diff --git a/.cargo/config.toml b/.cargo/config.toml index d941f9e7ae..617bffe924 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -16,3 +16,6 @@ ci-test-compile = "test --no-run --workspace --all-features --no-default-feature ci-test = "nextest run --all-features --release --workspace --exclude integration_tests --profile ci" ci-cucumber = "test --all-features --release --package integration_tests" ci-check = "check --workspace --release --all-features --all-targets --locked" + +[env] +TS_RS_EXPORT_DIR = { value = "./bindings/src/types", relative = true } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 820a734bc9..d06587f265 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1032,7 +1032,7 @@ version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "cexpr", "clang-sys", "itertools 0.12.1", @@ -1052,7 +1052,7 @@ version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "cexpr", "clang-sys", "itertools 0.13.0", @@ -1072,7 +1072,7 @@ version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "cexpr", "clang-sys", "itertools 0.13.0", @@ -1119,9 +1119,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" dependencies = [ "serde", ] @@ -2291,7 +2291,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "crossterm_winapi", "filedescriptor", "futures-core", @@ -3158,6 +3158,12 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + [[package]] name = "eax" version = "0.5.0" @@ -3914,7 +3920,7 @@ version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "libc", "libgit2-sys", "log", @@ -3946,7 +3952,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "ignore", "walkdir", ] @@ -6111,7 +6117,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "libc", "redox_syscall", ] @@ -7258,7 +7264,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "cfg-if", "cfg_aliases 0.1.1", "libc", @@ -7303,7 +7309,7 @@ version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c533b4c39709f9ba5005d8002048266593c1cfaf3c5f0739d5b8ab0c6c504009" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "filetime", "fsevent-sys", "inotify", @@ -7597,7 +7603,7 @@ version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "cfg-if", "foreign-types", "libc", @@ -8635,7 +8641,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "memchr", "unicase", ] @@ -8984,7 +8990,7 @@ version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", ] [[package]] @@ -8998,6 +9004,26 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "reflink-copy" version = "0.1.26" @@ -9279,7 +9305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64 0.21.7", - "bitflags 2.9.1", + "bitflags 2.9.2", "serde", "serde_derive", ] @@ -9461,7 +9487,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "errno", "libc", "linux-raw-sys 0.4.15", @@ -9474,7 +9500,7 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "errno", "libc", "linux-raw-sys 0.9.4", @@ -9681,6 +9707,30 @@ dependencies = [ "parking_lot", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -9753,7 +9803,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -9766,7 +9816,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -9958,6 +10008,38 @@ dependencies = [ "regex", ] +[[package]] +name = "serde_with" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.9.0", + "schemars 0.9.0", + "schemars 1.0.4", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "serde_yaml" version = "0.9.34+deprecated" @@ -10655,7 +10737,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "core-foundation 0.9.4", "system-configuration-sys 0.6.0", ] @@ -10820,7 +10902,7 @@ version = "4.9.0-pre.1" source = "git+https://github.com/tari-project/tari.git?tag=v4.9.0-pre.1#22bd4b9f851fa224fe4898c4601a71c326816f1b" dependencies = [ "base64 0.21.7", - "bitflags 2.9.1", + "bitflags 2.9.2", "blake2", "borsh", "bs58 0.5.1", @@ -10850,7 +10932,7 @@ source = "git+https://github.com/tari-project/tari.git?tag=v4.9.0-pre.1#22bd4b9f dependencies = [ "anyhow", "async-trait", - "bitflags 2.9.1", + "bitflags 2.9.2", "blake2", "bytes 1.10.1", "chrono", @@ -10895,7 +10977,7 @@ version = "4.9.0-pre.1" source = "git+https://github.com/tari-project/tari.git?tag=v4.9.0-pre.1#22bd4b9f851fa224fe4898c4601a71c326816f1b" dependencies = [ "anyhow", - "bitflags 2.9.1", + "bitflags 2.9.2", "blake2", "chacha20 0.7.3", "chacha20poly1305", @@ -11013,7 +11095,7 @@ dependencies = [ "anyhow", "async-trait", "bincode 1.3.3", - "bitflags 2.9.1", + "bitflags 2.9.2", "blake2", "borsh", "bytes 0.5.6", @@ -11242,6 +11324,7 @@ dependencies = [ "minotari_app_utilities", "serde", "serde_json", + "serde_with", "tari_base_node_client", "tari_common", "tari_common_types", @@ -11281,6 +11364,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", + "serde_with", "tari_common_types", "tari_consensus_types", "tari_engine_types", @@ -11512,6 +11596,7 @@ name = "tari_ootle_storage" version = "0.11.2" dependencies = [ "anyhow", + "bitflags 2.9.2", "borsh", "indexmap 2.9.0", "log", @@ -11743,7 +11828,7 @@ name = "tari_rpc_framework" version = "0.11.2" dependencies = [ "async-trait", - "bitflags 2.9.1", + "bitflags 2.9.2", "bytes 1.10.1", "futures 0.3.31", "libp2p", @@ -12283,6 +12368,7 @@ dependencies = [ "tari_ootle_common_types", "tari_ootle_storage", "tari_sidechain", + "tari_template_abi", "tari_template_lib_types", "tari_transaction", "thiserror 1.0.69", @@ -12294,7 +12380,6 @@ name = "tari_validator_node_rpc" version = "0.11.2" dependencies = [ "anyhow", - "async-trait", "prost 0.12.6", "proto_builder", "serde", @@ -12893,7 +12978,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "bytes 1.10.1", "futures-core", "futures-util", @@ -12918,7 +13003,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "bytes 1.10.1", "futures-util", "http 1.3.1", @@ -13802,7 +13887,7 @@ version = "0.224.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04f17a5917c2ddd3819e84c661fae0d6ba29d7b9c1f0e96c708c65a9c4188e11" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", ] [[package]] @@ -13811,7 +13896,7 @@ version = "0.235.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "indexmap 2.9.0", "semver", ] @@ -14682,7 +14767,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b268360ad2..cf770430f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -160,7 +160,7 @@ axum-jrpc = "0.3.2" base64 = "0.20.0" bigdecimal = "0.4.1" bincode = "2.0.0-rc.3" -bitflags = "2.4" +bitflags = "2.9.2" blake2 = "0.10.6" borsh = { version = "1.5", default-features = false } bytes = "1.10.0" @@ -228,6 +228,7 @@ rocksdb = "0.23.0" semver = "1.0" serde = { version = "1.0", default-features = false } serde_json = "1.0" +serde_with = "3.14.0" sha2 = "0.10.8" smallvec = "2.0.0-alpha.11" std-semaphore = "0.1.0" diff --git a/applications/tari_indexer/Cargo.toml b/applications/tari_indexer/Cargo.toml index ea2d7fb2cf..f81b782be7 100644 --- a/applications/tari_indexer/Cargo.toml +++ b/applications/tari_indexer/Cargo.toml @@ -23,7 +23,7 @@ tari_ootle_storage = { workspace = true } tari_ootle_storage_sqlite = { workspace = true } tari_epoch_manager = { workspace = true } tari_engine_types = { workspace = true } -tari_indexer_client = { workspace = true } +tari_indexer_client = { workspace = true, default-features = false } tari_indexer_lib = { workspace = true } tari_template_lib = { workspace = true } tari_template_manager = { workspace = true } @@ -44,7 +44,7 @@ config = { workspace = true } diesel = { workspace = true, default-features = false, features = [ "sqlite", "returning_clauses_for_sqlite_3_35", - "chrono", + "time", ] } diesel_migrations = { workspace = true } futures = { workspace = true } @@ -61,6 +61,7 @@ log4rs = { workspace = true, features = [ mime_guess = { workspace = true } serde = { workspace = true, features = ["default", "derive"] } serde_json = { workspace = true } +serde_with = { workspace = true, features = ["indexmap"] } thiserror = { workspace = true } tokio = { workspace = true, features = [ "default", diff --git a/applications/tari_indexer/src/bootstrap.rs b/applications/tari_indexer/src/bootstrap.rs index 83cecda8bd..2f3cbb3d0a 100644 --- a/applications/tari_indexer/src/bootstrap.rs +++ b/applications/tari_indexer/src/bootstrap.rs @@ -20,9 +20,9 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{fs, io, str::FromStr}; +use std::{fs, io, str::FromStr, sync::Arc}; -use anyhow::Context; +use anyhow::{anyhow, Context}; use libp2p::identity; use log::warn; use minotari_app_utilities::identity_management; @@ -51,7 +51,7 @@ use tari_ootle_app_utilities::{ seed_peer::SeedPeer, template_download_queue::TemplateDownloadQueue, }; -use tari_ootle_common_types::PeerAddress; +use tari_ootle_common_types::{optional::Optional, Network, PeerAddress}; use tari_ootle_p2p::TariMessagingSpec; use tari_ootle_storage::global::GlobalDb; use tari_ootle_storage_sqlite::global::SqliteGlobalDbAdapter; @@ -62,7 +62,12 @@ use tari_validator_node_rpc::client::TariValidatorNodeRpcClientFactory; use crate::{ network_client::TariNetworkClient, - storage_sqlite::store_factory::SqliteIndexerStore, + network_state_sync, + network_state_sync::NetworkWideStateSyncConfig, + storage_sqlite::{ + models::Key, + store_factory::{IndexerStore, IndexerStoreReadTransaction, IndexerStoreWriteTransaction, SqliteIndexerStore}, + }, ApplicationConfig, IndexerEpochManagerSpec, Noop, @@ -151,6 +156,7 @@ pub async fn spawn_services( // Connect to substate db let store = SqliteIndexerStore::try_create(config.indexer.state_db_path())?; + check_store(config, &store)?; // Epoch event oracle let epoch_event_oracle = create_epoch_oracle(config, global_db.clone(), &consensus_constants).await?; @@ -196,6 +202,17 @@ pub async fn spawn_services( template_queue_receiver, shutdown.clone(), ); + network_state_sync::NetworkWideStateSync::new( + epoch_manager.clone(), + networking.clone(), + store.clone(), + template_manager_service.clone(), + NetworkWideStateSyncConfig { + event_filters: Arc::from(config.indexer.event_filters.clone()), + ..Default::default() + }, + ) + .spawn(shutdown.clone()); // Save final node identity after comms has initialized. This is required because the public_address can be // changed by comms during initialization when using tor. @@ -209,7 +226,7 @@ pub async fn spawn_services( store, global_db, template_manager, - template_manager_service, + _template_manager_service: template_manager_service, }) } @@ -222,7 +239,7 @@ pub struct Services { pub network_client: TariNetworkClient, TariValidatorNodeRpcClientFactory>, pub global_db: GlobalDb>, pub template_manager: TemplateManager, - pub template_manager_service: TemplateManagerHandle, + pub _template_manager_service: TemplateManagerHandle, } fn ensure_directories_exist(config: &ApplicationConfig) -> io::Result<()> { @@ -319,3 +336,25 @@ async fn create_hybrid_epoch_oracle(config: &ApplicationConfig, store: &TStore) -> anyhow::Result<()> { + store.with_write_tx(|tx| { + match tx.key_value_get_value::<_, Network>(Key::Network).optional()? { + Some(network) => { + if network != config.network { + return Err(anyhow!( + "The network in the database ({}) does not match the configured network ({})", + network, + config.network + )); + } + Ok(()) + }, + None => { + // If the network is not set, we can assume this is a new store and we can set it + tx.key_value_set(Key::Network, config.network) + .map_err(|e| anyhow!("Failed to set network in the store: {}", e)) + }, + } + }) +} diff --git a/applications/tari_indexer/src/config.rs b/applications/tari_indexer/src/config.rs index 0a24078a5e..fa769e9bdf 100644 --- a/applications/tari_indexer/src/config.rs +++ b/applications/tari_indexer/src/config.rs @@ -42,6 +42,8 @@ use tari_ootle_app_utilities::{ use tari_ootle_common_types::Network; use tari_template_manager::implementation::TemplateConfig; +use crate::network_state_sync::EventFilter; + #[derive(Debug, Clone)] pub struct ApplicationConfig { pub common: CommonConfig, @@ -102,7 +104,7 @@ pub struct IndexerConfig { /// The burnt utxos sidechain id pub burnt_utxo_sidechain_id: Option, /// The event filtering configuration - pub event_filters: Vec, + pub event_filters: Vec, } impl IndexerConfig { @@ -151,11 +153,3 @@ impl SubConfigPath for IndexerConfig { "indexer" } } - -#[derive(Default, Debug, Serialize, Deserialize, Clone)] -pub struct EventFilterConfig { - pub topic: Option, - pub entity_id: Option, - pub substate_id: Option, - pub template_address: Option, -} diff --git a/applications/tari_indexer/src/event_manager.rs b/applications/tari_indexer/src/event_manager.rs index 9d44bdcf07..f107124aae 100644 --- a/applications/tari_indexer/src/event_manager.rs +++ b/applications/tari_indexer/src/event_manager.rs @@ -20,71 +20,24 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{collections::BTreeMap, str::FromStr, sync::Arc}; +use std::{collections::BTreeMap, str::FromStr}; use log::*; -use tari_crypto::tari_utilities::message_format::MessageFormat; use tari_engine_types::{events::Event, substate::SubstateId}; -use tari_epoch_manager::service::EpochManagerHandle; -use tari_indexer_lib::substate_scanner::SubstateScanner; -use tari_ootle_app_utilities::substate_file_cache::SubstateFileCache; -use tari_ootle_common_types::PeerAddress; -use tari_template_lib::{ - models::Metadata, - types::{Hash, TemplateAddress}, -}; -use tari_transaction::TransactionId; -use tari_validator_node_rpc::client::TariValidatorNodeRpcClientFactory; +use tari_template_lib::{models::Metadata, types::Hash}; -use crate::storage_sqlite::{ - models::events::NewEvent, - store_factory::{IndexerStore, IndexerStoreReadTransaction, IndexerStoreWriteTransaction, SqliteIndexerStore}, -}; +use crate::storage_sqlite::store_factory::{IndexerStore, IndexerStoreReadTransaction, SqliteIndexerStore}; const LOG_TARGET: &str = "tari::indexer::event_manager"; +#[derive(Debug, Clone)] pub struct EventManager { substate_store: SqliteIndexerStore, - _substate_scanner: - Arc, TariValidatorNodeRpcClientFactory, SubstateFileCache>>, } impl EventManager { - pub fn new( - substate_store: SqliteIndexerStore, - substate_scanner: Arc< - SubstateScanner, TariValidatorNodeRpcClientFactory, SubstateFileCache>, - >, - ) -> Self { - Self { - substate_store, - _substate_scanner: substate_scanner, - } - } - - pub fn save_event_to_db( - &self, - substate_id: &SubstateId, - template_address: TemplateAddress, - tx_hash: TransactionId, - topic: String, - payload: &Metadata, - version: u64, - timestamp: u64, - ) -> Result<(), anyhow::Error> { - self.substate_store.with_write_tx(|tx| { - let new_event = NewEvent { - substate_id: Some(substate_id.to_string()), - template_address: template_address.to_string(), - tx_hash: tx_hash.to_string(), - topic, - payload: payload.to_json().expect("Failed to convert to JSON"), - version: version as i32, - timestamp: timestamp as i64, - }; - tx.save_event(new_event) - })?; - Ok(()) + pub fn new(substate_store: SqliteIndexerStore) -> Self { + Self { substate_store } } pub async fn get_events_from_db( diff --git a/applications/tari_indexer/src/event_scanner.rs b/applications/tari_indexer/src/event_scanner.rs deleted file mode 100644 index 85e0fcddbe..0000000000 --- a/applications/tari_indexer/src/event_scanner.rs +++ /dev/null @@ -1,539 +0,0 @@ -// Copyright 2024 The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -use std::str::FromStr; - -use futures::StreamExt; -use log::*; -use tari_consensus_types::BlockId; -use tari_crypto::tari_utilities::message_format::MessageFormat; -use tari_engine_types::{ - events::Event, - substate::{SubstateId, SubstateValue}, -}; -use tari_epoch_manager::{service::EpochManagerHandle, EpochManagerReader}; -use tari_ootle_common_types::{committee::Committee, Epoch, PeerAddress, ShardGroup}; -use tari_ootle_p2p::{proto, proto::rpc::SyncBlocksRequest}; -use tari_ootle_storage::consensus_models::{Block, SubstateUpdateProof}; -use tari_template_lib::types::{EntityId, TemplateAddress}; -use tari_template_manager::interface::{TemplateChange, TemplateManagerHandle}; -use tari_validator_node_rpc::client::{TariValidatorNodeRpcClientFactory, ValidatorNodeClientFactory}; - -use crate::{ - block_data::BlockData, - config::EventFilterConfig, - storage_sqlite::{ - models::{ - events::{NewEvent, NewScannedBlockId}, - substate::NewSubstate, - }, - store_factory::{IndexerStore, IndexerStoreReadTransaction, IndexerStoreWriteTransaction, SqliteIndexerStore}, - }, -}; - -const LOG_TARGET: &str = "tari::indexer::event_scanner"; - -#[derive(Default, Debug, Clone)] -pub struct EventFilter { - pub topic: Option, - pub entity_id: Option, - pub substate_id: Option, - pub template_address: Option, -} - -impl TryFrom for EventFilter { - type Error = anyhow::Error; - - fn try_from(cfg: EventFilterConfig) -> Result { - let entity_id = cfg.entity_id.map(|str| EntityId::from_hex(&str)).transpose()?; - let substate_id = cfg.substate_id.map(|str| SubstateId::from_str(&str)).transpose()?; - let template_address = cfg - .template_address - .map(|str| TemplateAddress::from_str(&str)) - .transpose()?; - - Ok(Self { - topic: cfg.topic, - entity_id, - substate_id, - template_address, - }) - } -} - -#[derive(Clone)] -pub struct EventScanner { - epoch_manager: EpochManagerHandle, - client_factory: TariValidatorNodeRpcClientFactory, - substate_store: SqliteIndexerStore, - template_manager: TemplateManagerHandle, - event_filters: Vec, -} - -impl EventScanner { - pub fn new( - epoch_manager: EpochManagerHandle, - client_factory: TariValidatorNodeRpcClientFactory, - substate_store: SqliteIndexerStore, - template_manager: TemplateManagerHandle, - event_filters: Vec, - ) -> Self { - Self { - epoch_manager, - client_factory, - substate_store, - template_manager, - event_filters, - } - } - - pub async fn scan_events(&self) -> Result { - info!( - target: LOG_TARGET, - "scan_events", - ); - - let mut event_count = 0; - - let newest_epoch = self.epoch_manager.current_epoch().await?; - let oldest_scanned_epoch = self.get_oldest_scanned_epoch().await?; - - match oldest_scanned_epoch { - Some(oldest_epoch) => { - // we could span multiple cuncurrent epoch scans - // but we want to avoid gaps of the latest scanned value if any of the intermediate epoch scans fail - for epoch_idx in oldest_epoch.0..=newest_epoch.0 { - let epoch = Epoch(epoch_idx); - event_count += self.scan_events_of_epoch(epoch).await?; - - // at this point we can assume the previous epochs have been fully scanned - self.delete_scanned_epochs_older_than(epoch).await?; - } - }, - None => { - // by default we start scanning since the current epoch - // TODO: it would be nice a new parameter in the indexer to specify a custom starting epoch - event_count += self.scan_events_of_epoch(newest_epoch).await?; - }, - } - - info!( - target: LOG_TARGET, - "Scanned {} events", - event_count - ); - - Ok(event_count) - } - - async fn scan_events_of_epoch(&self, epoch: Epoch) -> Result { - // TODO(perf): This call can become expensive. Lazily load a committee member from all shard groups - let committees = self.epoch_manager.get_committees(epoch).await?; - - let mut event_count = 0; - - for (shard_group, mut committee) in committees { - info!( - target: LOG_TARGET, - "Scanning committee epoch={}, sg={}", - epoch, - shard_group - ); - let new_blocks = self - .get_new_blocks_from_committee(shard_group, &mut committee, epoch) - .await?; - info!( - target: LOG_TARGET, - "Scanned {} blocks in epoch={}", - new_blocks.len(), - epoch, - ); - - for block_data in new_blocks { - // fetch all the events in the transaction - let events = block_data - .diff - .iter() - .filter_map(|r| r.as_create()) - .filter_map(|create| create.substate.value.value().and_then(|v| v.as_transaction_receipt())) - .flat_map(|receipt| receipt.events.as_slice()); - - // only keep the events specified by the indexer filter - let filtered_events: Vec<_> = events.filter(|ev| self.should_persist_event(ev)).collect(); - event_count += filtered_events.len(); - debug!( - target: LOG_TARGET, - "Filtered events in epoch {}: {}", - epoch, - filtered_events.len() - ); - self.store_events_in_db(&filtered_events, block_data.block.timestamp())?; - self.store_substates_in_db(&block_data.diff, block_data.block.timestamp())?; - - let new_templates = block_data - .diff - .iter() - .filter_map(|r| r.as_create()) - .filter_map(|create| { - let value = create.substate.value().value()?; - let template = value.as_template()?; - let template_address = create - .substate - .substate_id() - .as_template() - // TODO: this should be an error - a VN could send invalid data - .expect("Expected template substate ID"); - - Some(TemplateChange::Add { - template_address, - author_public_key: template.author, - binary_hash: template.binary_hash.into_array().into(), - epoch, - }) - }) - .collect::>(); - if !new_templates.is_empty() { - self.template_manager.enqueue_template_changes(new_templates).await?; - } - } - } - - Ok(event_count) - } - - async fn delete_scanned_epochs_older_than(&self, epoch: Epoch) -> Result<(), anyhow::Error> { - self.substate_store - .with_write_tx(|tx| tx.delete_scanned_epochs_older_than(epoch)) - .map_err(|e| e.into()) - } - - fn should_persist_event(&self, event: &Event) -> bool { - for filter in &self.event_filters { - if Self::event_matches_filter(filter, event) { - return true; - } - } - - false - } - - fn event_matches_filter(filter: &EventFilter, event: &Event) -> bool { - let matches_topic = filter.topic.as_ref().is_none_or(|t| *t == event.topic()); - let matches_template = filter - .template_address - .as_ref() - .is_none_or(|t| *t == event.template_address()); - - let matches_substate_id = match filter.substate_id { - Some(ref substate_id) => event.substate_id().map(|s| s == substate_id).unwrap_or(false), - None => true, - }; - - let matches_entity_id = match &filter.entity_id { - Some(entity_id) => event - .substate_id() - .map(|s| Self::entity_id_matches(s, entity_id)) - .unwrap_or(false), - None => true, - }; - - if matches_topic && matches_template && matches_substate_id && matches_entity_id { - return true; - } - - false - } - - fn entity_id_matches(substate_id: &SubstateId, entity_id: &EntityId) -> bool { - substate_id.to_object_key().as_entity_id() == *entity_id - } - - fn store_events_in_db(&self, events: &[&Event], timestamp: u64) -> Result<(), anyhow::Error> { - let mut tx = self.substate_store.create_write_tx()?; - - for event in events { - let event_row = NewEvent { - template_address: event.template_address().to_string(), - tx_hash: event.tx_hash().to_string(), - topic: event.topic(), - payload: event.payload().to_json().expect("Failed to convert to JSON"), - substate_id: event.substate_id().map(|s| s.to_string()), - // TODO: include substate version in event? - version: 0_i32, - timestamp: timestamp as i64, - }; - - // TODO: properly avoid or handle duplicated events - // For now we will just check if a similar event exists in the db - let event_already_exists = tx.event_exists(&event_row)?; - if event_already_exists { - // the event was already stored previously - // TODO: Making this debug because it happens a lot and tends to spam the swarm output - debug!( - target: LOG_TARGET, - "Duplicate {}", - event - ); - continue; - } - - debug!( - target: LOG_TARGET, - "Saving event: {:?}", - event_row - ); - tx.save_event(event_row)?; - } - - tx.commit()?; - - Ok(()) - } - - fn store_substates_in_db(&self, updates: &[SubstateUpdateProof], timestamp: u64) -> Result<(), anyhow::Error> { - let mut tx = self.substate_store.create_write_tx()?; - // store/update up substates if any - for create in updates.iter().filter_map(|up| up.as_create()) { - let maybe_substate_value = create.substate.value.value(); - if maybe_substate_value.is_none() { - warn!( - target: LOG_TARGET, - "⚠️ Received UP substate {} without value. This indicates that the substate has been pruned. Some event data is not available.", create.substate.as_versioned_substate_id_ref(), - ); - } - let template_address = maybe_substate_value.and_then(Self::extract_template_address_from_substate); - let module_name = maybe_substate_value.and_then(Self::extract_module_name_from_substate); - let substate_row = NewSubstate { - address: create.substate.substate_id.to_string(), - version: create.substate.version as i32, - data: maybe_substate_value - .map(Self::encode_substate) - .transpose()? - .unwrap_or_default(), - tx_hash: String::new(), - template_address: template_address.map(|s| s.to_string()), - module_name, - timestamp: timestamp as i64, - }; - debug!( - target: LOG_TARGET, - "Saving substate: {:?}", - substate_row - ); - tx.insert_substate(substate_row)?; - } - tx.commit()?; - Ok(()) - } - - fn extract_template_address_from_substate(substate: &SubstateValue) -> Option { - match substate { - SubstateValue::Component(c) => Some(c.template_address), - _ => None, - } - } - - fn extract_module_name_from_substate(substate: &SubstateValue) -> Option { - match substate { - SubstateValue::Component(c) => Some(c.module_name.to_owned()), - _ => None, - } - } - - fn encode_substate(substate: &SubstateValue) -> Result { - let pretty_json = serde_json::to_string_pretty(&substate)?; - Ok(pretty_json) - } - - async fn get_oldest_scanned_epoch(&self) -> Result, anyhow::Error> { - self.substate_store - .with_read_tx(|tx| tx.get_oldest_scanned_epoch()) - .map_err(|e| e.into()) - } - - async fn get_new_blocks_from_committee( - &self, - shard_group: ShardGroup, - committee: &mut Committee, - epoch: Epoch, - ) -> Result, anyhow::Error> { - // We start scanning from the last scanned block for this committee - let start_block_id = self - .substate_store - .with_read_tx(|tx| tx.get_last_scanned_block_id(epoch, shard_group))?; - - committee.shuffle(); - - info!( - target: LOG_TARGET, - "Scanning new blocks from (start_id={}, epoch={}, shard={})", - start_block_id.map(|id| id.to_string()).unwrap_or_else(|| "None".to_string()), - epoch, - shard_group - ); - - for member in committee.address_iter() { - debug!( - target: LOG_TARGET, - "Trying to get blocks from VN {} (epoch={}, shard_group={})", - member, - epoch, - shard_group - ); - let resp = self.get_block_data_from_vn(member, start_block_id, epoch).await; - - match resp { - Ok(block_data) => { - // TODO: try more than 1 VN per committee - info!( - target: LOG_TARGET, - "Got {} blocks from VN {} (epoch={}, shard_group={})", - block_data.len(), - member, - epoch, - shard_group, - ); - - // get the most recent block among all scanned blocks in the epoch - let last_block = block_data - .iter() - .max_by_key(|data| (data.block.epoch(), data.block.height())) - .map(|data| &data.block); - - if let Some(block) = last_block { - // Store the latest scanned block id in the database for future scans - self.save_scanned_block_id(epoch, shard_group, *block.id())?; - } - return Ok(block_data); - }, - Err(e) => { - // We do nothing on a single VN failure, we only log it - warn!( - target: LOG_TARGET, - "Could not get blocks from VN {} (epoch={}, shard_group={}): {}", - member, - epoch, - shard_group, - e - ); - }, - }; - } - - // We don't raise an error if none of the VNs have blocks, the scanning will retry eventually - warn!( - target: LOG_TARGET, - "Could not get blocks from any of the VNs of the committee (epoch={}, shard_group={})", - epoch, - shard_group - ); - Ok(vec![]) - } - - fn save_scanned_block_id( - &self, - epoch: Epoch, - shard_group: ShardGroup, - last_block_id: BlockId, - ) -> Result<(), anyhow::Error> { - let row = NewScannedBlockId { - epoch: epoch.0 as i64, - shard_group: shard_group.encode_as_u32() as i32, - last_block_id: last_block_id.as_bytes().to_vec(), - }; - self.substate_store.with_write_tx(|tx| tx.save_scanned_block_id(row))?; - Ok(()) - } - - // async fn get_all_vns(&self) -> Result, anyhow::Error> { - // // get all the committees - // let epoch = self.epoch_manager.current_epoch().await?; - // Ok(self - // .epoch_manager - // .get_all_validator_nodes(epoch) - // .await - // .map(|v| v.iter().map(|m| m.address).collect())?) - // } - - async fn get_block_data_from_vn( - &self, - vn_addr: &PeerAddress, - start_block_id: Option, - up_to_epoch: Epoch, - ) -> Result, anyhow::Error> { - let mut blocks = vec![]; - - let mut rpc_client = self.client_factory.create_client(vn_addr); - let mut client = rpc_client.client_connection().await?; - - let mut stream = client - .sync_blocks(SyncBlocksRequest { - start_block_id: start_block_id.map(|id| id.as_bytes().to_vec()).unwrap_or_default(), - epoch: Some(up_to_epoch.into()), - // TODO: QC should be validated - stream_qcs: false, - stream_substates: proto::rpc::StreamSubstateSelection::All.into(), - stream_transactions: false, - }) - .await?; - while let Some(resp) = stream.next().await { - let msg = resp?; - - let new_block = msg - .into_block() - .ok_or_else(|| anyhow::anyhow!("Expected peer to return a newblock"))?; - let block = Block::try_from(new_block)?; - - let Some(resp) = stream.next().await else { - anyhow::bail!("Peer closed session before sending substate update count message") - }; - let msg = resp?; - let num_substates = - msg.substate_count() - .ok_or_else(|| anyhow::anyhow!("Expected peer to return substate count"))? as usize; - // TODO: what should this limit be? - if num_substates > 10_000 { - return Err(anyhow::anyhow!( - "Exceeded maximum number of substates (10,000). Got {}", - num_substates - )); - } - - let mut diff = Vec::with_capacity(num_substates); - for _ in 0..num_substates { - let Some(resp) = stream.next().await else { - anyhow::bail!("Peer closed session before sending substate updates message") - }; - let msg = resp?; - let update = msg - .into_substate_update() - .ok_or_else(|| anyhow::anyhow!("Expected a substate"))?; - let update = SubstateUpdateProof::try_from(update)?; - diff.push(update); - } - - blocks.push(BlockData { block, diff }); - } - - Ok(blocks) - } -} diff --git a/applications/tari_indexer/src/graphql/model/events.rs b/applications/tari_indexer/src/graphql/model/events.rs index 230a2069ff..f230cffa33 100644 --- a/applications/tari_indexer/src/graphql/model/events.rs +++ b/applications/tari_indexer/src/graphql/model/events.rs @@ -20,14 +20,12 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{collections::BTreeMap, str::FromStr, sync::Arc}; +use std::{collections::BTreeMap, str::FromStr}; use async_graphql::{Context, EmptyMutation, EmptySubscription, Object, Schema, SimpleObject}; use log::*; use serde::{Deserialize, Serialize}; use tari_engine_types::substate::SubstateId; -use tari_template_lib::types::Hash; -use tari_transaction::TransactionId; use crate::event_manager::EventManager; @@ -74,55 +72,12 @@ impl EventQuery { "Querying events. topic: {:?}, substate_id: {:?}, offset: {}, limit: {}, ", topic, substate_id, offset, limit, ); let substate_id = substate_id.map(|str| SubstateId::from_str(&str)).transpose()?; - let event_manager = ctx.data_unchecked::>(); - let events = event_manager + let event_manager = ctx.data_unchecked::(); + event_manager .get_events_from_db(topic, substate_id, offset, limit) .await? - .iter() - .map(|e| Event::from_engine_event(e.clone())) - .collect::, anyhow::Error>>()?; - - Ok(events) - } - - pub async fn save_event( - &self, - ctx: &Context<'_>, - substate_id: String, - template_address: String, - tx_hash: String, - topic: String, - payload: String, - version: u64, - timestamp: u64, - ) -> Result { - info!( - target: LOG_TARGET, - "Saving event for substate_id = {}, tx_hash = {} and topic = {}", substate_id, tx_hash, topic - ); - - let substate_id = SubstateId::from_str(&substate_id)?; - let template_address = Hash::from_str(&template_address)?; - let tx_hash = TransactionId::from_hex(&tx_hash)?; - - let payload = serde_json::from_str(&payload)?; - let event_manager = ctx.data_unchecked::>(); - event_manager.save_event_to_db( - &substate_id, - template_address, - tx_hash, - topic.clone(), - &payload, - version, - timestamp, - )?; - - Ok(Event { - substate_id: Some(substate_id.to_string()), - template_address: template_address.into_array(), - tx_hash: tx_hash.into_array(), - topic, - payload: payload.into_iter().collect(), - }) + .into_iter() + .map(Event::from_engine_event) + .collect() } } diff --git a/applications/tari_indexer/src/graphql/server.rs b/applications/tari_indexer/src/graphql/server.rs index 945e39ecae..8f8fffba19 100644 --- a/applications/tari_indexer/src/graphql/server.rs +++ b/applications/tari_indexer/src/graphql/server.rs @@ -20,7 +20,7 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{net::SocketAddr, sync::Arc}; +use std::net::SocketAddr; use async_graphql::{ http::{playground_source, GraphQLPlaygroundConfig}, @@ -51,8 +51,8 @@ const LOG_TARGET: &str = "tari::indexer::graphql"; pub async fn run_graphql( preferred_address: SocketAddr, - substate_manager: Arc, - event_manager: Arc, + substate_manager: SubstateManager, + event_manager: EventManager, ) -> Result<(), anyhow::Error> { let schema = Schema::build(EventQuery, EmptyMutation, EmptySubscription) .data(substate_manager) diff --git a/applications/tari_indexer/src/json_rpc/handlers.rs b/applications/tari_indexer/src/json_rpc/handlers.rs index 30f7029e08..fd7a540996 100644 --- a/applications/tari_indexer/src/json_rpc/handlers.rs +++ b/applications/tari_indexer/src/json_rpc/handlers.rs @@ -20,7 +20,7 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{collections::HashMap, fmt::Display, ops::Deref, sync::Arc}; +use std::{collections::HashMap, fmt::Display, ops::Deref}; use axum_jrpc::{ error::{JsonRpcError, JsonRpcErrorReason}, @@ -54,6 +54,8 @@ use tari_indexer_client::types::{ GetTemplateDefinitionResponse, GetTransactionResultRequest, GetTransactionResultResponse, + GetUtxoUpdatesRequest, + GetUtxoUpdatesResponse, IndexerReadyResponse, IndexerTransactionFinalizedResult, InspectSubstateRequest, @@ -71,7 +73,13 @@ use tari_indexer_client::types::{ }; use tari_networking::{is_supported_multiaddr, NetworkingHandle, NetworkingService}; use tari_ootle_app_utilities::keypair::RistrettoKeypair; -use tari_ootle_common_types::{optional::Optional, public_key_to_peer_id, PeerAddress, SubstateRequirement}; +use tari_ootle_common_types::{ + optional::Optional, + public_key_to_peer_id, + NumPreshards, + PeerAddress, + SubstateRequirement, +}; use tari_ootle_p2p::TariMessagingSpec; use tari_ootle_storage::{ global::GlobalDb, @@ -96,7 +104,7 @@ const LOG_TARGET: &str = "tari::indexer::json_rpc::handlers"; pub struct JsonRpcHandlers { keypair: RistrettoKeypair, networking: NetworkingHandle, - substate_manager: Arc, + substate_manager: SubstateManager, epoch_manager: EpochManagerHandle, transaction_manager: TransactionManager, TariValidatorNodeRpcClientFactory, SqliteIndexerStore>, @@ -108,7 +116,7 @@ pub struct JsonRpcHandlers { impl JsonRpcHandlers { pub fn new( services: &Services, - substate_manager: Arc, + substate_manager: SubstateManager, transaction_manager: TransactionManager< EpochManagerHandle, TariValidatorNodeRpcClientFactory, @@ -265,8 +273,7 @@ impl JsonRpcHandlers { let substates = self .substate_manager - .list_substates(filter_by_type, filter_by_template, limit, offset) - .await + .get_stored_substates_by_filters(filter_by_type, filter_by_template, limit, offset) .map_err(|e| { warn!(target: LOG_TARGET, "Error getting substate: {}", e); Self::internal_error(answer_id, format!("Error getting substate: {}", e)) @@ -439,6 +446,81 @@ impl JsonRpcHandlers { })) } + pub async fn get_utxo_updates(&self, value: JsonRpcExtractor) -> JrpcResult { + let answer_id = value.get_answer_id(); + let req: GetUtxoUpdatesRequest = value.parse_params()?; + if req.per_shard_limit > 1000 { + return Err(JsonRpcResponse::error( + answer_id, + JsonRpcError::new( + JsonRpcErrorReason::InvalidParams, + "per_shard_limit cannot be greater than 1000".to_string(), + json::Value::Null, + ), + )); + } + + if req.shard_state_versions.len() > NumPreshards::MAX_SHARD.as_u32() as usize { + return Err(JsonRpcResponse::error( + answer_id, + JsonRpcError::new( + JsonRpcErrorReason::InvalidParams, + format!( + "shard_state_versions cannot contain more than {} entries", + NumPreshards::MAX_SHARD.as_u32() + ), + Value::Null, + ), + )); + } + + if req + .shard_state_versions + .keys() + .any(|shard| shard.is_global() || *shard > NumPreshards::MAX_SHARD) + { + return Err(JsonRpcResponse::error( + answer_id, + JsonRpcError::new( + JsonRpcErrorReason::InvalidParams, + format!( + "shard_state_versions contains invalid shard. Cannot query UTXOs in global shard or greater \ + than max shard {} exceeded", + NumPreshards::MAX_SHARD.as_u32() + ), + Value::Null, + ), + )); + } + + let mut utxo_updates = Vec::new(); + for (shard, state_version) in req.shard_state_versions { + let updates = self + .substate_manager + .get_utxo_updates( + req.resource_address, + shard, + state_version, + &req.filter_tag_bytes, + req.per_shard_limit, + ) + .map_err(|e| { + Self::internal_error( + answer_id, + format!( + "Error getting UTXO updates for resource_address {}, shard {}, state_version {}: {}", + req.resource_address, shard, state_version, e + ), + ) + })?; + utxo_updates.extend(updates); + } + + Ok(JsonRpcResponse::success(answer_id, GetUtxoUpdatesResponse { + utxo_updates, + })) + } + pub async fn submit_transaction(&self, value: JsonRpcExtractor) -> JrpcResult { let answer_id = value.get_answer_id(); let request: SubmitTransactionRequest = value.parse_params()?; diff --git a/applications/tari_indexer/src/json_rpc/server.rs b/applications/tari_indexer/src/json_rpc/server.rs index a31c97a7f8..0fdbfa36fb 100644 --- a/applications/tari_indexer/src/json_rpc/server.rs +++ b/applications/tari_indexer/src/json_rpc/server.rs @@ -66,21 +66,31 @@ async fn handler(Extension(handlers): Extension>, value: Js debug!(target: LOG_TARGET, "🌐 JSON-RPC body: {:?}", value); match value.method.as_str() { "rpc.discover" => handlers.rpc_discover(value), + // Network "get_identity" => handlers.get_identity(value).await, "add_peer" => handlers.add_peer(value).await, "get_comms_stats" => handlers.get_comms_stats(value).await, + "get_connections" => handlers.get_connections(value).await, + + // Substates "list_substates" => handlers.list_substates(value).await, "get_substate" => handlers.get_substate(value).await, "inspect_substate" => handlers.inspect_substate(value).await, - "get_connections" => handlers.get_connections(value).await, "get_non_fungibles" => handlers.get_non_fungibles(value).await, + "get_utxo_updates" => handlers.get_utxo_updates(value).await, + + // Transactions "submit_transaction" => handlers.submit_transaction(value).await, "get_transaction_result" => handlers.get_transaction_result(value).await, - "get_epoch_manager_stats" => handlers.get_epoch_manager_stats(value).await, + + // Templates "get_template_definition" => handlers.get_template_definition(value).await, "list_templates" => handlers.list_templates(value).await, "list_recent_transactions" => handlers.list_recent_transactions(value).await, + + // Misc "wait_until_ready" => handlers.wait_until_ready(value).await, + "get_epoch_manager_stats" => handlers.get_epoch_manager_stats(value).await, method => Ok(value.method_not_found(method)), } } diff --git a/applications/tari_indexer/src/lib.rs b/applications/tari_indexer/src/lib.rs index 6ae67d86d2..d5546abeb5 100644 --- a/applications/tari_indexer/src/lib.rs +++ b/applications/tari_indexer/src/lib.rs @@ -36,17 +36,17 @@ mod http_ui; mod block_data; mod event_data; mod event_manager; -mod event_scanner; mod json_rpc; mod network_client; +mod network_state_sync; mod storage_sqlite; mod substate_manager; mod transaction_manager; -use std::{convert::Infallible, fs, future, future::Future, sync::Arc}; +use std::{convert::Infallible, fs, future, future::Future}; -use event_scanner::{EventFilter, EventScanner}; use log::*; +use network_state_sync::BlockScanner; use serde::Serialize; use substate_manager::SubstateManager; use tari_common::exit_codes::{ExitCode, ExitError}; @@ -98,7 +98,7 @@ pub async fn run_indexer(config: ApplicationConfig, mut shutdown_signal: Shutdow .map_err(|e| ExitError::new(ExitCode::DatabaseError, e))?; let consensus_constants = ConsensusConstants::from(config.network); - let services: Services = spawn_services( + let services = spawn_services( &config, shutdown_signal.clone(), keypair.clone(), @@ -113,13 +113,13 @@ pub async fn run_indexer(config: ApplicationConfig, mut shutdown_signal: Shutdow let substate_cache = SubstateFileCache::new(substate_cache_dir) .map_err(|e| ExitError::new(ExitCode::ConfigError, format!("Substate cache error: {}", e)))?; - let substate_scanner = Arc::new(SubstateScanner::new( + let substate_scanner = SubstateScanner::new( services.epoch_manager.clone(), services.validator_node_client_factory.clone(), substate_cache, - )); + ); - let substate_manager = Arc::new(SubstateManager::new(substate_scanner.clone(), services.store.clone())); + let substate_manager = SubstateManager::new(substate_scanner.clone(), services.store.clone()); let transaction_manager = TransactionManager::new(services.network_client.clone(), services.store.clone()); // dry run @@ -132,13 +132,13 @@ pub async fn run_indexer(config: ApplicationConfig, mut shutdown_signal: Shutdow ); // Run the event manager - let event_manager = Arc::new(EventManager::new(services.store.clone(), substate_scanner.clone())); + let event_manager = EventManager::new(services.store.clone()); // Run the GraphQL API let graphql_address = config.indexer.graphql_address; if let Some(address) = graphql_address { info!(target: LOG_TARGET, "🌐 Started GraphQL server on {}", address); - task::spawn(run_graphql(address, substate_manager.clone(), event_manager.clone())); + task::spawn(run_graphql(address, substate_manager.clone(), event_manager)); } // Run the JSON-RPC API @@ -147,7 +147,7 @@ pub async fn run_indexer(config: ApplicationConfig, mut shutdown_signal: Shutdow info!(target: LOG_TARGET, "🌐 Started JSON-RPC server on {}", jrpc_address); let handlers = JsonRpcHandlers::new( &services, - substate_manager.clone(), + substate_manager, transaction_manager, services.global_db.clone(), services.template_manager.clone(), @@ -197,32 +197,28 @@ pub async fn run_indexer(config: ApplicationConfig, mut shutdown_signal: Shutdow info!(target: LOG_TARGET, "πŸ•ΈοΈ Web UI not enabled. Run with --features web_ui to enable it."); // Run the event scanner - let event_filters: Vec = config - .indexer - .event_filters - .into_iter() - .map(TryInto::try_into) - .collect::>() - .map_err(|e| ExitError::new(ExitCode::ConfigError, format!("Invalid event filters: {}", e)))?; - let event_scanner = EventScanner::new( + let event_scanner = BlockScanner::new( services.epoch_manager.clone(), services.validator_node_client_factory.clone(), services.store.clone(), - services.template_manager_service.clone(), - event_filters, ); // Create pid to allow watchers to know that the process has started fs::write(config.common.base_path.join("pid"), std::process::id().to_string()) .map_err(|e| ExitError::new(ExitCode::IOError, e))?; + let mut scanning_interval = time::interval(config.indexer.scanning_interval); + // Skip - because we assume that the reason we missed it is because of scanning + scanning_interval.set_missed_tick_behavior(time::MissedTickBehavior::Skip); + loop { tokio::select! { // keep scanning the dan layer for new events - _ = time::sleep(config.indexer.scanning_interval) => { - match event_scanner.scan_events().await { + _ = scanning_interval.tick() => { + // TODO: shutdown while scanning + match event_scanner.scan().await { Ok(0) => {}, - Ok(cnt) => info!(target: LOG_TARGET, "Scanned {} events(s) successfully", cnt), + Ok(cnt) => info!(target: LOG_TARGET, "Scanned {} block(s) successfully", cnt), Err(e) => error!(target: LOG_TARGET, "Event auto-scan failed: {}", e), }; }, diff --git a/applications/tari_indexer/src/network_client.rs b/applications/tari_indexer/src/network_client.rs index b149504e87..5d063b76d5 100644 --- a/applications/tari_indexer/src/network_client.rs +++ b/applications/tari_indexer/src/network_client.rs @@ -103,53 +103,6 @@ where Ok(tx_id) } - #[allow(dead_code)] - pub async fn try_with_random_members<'a, F, T, E, TFut>( - &self, - num_to_query: usize, - shard_group: Option, - mut callback: F, - ) -> Result - where - F: FnMut(TClientFactory::Client) -> TFut, - TFut: Future> + 'a, - TClientFactory::Client: 'a, - T: 'static, - E: Display, - { - let epoch = self.epoch_manager.current_epoch().await?; - let mut attempted = vec![]; - - let mut last_error = None; - while attempted.len() < num_to_query { - let vn = self - .epoch_manager - .get_random_committee_member(epoch, shard_group, attempted.clone()) - .await?; - - let client = self.client_provider.create_client(&vn.address); - match callback(client).await { - Ok(ret) => { - return Ok(ret); - }, - Err(err) => { - warn!( - target: LOG_TARGET, - "Request failed for validator '{}': {}", vn, err - ); - last_error = Some(err.to_string()); - }, - } - - attempted.push(vn.address); - } - - Err(NetworkClientError::AllValidatorsFailed { - committee_size: attempted.len(), - last_error, - }) - } - pub async fn try_single_with_committee<'a, F, T, E, TFut>( &self, substate_address: SubstateAddress, diff --git a/applications/tari_indexer/src/network_state_sync/block_scanner.rs b/applications/tari_indexer/src/network_state_sync/block_scanner.rs new file mode 100644 index 0000000000..53228d5d87 --- /dev/null +++ b/applications/tari_indexer/src/network_state_sync/block_scanner.rs @@ -0,0 +1,386 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use futures::StreamExt; +use log::*; +use tari_consensus_types::BlockId; +use tari_engine_types::substate::SubstateValue; +use tari_epoch_manager::{service::EpochManagerHandle, EpochManagerReader}; +use tari_ootle_common_types::{committee::Committee, Epoch, PeerAddress, ShardGroup}; +use tari_ootle_p2p::{proto, proto::rpc::SyncBlocksRequest}; +use tari_ootle_storage::{ + consensus_models::{Block, SubstateUpdateProof}, + time::{OffsetDateTime, PrimitiveDateTime}, +}; +use tari_template_lib::types::TemplateAddress; +use tari_validator_node_rpc::client::{TariValidatorNodeRpcClientFactory, ValidatorNodeClientFactory}; + +use crate::{ + block_data::BlockData, + storage_sqlite::{ + models::{NewScannedBlockId, NewSubstate}, + store_factory::{IndexerStore, IndexerStoreReadTransaction, IndexerStoreWriteTransaction, SqliteIndexerStore}, + }, +}; + +const LOG_TARGET: &str = "tari::indexer::block_scanner"; + +#[derive(Clone)] +pub struct BlockScanner { + epoch_manager: EpochManagerHandle, + client_factory: TariValidatorNodeRpcClientFactory, + substate_store: SqliteIndexerStore, +} + +impl BlockScanner { + pub fn new( + epoch_manager: EpochManagerHandle, + client_factory: TariValidatorNodeRpcClientFactory, + substate_store: SqliteIndexerStore, + ) -> Self { + Self { + epoch_manager, + client_factory, + substate_store, + } + } + + pub async fn scan(&self) -> Result { + let mut block_count = 0; + + let newest_epoch = self.epoch_manager.current_epoch().await?; + let oldest_scanned_epoch = self.get_oldest_scanned_epoch().await?; + + match oldest_scanned_epoch { + Some(oldest_epoch) => { + // we could span concurrent epoch scans + // but we want to avoid gaps of the latest scanned value if any of the intermediate epoch scans fail + for epoch in oldest_epoch.as_u64()..=newest_epoch.as_u64() { + let epoch = Epoch(epoch); + block_count += self.scan_blocks_in_epoch(epoch).await?; + + // at this point we can assume the previous epochs have been fully scanned + self.delete_scanned_epochs_older_than(epoch).await?; + } + }, + None => { + // by default we start scanning since the current epoch + // TODO: maybe a new parameter in the indexer to specify a custom starting epoch, or we should scan from + // the genesis epoch + block_count += self.scan_blocks_in_epoch(newest_epoch).await?; + }, + } + + info!( + target: LOG_TARGET, + "Scanned {} events", + block_count + ); + + Ok(block_count) + } + + async fn scan_blocks_in_epoch(&self, epoch: Epoch) -> Result { + // TODO(perf): This call can become expensive. Lazily load a committee member from all shard groups + let committees = self.epoch_manager.get_committees(epoch).await?; + let mut count = 0; + + for (shard_group, committee) in committees { + info!( + target: LOG_TARGET, + "Scanning committee epoch={}, sg={}", + epoch, + shard_group + ); + let new_blocks = self + .get_new_blocks_from_committee(shard_group, &committee, epoch) + .await?; + info!( + target: LOG_TARGET, + "Scanned {} blocks in epoch={}", + new_blocks.len(), + epoch, + ); + + count += new_blocks.len(); + for block_data in new_blocks { + let timestamp = unix_epoch_to_primitive_date_time(block_data.block.timestamp()); + // TODO: store blocks + // TODO: remove substates (I think). These can be requested lazily and cached (LRU) as needed to allow + // TODO: an committed transaction should queue a shard state sync in the affected shards + // an upper bound on substates stored in the indexer. + self.store_substates_in_db(&block_data.diff, timestamp)?; + } + } + + Ok(count) + } + + async fn delete_scanned_epochs_older_than(&self, epoch: Epoch) -> Result<(), anyhow::Error> { + self.substate_store + .with_write_tx(|tx| tx.delete_scanned_epochs_older_than(epoch)) + .map_err(|e| e.into()) + } + + fn store_substates_in_db( + &self, + updates: &[SubstateUpdateProof], + timestamp: PrimitiveDateTime, + ) -> Result<(), anyhow::Error> { + let mut tx = self.substate_store.create_write_tx()?; + // store/update up substates if any + for update in updates { + match update { + SubstateUpdateProof::Create(create) => { + let maybe_substate_value = create.substate.value.value(); + if maybe_substate_value.is_none() { + warn!( + target: LOG_TARGET, + "⚠️ Received UP substate {} without value. This indicates that the substate has been pruned. Some event data is not available.", create.substate.as_versioned_substate_id_ref(), + ); + } + let template_address = maybe_substate_value.and_then(Self::extract_template_address_from_substate); + let module_name = maybe_substate_value.and_then(Self::extract_module_name_from_substate); + let substate_row = NewSubstate { + address: create.substate.substate_id.to_string(), + version: create.substate.version as i32, + data: maybe_substate_value + .map(Self::encode_substate) + .transpose()? + .unwrap_or_default(), + template_address: template_address.map(|s| s.to_string()), + module_name, + timestamp, + }; + debug!( + target: LOG_TARGET, + "Saving substate: {:?}", + substate_row + ); + tx.upsert_substate(substate_row)?; + }, + SubstateUpdateProof::Destroy(_) => {}, + } + } + tx.commit()?; + Ok(()) + } + + fn extract_template_address_from_substate(substate: &SubstateValue) -> Option { + match substate { + SubstateValue::Component(c) => Some(c.template_address), + _ => None, + } + } + + fn extract_module_name_from_substate(substate: &SubstateValue) -> Option { + match substate { + SubstateValue::Component(c) => Some(c.module_name.to_owned()), + _ => None, + } + } + + fn encode_substate(substate: &SubstateValue) -> Result { + let pretty_json = serde_json::to_string_pretty(&substate)?; + Ok(pretty_json) + } + + async fn get_oldest_scanned_epoch(&self) -> Result, anyhow::Error> { + self.substate_store + .with_read_tx(|tx| tx.get_oldest_scanned_epoch()) + .map_err(|e| e.into()) + } + + async fn get_new_blocks_from_committee( + &self, + shard_group: ShardGroup, + committee: &Committee, + epoch: Epoch, + ) -> Result, anyhow::Error> { + // We start scanning from the last scanned block for this committee + let start_block_id = self + .substate_store + .with_read_tx(|tx| tx.get_last_scanned_block_id(epoch, shard_group))?; + + info!( + target: LOG_TARGET, + "Scanning new blocks from (start_id={}, epoch={}, shard={})", + start_block_id.map(|id| id.to_string()).unwrap_or_else(|| "None".to_string()), + epoch, + shard_group + ); + + for member in committee.shuffled() { + debug!( + target: LOG_TARGET, + "Trying to get blocks from VN {} (epoch={}, shard_group={})", + member, + epoch, + shard_group + ); + let resp = self + .get_block_data_from_vn(&member.address, start_block_id, epoch) + .await; + + match resp { + Ok(block_data) => { + // TODO: try more than 1 VN per committee + info!( + target: LOG_TARGET, + "Got {} blocks from VN {} (epoch={}, shard_group={})", + block_data.len(), + member, + epoch, + shard_group, + ); + + // get the most recent block among all scanned blocks in the epoch + let last_block = block_data + .iter() + .max_by_key(|data| (data.block.epoch(), data.block.height())) + .map(|data| &data.block); + + if let Some(block) = last_block { + // Store the latest scanned block id in the database for future scans + self.save_scanned_block_id(epoch, shard_group, *block.id())?; + } + return Ok(block_data); + }, + Err(e) => { + // We do nothing on a single VN failure, we only log it + warn!( + target: LOG_TARGET, + "Could not get blocks from VN {} (epoch={}, shard_group={}): {}", + member, + epoch, + shard_group, + e + ); + }, + }; + } + + // We don't raise an error if none of the VNs have blocks, the scanning will retry eventually + warn!( + target: LOG_TARGET, + "Could not get blocks from any of the VNs of the committee (epoch={}, shard_group={})", + epoch, + shard_group + ); + Ok(vec![]) + } + + fn save_scanned_block_id( + &self, + epoch: Epoch, + shard_group: ShardGroup, + last_block_id: BlockId, + ) -> Result<(), anyhow::Error> { + let row = NewScannedBlockId { + epoch: epoch.0 as i64, + shard_group: shard_group.encode_as_u32() as i32, + last_block_id: last_block_id.as_bytes().to_vec(), + }; + self.substate_store.with_write_tx(|tx| tx.save_scanned_block_id(row))?; + Ok(()) + } + + // async fn get_all_vns(&self) -> Result, anyhow::Error> { + // // get all the committees + // let epoch = self.epoch_manager.current_epoch().await?; + // Ok(self + // .epoch_manager + // .get_all_validator_nodes(epoch) + // .await + // .map(|v| v.iter().map(|m| m.address).collect())?) + // } + + async fn get_block_data_from_vn( + &self, + vn_addr: &PeerAddress, + start_block_id: Option, + up_to_epoch: Epoch, + ) -> Result, anyhow::Error> { + let mut blocks = vec![]; + + let rpc_client = self.client_factory.create_client(vn_addr); + let mut client = rpc_client.client_connection().await?; + + let mut stream = client + .sync_blocks(SyncBlocksRequest { + start_block_id: start_block_id.map(|id| id.as_bytes().to_vec()).unwrap_or_default(), + epoch: Some(up_to_epoch.into()), + // TODO: QC should be validated + stream_qcs: false, + stream_substates: proto::rpc::StreamSubstateSelection::AllSubstates.into(), + stream_transactions: false, + }) + .await?; + while let Some(resp) = stream.next().await { + let msg = resp?; + + let new_block = msg + .into_block() + .ok_or_else(|| anyhow::anyhow!("Expected peer to return a newblock"))?; + let block = Block::try_from(new_block)?; + + let Some(resp) = stream.next().await else { + anyhow::bail!("Peer closed session before sending substate update count message") + }; + let msg = resp?; + let num_substates = + msg.substate_count() + .ok_or_else(|| anyhow::anyhow!("Expected peer to return substate count"))? as usize; + // TODO: what should this limit be? + if num_substates > 10_000 { + return Err(anyhow::anyhow!( + "Exceeded maximum number of substates (10,000). Got {}", + num_substates + )); + } + + let mut diff = Vec::with_capacity(num_substates); + for _ in 0..num_substates { + let Some(resp) = stream.next().await else { + anyhow::bail!("Peer closed session before sending substate updates message") + }; + let msg = resp?; + let update = msg + .into_substate_update() + .ok_or_else(|| anyhow::anyhow!("Expected a substate"))?; + let update = SubstateUpdateProof::try_from(update)?; + diff.push(update); + } + + blocks.push(BlockData { block, diff }); + } + + Ok(blocks) + } +} + +fn unix_epoch_to_primitive_date_time(timestamp: u64) -> PrimitiveDateTime { + let timestamp = i64::try_from(timestamp).unwrap_or_else(|e| { + // TODO: this is very possible because we trust that the timestamp is roughly correct, however + // it is purely informational and not enforced in consensus therefore could be any value and + // therefore cannot be relied for ordering (use (epoch,height) instead). + warn!( + target: LOG_TARGET, + "Failed to convert block timestamp to PrimitiveDateTime: {}", + e + ); + i64::MAX // = August 17, 292278994, 07:12:55.807 UTC + }); + OffsetDateTime::from_unix_timestamp(timestamp) + .map(|osdt| PrimitiveDateTime::new(osdt.date(), osdt.time())) + .unwrap_or_else(|e| { + warn!( + target: LOG_TARGET, + "Failed to convert block timestamp to OffsetDateTime: {}. Using UNIX_EPOCH", + e + ); + // An error cannot be because the timestamp is too small, because we use an u64 and a zero unix + // timestamp represents a greater date (1970 AD) than the minimum (9999 BC) + PrimitiveDateTime::MAX + }) +} diff --git a/applications/tari_indexer/src/network_state_sync/committee_client.rs b/applications/tari_indexer/src/network_state_sync/committee_client.rs new file mode 100644 index 0000000000..6100efe047 --- /dev/null +++ b/applications/tari_indexer/src/network_state_sync/committee_client.rs @@ -0,0 +1,171 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use std::{ + fmt::Display, + future::Future, + ops::{Deref, DerefMut}, +}; + +use log::*; +use tari_epoch_manager::{service::EpochManagerHandle, EpochManagerError, EpochManagerReader}; +use tari_networking::NetworkingHandle; +use tari_ootle_common_types::{optional::Optional, PeerAddress, ShardGroup, ToPeerId}; +use tari_ootle_p2p::TariMessagingSpec; +use tari_validator_node_rpc::{client::RpcMultiPool, rpc_service, ValidatorNodeRpcClientError}; + +const LOG_TARGET: &str = "tari::indexer::network_state_sync::committee_client"; + +#[derive(Debug, Clone)] +pub struct ValidatorCommitteeRpcPool { + shard_group: ShardGroup, + pool: RpcMultiPool, + epoch_manager: EpochManagerHandle, + past_failed_nodes: Vec, +} + +impl ValidatorCommitteeRpcPool { + pub fn new( + shard_group: ShardGroup, + networking: NetworkingHandle, + epoch_manager: EpochManagerHandle, + ) -> Self { + Self { + shard_group, + pool: RpcMultiPool::new(networking), + epoch_manager, + past_failed_nodes: vec![], + } + } + + pub async fn new_session(&self) -> Result { + let epoch = self.epoch_manager.get_current_epoch(); + let member = self + .epoch_manager + .get_random_committee_member(epoch, Some(self.shard_group), self.past_failed_nodes.clone()) + .await?; + self.session_for_peer(member.address).await + } + + async fn session_for_peer( + &self, + address: PeerAddress, + ) -> Result { + let client = self.pool.get_or_connect(&address.to_peer_id()).await?; + Ok(ValidatorRpcSession { + peer_address: address, + client, + }) + } + + /// Attempts to execute the provided callback with a session for a random committee member. + /// If the callback succeeds, it returns the response. + /// If the callback fails, it will try with another random member until all members have been attempted. + /// If all members fail, it returns an error with the last error encountered. + pub async fn try_with_random_members( + &mut self, + callback: F, + ) -> Result + where + F: Fn(ValidatorRpcSession) -> TFut, + TFut: Future>, + T: 'static, + E: Display + 'static, + { + let epoch = self.epoch_manager.get_current_epoch(); + let mut last_error = None; + let mut attempted = vec![]; + loop { + let Some(vn) = self + .epoch_manager + .get_random_committee_member(epoch, Some(self.shard_group), attempted.clone()) + .await + .optional()? + else { + // No more committee members to try + break; + }; + + let session = match self.session_for_peer(vn.address).await { + Ok(session) => session, + Err(err) => { + warn!( + target: LOG_TARGET, + "Failed to create session for validator '{}': {}", vn, err + ); + last_error = Some(err.to_string()); + attempted.push(vn.address); + self.past_failed_nodes.push(vn.address); + continue; // Skip this member and try the next one + }, + }; + + match callback(session).await { + Ok(ret) => { + return Ok(ret); + }, + Err(err) => { + warn!( + target: LOG_TARGET, + "Request failed for validator '{}': {}", vn, err + ); + last_error = Some(err.to_string()); + }, + } + + attempted.push(vn.address); + } + + Err(ValidatorCommitteeClientError::AllValidatorsFailed { + committee_size: attempted.len(), + last_error, + }) + } +} + +#[derive(Clone)] +pub struct ValidatorRpcSession { + peer_address: PeerAddress, + client: rpc_service::ValidatorNodeRpcClient, +} + +impl ValidatorRpcSession { + pub fn peer_address(&self) -> &PeerAddress { + &self.peer_address + } + + pub fn client(&self) -> &rpc_service::ValidatorNodeRpcClient { + &self.client + } + + pub fn client_mut(&mut self) -> &mut rpc_service::ValidatorNodeRpcClient { + &mut self.client + } +} + +impl Deref for ValidatorRpcSession { + type Target = rpc_service::ValidatorNodeRpcClient; + + fn deref(&self) -> &Self::Target { + self.client() + } +} + +impl DerefMut for ValidatorRpcSession { + fn deref_mut(&mut self) -> &mut rpc_service::ValidatorNodeRpcClient { + self.client_mut() + } +} + +#[derive(Debug, thiserror::Error)] +pub enum ValidatorCommitteeClientError { + #[error("Epoch manager error: {0}")] + EpochManagerError(#[from] EpochManagerError), + #[error("Validator node RPC client error: {0}")] + ValidatorNodeRpcClientError(#[from] ValidatorNodeRpcClientError), + #[error("Rpc call failed for all ({committee_size}) validators: {}", .last_error.as_deref().unwrap_or("unknown"))] + AllValidatorsFailed { + committee_size: usize, + last_error: Option, + }, +} diff --git a/applications/tari_indexer/src/network_state_sync/config.rs b/applications/tari_indexer/src/network_state_sync/config.rs new file mode 100644 index 0000000000..181d18713f --- /dev/null +++ b/applications/tari_indexer/src/network_state_sync/config.rs @@ -0,0 +1,21 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use std::{sync::Arc, time::Duration}; + +use crate::network_state_sync::EventFilter; + +#[derive(Debug, Clone)] +pub struct NetworkWideStateSyncConfig { + pub work_interval: Duration, + pub event_filters: Arc<[EventFilter]>, +} + +impl Default for NetworkWideStateSyncConfig { + fn default() -> Self { + Self { + work_interval: Duration::from_secs(60), + event_filters: Arc::new([]), + } + } +} diff --git a/applications/tari_indexer/src/network_state_sync/error.rs b/applications/tari_indexer/src/network_state_sync/error.rs new file mode 100644 index 0000000000..0dd02d2b5c --- /dev/null +++ b/applications/tari_indexer/src/network_state_sync/error.rs @@ -0,0 +1,28 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use tari_epoch_manager::EpochManagerError; +use tari_ootle_storage::StorageError; +use tari_rpc_framework::{RpcError, RpcStatus}; + +use crate::network_state_sync::committee_client::ValidatorCommitteeClientError; + +#[derive(Debug, thiserror::Error)] +pub enum NetworkStateSyncError { + #[error("Epoch manager error: {0}")] + EpochManagerError(#[from] EpochManagerError), + #[error("Storage error: {0}")] + StorageError(#[from] StorageError), + #[error("Validator committee client error: {0}")] + ValidatorCommitteeClientError(#[from] ValidatorCommitteeClientError), + #[error("Invalid checkpoint: {details}")] + InvalidCheckpoint { details: String }, + #[error("Invalid state update: {details}")] + InvalidStateUpdate { details: String }, + #[error("Request failed: {0}")] + RequestFailed(#[from] RpcStatus), + #[error("Rpc error: {0}")] + RpcError(#[from] RpcError), + #[error("Invariant error: {details}. This indicates a bug in the code, please report it.")] + InvariantError { details: String }, +} diff --git a/applications/tari_indexer/src/network_state_sync/event_filter.rs b/applications/tari_indexer/src/network_state_sync/event_filter.rs new file mode 100644 index 0000000000..02178b84d5 --- /dev/null +++ b/applications/tari_indexer/src/network_state_sync/event_filter.rs @@ -0,0 +1,38 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use serde::{Deserialize, Serialize}; +use tari_engine_types::{events::Event, substate::SubstateId}; +use tari_template_lib::prelude::{EntityId, TemplateAddress}; + +#[derive(Default, Debug, Serialize, Deserialize, Clone)] +pub struct EventFilter { + pub topic: Option, + pub entity_id: Option, + pub substate_id: Option, + pub template_address: Option, +} + +impl EventFilter { + pub fn matches(&self, event: &Event) -> bool { + let matches_topic = self.topic.as_ref().is_none_or(|t| *t == event.topic()); + let matches_template = self + .template_address + .as_ref() + .is_none_or(|t| *t == event.template_address()); + + let matches_substate_id = self + .substate_id + .as_ref() + .is_none_or(|substate_id| event.substate_id().map(|s| s == substate_id).unwrap_or(false)); + + let matches_entity_id = self.entity_id.as_ref().is_none_or(|entity_id| { + event + .substate_id() + .map(|s| s.to_object_key().as_entity_id() == *entity_id) + .unwrap_or(false) + }); + + matches_topic && matches_template && matches_substate_id && matches_entity_id + } +} diff --git a/applications/tari_indexer/src/network_state_sync/mod.rs b/applications/tari_indexer/src/network_state_sync/mod.rs new file mode 100644 index 0000000000..c4ea3df937 --- /dev/null +++ b/applications/tari_indexer/src/network_state_sync/mod.rs @@ -0,0 +1,17 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +mod block_scanner; +mod committee_client; +mod config; +mod error; +mod event_filter; +mod stats; +mod sync_plan; +mod sync_progress; +mod worker; + +pub use block_scanner::*; +pub use config::*; +pub use event_filter::*; +pub use worker::*; diff --git a/applications/tari_indexer/src/network_state_sync/stats.rs b/applications/tari_indexer/src/network_state_sync/stats.rs new file mode 100644 index 0000000000..a0be4ab360 --- /dev/null +++ b/applications/tari_indexer/src/network_state_sync/stats.rs @@ -0,0 +1,51 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use std::fmt::Display; + +#[derive(Debug, Clone, Default)] +pub struct SyncStats { + pub total_checkpoints: usize, + pub total_state_updates: usize, + pub total_events: usize, +} + +impl SyncStats { + pub fn new() -> Self { + Self { + total_checkpoints: 0, + total_state_updates: 0, + total_events: 0, + } + } + + pub fn increment_checkpoints(&mut self) { + self.total_checkpoints += 1; + } + + pub fn increase_state_updates(&mut self, by: usize) { + self.total_state_updates += by; + } + + pub fn increase_events(&mut self, by: usize) { + self.total_events += by; + } + + pub fn log_stats(&self) { + log::info!("{}", self); + } + + pub fn reset(&mut self) { + *self = Self::new(); + } +} + +impl Display for SyncStats { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Sync Stats: {{ checkpoints: {}, state_updates: {}, events: {} }}", + self.total_checkpoints, self.total_state_updates, self.total_events + ) + } +} diff --git a/applications/tari_indexer/src/network_state_sync/sync_plan.rs b/applications/tari_indexer/src/network_state_sync/sync_plan.rs new file mode 100644 index 0000000000..2c6de9b4e9 --- /dev/null +++ b/applications/tari_indexer/src/network_state_sync/sync_plan.rs @@ -0,0 +1,51 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use std::collections::HashMap; + +use tari_epoch_manager::service::NetworkDescription; +use tari_ootle_common_types::{shard::Shard, Epoch, ShardGroup, StateVersion}; + +use crate::network_state_sync::{committee_client::ValidatorCommitteeRpcPool, sync_progress::SyncProgress}; + +pub struct SyncPlan { + network_description: NetworkDescription, + sync_progress: SyncProgress, + committee_pools: HashMap, +} + +impl SyncPlan { + pub fn new( + network_description: NetworkDescription, + sync_progress: SyncProgress, + committee_pools: HashMap, + ) -> Self { + Self { + network_description, + sync_progress, + committee_pools, + } + } + + pub fn add_checkpoint_sync_progress(&mut self, shard_group: ShardGroup, epoch: Epoch) { + self.sync_progress.checkpoint_progress.insert(shard_group, epoch); + } + + pub fn add_state_sync_progress(&mut self, shard: Shard, state_version: StateVersion, epoch: Epoch) { + self.sync_progress + .last_state_versions + .insert(shard, (state_version, epoch)); + } + + pub fn sync_progress(&self) -> &SyncProgress { + &self.sync_progress + } + + pub fn committee_pools(&self) -> &HashMap { + &self.committee_pools + } + + pub fn network_description(&self) -> &NetworkDescription { + &self.network_description + } +} diff --git a/applications/tari_indexer/src/network_state_sync/sync_progress.rs b/applications/tari_indexer/src/network_state_sync/sync_progress.rs new file mode 100644 index 0000000000..4b04b462a0 --- /dev/null +++ b/applications/tari_indexer/src/network_state_sync/sync_progress.rs @@ -0,0 +1,18 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use async_graphql::indexmap::IndexMap; +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, Seq}; +use tari_ootle_common_types::{shard::Shard, Epoch, ShardGroup, StateVersion}; + +#[serde_as] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct SyncProgress { + pub last_epoch: Epoch, + // These transform the maps into Vecs for JSON serialization (can't have non-string keys). + #[serde_as(as = "Seq<(_, _)>")] + pub checkpoint_progress: IndexMap, + #[serde_as(as = "Seq<(_, _)>")] + pub last_state_versions: IndexMap, +} diff --git a/applications/tari_indexer/src/network_state_sync/worker.rs b/applications/tari_indexer/src/network_state_sync/worker.rs new file mode 100644 index 0000000000..f467de64c2 --- /dev/null +++ b/applications/tari_indexer/src/network_state_sync/worker.rs @@ -0,0 +1,529 @@ +// Copyright 2024 The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use std::{collections::HashMap, pin::pin}; + +use futures::StreamExt; +use log::*; +use tari_engine_types::{ + substate::{SubstateId, SubstateValue}, + transaction_receipt::TransactionReceipt, +}; +use tari_epoch_manager::{service::EpochManagerHandle, EpochManagerEvent, EpochManagerReader}; +use tari_indexer_client::types::{UtxoSpent, UtxoUnspent, UtxoUpdate}; +use tari_networking::NetworkingHandle; +use tari_ootle_common_types::{ + optional::Optional, + shard::Shard, + Epoch, + PeerAddress, + ShardGroup, + StateVersion, + VotePower, +}; +use tari_ootle_p2p::{proto::rpc, TariMessagingSpec}; +use tari_ootle_storage::{ + consensus_models::{EpochCheckpoint, SubstateUpdateProof, SubstateValueFilterFlags}, + StorageError, +}; +use tari_rpc_framework::__macro_reexports::future::Either; +use tari_shutdown::ShutdownSignal; +use tari_template_manager::interface::{TemplateChange, TemplateManagerHandle}; +use tokio::time; + +use crate::{ + network_state_sync::{ + committee_client::{ValidatorCommitteeRpcPool, ValidatorRpcSession}, + config::NetworkWideStateSyncConfig, + error::NetworkStateSyncError, + stats::SyncStats, + sync_plan::SyncPlan, + sync_progress::SyncProgress, + }, + storage_sqlite::{ + models::Key, + store_factory::{ + IndexerStore, + IndexerStoreReadTransaction, + IndexerStoreWriteTransaction, + SqliteIndexerStore, + SqliteStoreWriteTransaction, + }, + }, +}; + +const LOG_TARGET: &str = "tari::indexer::network_state_sync::worker"; + +#[derive(Clone)] +pub struct NetworkWideStateSync { + epoch_manager: EpochManagerHandle, + networking: NetworkingHandle, + store: SqliteIndexerStore, + template_manager: TemplateManagerHandle, + stats: SyncStats, + config: NetworkWideStateSyncConfig, +} + +impl NetworkWideStateSync { + pub fn new( + epoch_manager: EpochManagerHandle, + networking: NetworkingHandle, + storage: SqliteIndexerStore, + template_manager: TemplateManagerHandle, + config: NetworkWideStateSyncConfig, + ) -> Self { + Self { + epoch_manager, + networking, + store: storage, + template_manager, + stats: SyncStats::new(), + config, + } + } + + pub fn spawn(mut self, shutdown_signal: ShutdownSignal) -> tokio::task::JoinHandle<()> { + tokio::spawn(async move { + loop { + let config = self.config.clone(); + let task = self.start(); + let task = pin!(task); + match shutdown_signal.clone().select(task).await { + Either::Left(_) => { + info!(target: LOG_TARGET, "🌍️ Network-wide state sync was shutdown."); + break; + }, + Either::Right((Ok(()), _)) => { + info!(target: LOG_TARGET, "🌍️ Network-wide state sync completed successfully."); + }, + Either::Right((Err(e), _)) => { + error!(target: LOG_TARGET, "⚠️ Network-wide state sync failed: {}", e); + // Restart after cooldown + time::sleep(config.work_interval).await; + }, + } + } + }) + } + + async fn start(&mut self) -> Result<(), NetworkStateSyncError> { + self.epoch_manager.wait_for_initial_scanning_to_complete().await?; + let mut epoch_events = self.epoch_manager.subscribe(); + + // TODO: configurable + let mut interval = time::interval(self.config.work_interval); + interval.set_missed_tick_behavior(time::MissedTickBehavior::Delay); + + loop { + tokio::select! { + Ok(event) = epoch_events.recv() => { + interval.reset(); + self.handle_epoch_event(event).await?; + }, + _ = interval.tick() => { + self.start_sync_round().await?; + } + } + } + } + + async fn start_sync_round(&mut self) -> Result<(), NetworkStateSyncError> { + info!(target: LOG_TARGET, "🌍️ Starting network-wide state sync round..."); + let sync_plan = self.initialize_sync_plan().await?; + self.start_sync(sync_plan).await?; + self.stats.log_stats(); + self.stats.reset(); + Ok(()) + } + + async fn handle_epoch_event(&mut self, event: EpochManagerEvent) -> Result<(), NetworkStateSyncError> { + match event { + EpochManagerEvent::EpochChanged { epoch, .. } => { + info!(target: LOG_TARGET, "🌍️ Epoch changed to {}.", epoch); + self.start_sync_round().await?; + }, + } + Ok(()) + } + + async fn initialize_sync_plan(&self) -> Result { + let network_desc = self.epoch_manager.get_network_description().await?; + let sync_progress = self + .store + .with_read_tx(|tx| tx.key_value_get_value::<_, SyncProgress>(Key::SyncProgress)) + .optional()? + .unwrap_or_default(); + + let mut committee_pools = HashMap::with_capacity(network_desc.num_committees()); + for shard_group in network_desc.shard_groups_iter() { + let pool = ValidatorCommitteeRpcPool::new(shard_group, self.networking.clone(), self.epoch_manager.clone()); + committee_pools.insert(shard_group, pool); + } + + Ok(SyncPlan::new(network_desc, sync_progress, committee_pools)) + } + + async fn start_sync(&mut self, mut sync_plan: SyncPlan) -> Result<(), NetworkStateSyncError> { + self.sync_checkpoints(&mut sync_plan).await?; + self.sync_state(&mut sync_plan).await?; + + Ok(()) + } + + async fn sync_checkpoints(&mut self, sync_plan_mut: &mut SyncPlan) -> Result<(), NetworkStateSyncError> { + let prev_epoch = sync_plan_mut + .network_description() + .epoch() + .checked_sub(Epoch(1)) + .ok_or_else(|| NetworkStateSyncError::InvariantError { + details: "current epoch is zero, there are on checkpoints to sync".to_string(), + })?; + let committee_pools = sync_plan_mut.committee_pools().clone(); + + for (shard_group, mut pool) in committee_pools { + let from_epoch = sync_plan_mut + .sync_progress() + .checkpoint_progress + .get(&shard_group) + .copied() + .unwrap_or_else(Epoch::zero); + if from_epoch >= prev_epoch { + info!(target: LOG_TARGET, "🌍️ No checkpoints to sync for shard group {shard_group} from epoch {from_epoch}"); + continue; + } + info!(target: LOG_TARGET, "🌍️ Syncing checkpoints from {from_epoch} for shard group {shard_group}"); + // Perform sync operations using the pool and checkpoint + let checkpoints: Vec<_> = pool + .try_with_random_members(|mut session| async move { + let resp = session + .get_checkpoints(rpc::GetCheckpointsRequest { + from_epoch: Some(from_epoch.into()), + num_to_return: 100, + }) + .await?; + + debug!(target: LOG_TARGET, "🌍️ Received {} checkpoints for shard group {} from peer {}", resp.checkpoints.len(), shard_group, session.peer_address()); + + resp.checkpoints + .into_iter() + .map(|cp| { + EpochCheckpoint::try_from(cp).map_err(|e| NetworkStateSyncError::InvalidCheckpoint { + details: format!("Failed to convert checkpoint for shard group {}: {}", shard_group, e), + }) + }) + .collect() + }) + .await?; + + if checkpoints.is_empty() { + info!(target: LOG_TARGET, "🌍️ No checkpoints found for shard group {shard_group} from epoch {from_epoch}"); + continue; + } + + info!(target: LOG_TARGET, "🌍️ Found {} checkpoints for shard group {shard_group} from epoch {from_epoch}", checkpoints.len()); + + let committee = self + .epoch_manager + .get_committee_by_shard_group(prev_epoch, shard_group, None) + .await?; + + // TODO: continue on failure + for checkpoint in checkpoints { + info!(target: LOG_TARGET, "🌍️ Validating checkpoint for shard group {shard_group}: {:?}", checkpoint); + // TODO: we require historical committees to validate older checkpoints. Figure out the best way to + // avoid needing the data (e.g. VN merkle inclusion proof + historic L1 block MR), or, + // decide it is ok to require this data to be locally stored by all indexers. For now, to avoid + // complexity that may be removed later, we'll skip validating them and only validate prev_epochs + // checkpoint. + let checkpoint_shard_group = + checkpoint + .checked_shard_group() + .map_err(|e| NetworkStateSyncError::InvalidCheckpoint { + details: format!("Checkpoint for shard group {} is not valid: {}", shard_group, e), + })?; + + if checkpoint.epoch() == prev_epoch { + checkpoint + .validate(checkpoint.epoch(), committee.quorum_threshold(), |pk| { + Ok(committee.get_power_by_public_key(pk).unwrap_or_else(VotePower::zero)) + }) + .map_err(|e| NetworkStateSyncError::InvalidCheckpoint { + details: format!("Failed to validate checkpoint for shard group {}: {}", shard_group, e), + })?; + } else { + checkpoint + .validate_well_formed() + .map_err(|e| NetworkStateSyncError::InvalidCheckpoint { + details: format!( + "Failed to validate well-formedness of checkpoint for shard group {}: {}", + checkpoint_shard_group, e + ), + })?; + debug!(target: LOG_TARGET, "🌍️ Skipping checkpoint for shard group {shard_group} with epoch {} (expected {})", checkpoint.epoch(), prev_epoch); + } + + info!(target: LOG_TARGET, "🌍️ Inserting checkpoint for {}, shard group {}", checkpoint.epoch(), checkpoint_shard_group); + + self.stats.increment_checkpoints(); + sync_plan_mut.add_checkpoint_sync_progress(shard_group, checkpoint.epoch()); + self.store.with_write_tx(|tx| { + tx.insert_or_ignore_epoch_checkpoint(&checkpoint)?; + tx.key_value_set(Key::SyncProgress, sync_plan_mut.sync_progress()) + })?; + } + } + + Ok(()) + } + + async fn sync_state(&mut self, sync_plan_mut: &mut SyncPlan) -> Result<(), NetworkStateSyncError> { + let committee_pools = sync_plan_mut.committee_pools().clone(); + let mut update_buf = Vec::new(); + let mut utxos_buf = Vec::new(); + let mut transactions_buf = Vec::new(); + + let mut has_synced_global_shard = false; + + for (shard_group, pool) in committee_pools { + // TODO: make this robust against failures, e.g. if one peer fails, continue with others + // TODO: consider syncing shards in epoch chunks rather than one after another + // TODO: consider parallelizing shard syncs within a shard group + let mut session = pool.new_session().await?; + if !has_synced_global_shard { + self.sync_shard_state( + Shard::global(), + sync_plan_mut, + &mut update_buf, + &mut utxos_buf, + &mut transactions_buf, + shard_group, + &mut session, + ) + .await?; + has_synced_global_shard = true; + } + + for shard in shard_group.shard_iter() { + self.sync_shard_state( + shard, + sync_plan_mut, + &mut update_buf, + &mut utxos_buf, + &mut transactions_buf, + shard_group, + &mut session, + ) + .await?; + } + } + + Ok(()) + } + + async fn sync_shard_state( + &mut self, + shard: Shard, + sync_plan_mut: &mut SyncPlan, + update_buf: &mut Vec<(Epoch, SubstateUpdateProof)>, + utxos_buf: &mut Vec, + transactions_buf: &mut Vec, + shard_group: ShardGroup, + session: &mut ValidatorRpcSession, + ) -> Result<(), NetworkStateSyncError> { + // Perform sync operations using the pool and state + let (prev_version, prev_epoch) = sync_plan_mut + .sync_progress() + .last_state_versions + .get(&shard) + .map(|(v, e)| (v.as_u64(), *e)) + .unwrap_or_else(|| (0, Epoch::zero())); + let from_version = prev_version + 1; + + let mut stream = session + .sync_state(rpc::SyncStateRequest { + start_state_version: from_version, + shard: shard.as_u32(), + // Sync to latest epoch + until_epoch: None, + value_filters: (SubstateValueFilterFlags::UTXO | + SubstateValueFilterFlags::TEMPLATE | + SubstateValueFilterFlags::TRANSACTION_RECEIPT) + .bits(), + }) + .await?; + + let mut is_first_iter = true; + while let Some(result) = stream.next().await { + // Allocations are unavoidable for templates (since the call to the template manager requires owned data due + // to async service call). This is completely fine as published templates are expected to be + // relatively rare compared to other substate updates. + let mut templates_buf = Vec::new(); + + if is_first_iter { + // Avoid log spam, only log if we actually get something from the stream + debug!(target: LOG_TARGET, "🌍️ Established stream for {shard} in shard group {shard_group} from peer {} (last sync: {prev_epoch} {prev_version})", session.peer_address()); + is_first_iter = false; + } + let msg = result?; + let msg_epoch = msg + .epoch + .map(Epoch::from) + .ok_or_else(|| NetworkStateSyncError::InvalidStateUpdate { + details: "Received state update without epoch".to_string(), + })?; + let state_version = StateVersion::new(msg.state_version); + + for update in msg.updates { + let update = + SubstateUpdateProof::try_from(update).map_err(|e| NetworkStateSyncError::InvalidStateUpdate { + details: format!("Failed to convert substate update: {}", e), + })?; + + extend_bufs_from_substate_update( + shard, + state_version, + update, + msg_epoch, + update_buf, + &mut templates_buf, + utxos_buf, + transactions_buf, + )?; + } + if msg.has_more { + debug!(target: LOG_TARGET, "🌍️ more updates for shard {shard} (epoch: {msg_epoch}, state version: {state_version})"); + continue; + } + + info!(target: LOG_TARGET, "🌍️ Received {} updates for shard {shard} (epoch: {msg_epoch}, state version: {state_version})", update_buf.len()); + + self.stats.increase_state_updates(update_buf.len()); + + self.store.clone().with_write_tx(|tx| { + debug!(target: LOG_TARGET, "βœ… Committing {} updates for shard {shard} (epoch: {msg_epoch}, state version: {state_version})", update_buf.len()); + tx.batch_insert_substate_transitions(shard, state_version, update_buf.drain(..))?; + debug!(target: LOG_TARGET, "βœ… Committing {} UTXOs for shard {shard} (epoch: {msg_epoch})", utxos_buf.len()); + tx.batch_insert_utxo_updates(utxos_buf.drain(..))?; + // TODO: transaction events and templates + debug!(target: LOG_TARGET, "βœ… Committing {} transactions for shard {shard} (epoch: {msg_epoch})", transactions_buf.len()); + self.stats.increase_events(transactions_buf.len()); + self.persist_transaction_receipts(tx, transactions_buf.drain(..))?; + + // All done - write the sync progress + sync_plan_mut.add_state_sync_progress(shard, state_version, msg_epoch); + tx.key_value_set(Key::SyncProgress, sync_plan_mut.sync_progress()) + })?; + + if !templates_buf.is_empty() { + info!(target: LOG_TARGET, "🌍️ Persisting {} template changes for shard {shard} (epoch: {msg_epoch})", templates_buf.len()); + if let Err(err) = self.template_manager.enqueue_template_changes(templates_buf).await { + error!(target: LOG_TARGET, "⚠️ Failed to enqueue template changes: {}", err); + } + } + } + Ok(()) + } + + fn persist_transaction_receipts>( + &self, + tx: &mut SqliteStoreWriteTransaction<'_>, + receipts: I, + ) -> Result<(), StorageError> { + let events = receipts + .into_iter() + .flat_map(|receipt| receipt.events) + // only keep the events specified by the indexer filter + .filter(|event| { + self.config.event_filters.is_empty() || self.config.event_filters.iter().any(|filter| filter.matches(event)) + }); + + tx.batch_insert_events(events)?; + + Ok(()) + } +} + +fn extend_bufs_from_substate_update( + shard: Shard, + state_version: StateVersion, + update: SubstateUpdateProof, + msg_epoch: Epoch, + update_buf: &mut Vec<(Epoch, SubstateUpdateProof)>, + templates_buf: &mut Vec, + utxos_buf: &mut Vec, + transactions_buf: &mut Vec, +) -> Result<(), NetworkStateSyncError> { + match &update { + SubstateUpdateProof::Create(create) => match create.substate.value().value() { + Some(SubstateValue::Utxo(utxo)) => { + utxos_buf.push(UtxoUpdate::Unspent(UtxoUnspent { + versioned_substate_id: update.to_versioned_substate_id(), + shard, + state_version, + utxo: utxo.clone(), + })); + }, + Some(SubstateValue::TransactionReceipt(receipt)) => { + transactions_buf.push(receipt.clone()); + }, + Some(SubstateValue::Template(template)) => { + if let Some(address) = create.substate.substate_id().as_template() { + templates_buf.push(TemplateChange::Add { + template_address: address, + author_public_key: template.author, + binary_hash: template.binary_hash.into_array().into(), + epoch: msg_epoch, + }); + } else { + // This is invalid, but possible given a malfunctioning validator + warn!(target: LOG_TARGET, "⚠️ NEVER HAPPEN: Received template substate with invalid address: {}", create.substate.substate_id()); + } + }, + Some(_) => {}, + None => { + let id = create.substate.substate_id(); + if id.is_template() || id.is_transaction_receipt() || id.is_utxo() { + warn!(target: LOG_TARGET, "⚠️ NEVER HAPPEN: Received substate {id} update with no value"); + } + }, + }, + SubstateUpdateProof::Destroy(destroy) => match destroy.substate_id { + SubstateId::TransactionReceipt(_) => { + warn!(target: LOG_TARGET, "⚠️ NEVER HAPPEN: Received destroy for transaction receipt substate: {}", destroy.substate_id); + }, + SubstateId::Template(template_address) => { + // Currently not possible + templates_buf.push(TemplateChange::Deprecate { template_address }); + }, + SubstateId::Utxo(_) => { + utxos_buf.push(UtxoUpdate::Spent(UtxoSpent { + versioned_substate_id: update.to_versioned_substate_id(), + state_version, + })); + }, + _ => {}, + }, + } + + update_buf.push((msg_epoch, update)); + Ok(()) +} diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2023-02-16-145719_create_substates/up.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2023-02-16-145719_create_substates/up.sql deleted file mode 100644 index fb6da35f49..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2023-02-16-145719_create_substates/up.sql +++ /dev/null @@ -1,9 +0,0 @@ -create table substates -( - id integer not NULL primary key AUTOINCREMENT, - address text not NULL, - version int not NULL, - data text not NULL -); - -create unique index uniq_substates_address on substates (address); \ No newline at end of file diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2023-02-16-145719_create_substates/down.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2023-02-16-145719_initial/down.sql similarity index 100% rename from applications/tari_indexer/src/storage_sqlite/migrations/2023-02-16-145719_create_substates/down.sql rename to applications/tari_indexer/src/storage_sqlite/migrations/2023-02-16-145719_initial/down.sql diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2023-02-16-145719_initial/up.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2023-02-16-145719_initial/up.sql new file mode 100644 index 0000000000..81bf01e678 --- /dev/null +++ b/applications/tari_indexer/src/storage_sqlite/migrations/2023-02-16-145719_initial/up.sql @@ -0,0 +1,137 @@ +create table substates +( + id integer not NULL primary key AUTOINCREMENT, + address text not NULL, + version int not NULL, + data text not NULL, + template_address text NULL, + module_name text NULL, + -- Block timestamp + timestamp timestamp not NULL, + updated_at timestamp not null default current_timestamp, + created_at timestamp not null default current_timestamp +); + +create unique index uniq_substates_address on substates (address); + +create table substate_transitions +( + id integer not NULL primary key AUTOINCREMENT, + shard int not NULL, + state_version bigint not NULL, + epoch bigint not NULL, + substate_id text not NULL, + version int not NULL, + substate_type text not NULL, + is_up bool not NULL, + value_hash text NULL, + created_at timestamp not null default current_timestamp +); + +create unique index substate_transitions_substate_id_version_uniq on substate_transitions (substate_id, version, is_up); +create index substate_transitions_shard_state_version_idx on substate_transitions (shard, state_version); + +-- all the indexes in NFT resources +create table non_fungible_indexes +( + id integer not NULL primary key AUTOINCREMENT, + resource_address text not NULL, + idx integer not NULL, + non_fungible_address text not NULL, + FOREIGN KEY (resource_address) REFERENCES substates (address), + FOREIGN KEY (non_fungible_address) REFERENCES substates (address) +); + +-- A list can only have one single item at any specific position +create unique index uniq_nft_indexes on non_fungible_indexes (resource_address, idx); + +-- DB index for faster collection scan queries +create index nft_indexes_resource on non_fungible_indexes (resource_address, idx); + +-- Event data +create table events +( + id integer not NULL primary key AUTOINCREMENT, + template_address text not NULL, + tx_hash text not NULL, + topic text not NULL, + payload text not NULL, + substate_id text NULL, + created_at timestamp not null default current_timestamp +); + + +-- DB index for faster collection scan queries +create index events_indexer on events (template_address, tx_hash); + +-- Latest scanned blocks, separately by committee (epoch + shard) +-- Used mostly for efficient scanning of events in the whole network +create table scanned_block_ids +( + id integer not NULL primary key AUTOINCREMENT, + epoch bigint not NULL, + shard_group integer not null, + last_block_id blob not null +); + + +-- There should only be one last scanned block by committee (epoch + shard) +create unique index scanned_block_ids_unique_committee on scanned_block_ids (epoch, shard_group); + +-- DB index for faster retrieval of the latest block by committee +create index scanned_block_ids_committee on scanned_block_ids (epoch, shard_group); + +create table transactions +( + id integer not NULL primary key AUTOINCREMENT, + transaction_id text not NULL, + body text not null, + created_at timestamp not null default current_timestamp +); + +create unique index transactions_transaction_id_uniq_idx on transactions (transaction_id); + +-- General purpose key value table +CREATE TABLE key_values +( + id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + key TEXT NOT NULL, + value TEXT NOT NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX key_values_uniq_key on key_values (key); + +-- Epoch checkpoints +CREATE TABLE epoch_checkpoints +( + id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + epoch BIGINT NOT NULL, + shard_group TEXT NOT NULL, + json_data TEXT NOT NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX epoch_checkpoints_uniq_epoch_shard_group ON epoch_checkpoints (epoch, shard_group); + +create table utxos +( + id integer not NULL primary key AUTOINCREMENT, + substate_id text not NULL, + version int not NULL, + resource_address text not NULL, + shard int not NULL, + state_version bigint not NULL, + output text NULL, + utxo_tag_byte int NULL, + is_spent boolean not NULL, + is_burnt boolean not NULL, + is_frozen boolean not NULL, + created_at timestamp not null default current_timestamp +); + +CREATE INDEX utxos_shard_tag_resource_state_version_idx + ON utxos (shard, utxo_tag_byte, resource_address, state_version); + diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2023-03-02-162407_create_nft_indexes/down.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2023-03-02-162407_create_nft_indexes/down.sql deleted file mode 100644 index 291a97c5ce..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2023-03-02-162407_create_nft_indexes/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` \ No newline at end of file diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2023-03-02-162407_create_nft_indexes/up.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2023-03-02-162407_create_nft_indexes/up.sql deleted file mode 100644 index cad2198cb5..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2023-03-02-162407_create_nft_indexes/up.sql +++ /dev/null @@ -1,16 +0,0 @@ --- all the indexes in NFT resources -create table non_fungible_indexes -( - id integer not NULL primary key AUTOINCREMENT, - resource_address text not NULL, - idx integer not NULL, - non_fungible_address text not NULL, - FOREIGN KEY (resource_address) REFERENCES substates (address), - FOREIGN KEY (non_fungible_address) REFERENCES substates (address) -); - --- A list can only have one single item at any specific position -create unique index uniq_nft_indexes on non_fungible_indexes (resource_address, idx); - --- DB index for faster collection scan queries -create index nft_indexes_resource on non_fungible_indexes (resource_address, idx); \ No newline at end of file diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2023-04-28-153806_create_events_table/down.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2023-04-28-153806_create_events_table/down.sql deleted file mode 100644 index d9a93fe9a1..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2023-04-28-153806_create_events_table/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2023-04-28-153806_create_events_table/up.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2023-04-28-153806_create_events_table/up.sql deleted file mode 100644 index fa3ad07043..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2023-04-28-153806_create_events_table/up.sql +++ /dev/null @@ -1,16 +0,0 @@ --- Event data -create table events -( - id integer not NULL primary key AUTOINCREMENT, - template_address text not NULL, - tx_hash text not NULL, - topic text not NULL, - payload text not NULL -); - - --- An event should be uniquely identified by its template_address, tx_hash and topic -create unique index unique_events_indexer on events (template_address, tx_hash, topic); - --- DB index for faster collection scan queries -create index events_indexer on events (template_address, tx_hash); diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2023-05-03-054827_add_transaction_hash_to_substate/down.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2023-05-03-054827_add_transaction_hash_to_substate/down.sql deleted file mode 100644 index 291a97c5ce..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2023-05-03-054827_add_transaction_hash_to_substate/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` \ No newline at end of file diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2023-05-03-054827_add_transaction_hash_to_substate/up.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2023-05-03-054827_add_transaction_hash_to_substate/up.sql deleted file mode 100644 index 7f4f41091e..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2023-05-03-054827_add_transaction_hash_to_substate/up.sql +++ /dev/null @@ -1,2 +0,0 @@ -alter table substates - add column transaction_hash blob null; \ No newline at end of file diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2023-05-19-165832_add_version_to_events_table/down.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2023-05-19-165832_add_version_to_events_table/down.sql deleted file mode 100644 index 291a97c5ce..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2023-05-19-165832_add_version_to_events_table/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` \ No newline at end of file diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2023-05-19-165832_add_version_to_events_table/up.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2023-05-19-165832_add_version_to_events_table/up.sql deleted file mode 100644 index f7f7a98d41..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2023-05-19-165832_add_version_to_events_table/up.sql +++ /dev/null @@ -1,8 +0,0 @@ -alter table events - add column version integer not null; - -alter table events - add column component_address text null; - --- drop previous index -drop index unique_events_indexer; diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2024-03-19-114926_refactor_event_payloads/down.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2024-03-19-114926_refactor_event_payloads/down.sql deleted file mode 100644 index d9a93fe9a1..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2024-03-19-114926_refactor_event_payloads/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2024-03-19-114926_refactor_event_payloads/up.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2024-03-19-114926_refactor_event_payloads/up.sql deleted file mode 100644 index 4f397ce83e..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2024-03-19-114926_refactor_event_payloads/up.sql +++ /dev/null @@ -1,19 +0,0 @@ --- All key-value pairs in event payloads -create table event_payloads -( - id integer not NULL primary key AUTOINCREMENT, - payload_key text not NULL, - payload_value text not NULL, - event_id integer not NULL, - - FOREIGN KEY (event_id) REFERENCES events (id) -); - --- A payload key should be unique by event -create unique index unique_event_payload_keys on event_payloads (event_id, payload_key); - --- Index for faster retrieval of all payloads of an event -create index event_payloads_index on event_payloads (event_id); - --- Index for faster scan queries by key and value -create index event_payloads_key_value_index on event_payloads (payload_key, payload_value); \ No newline at end of file diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2024-03-21-212928_refactor_event_substate/down.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2024-03-21-212928_refactor_event_substate/down.sql deleted file mode 100644 index d9a93fe9a1..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2024-03-21-212928_refactor_event_substate/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2024-03-21-212928_refactor_event_substate/up.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2024-03-21-212928_refactor_event_substate/up.sql deleted file mode 100644 index 2afcfe78e8..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2024-03-21-212928_refactor_event_substate/up.sql +++ /dev/null @@ -1,2 +0,0 @@ -alter table events - rename column component_address to substate_id; diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2024-04-04-201211_create_scanned_block_ids/down.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2024-04-04-201211_create_scanned_block_ids/down.sql deleted file mode 100644 index d9a93fe9a1..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2024-04-04-201211_create_scanned_block_ids/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2024-04-04-201211_create_scanned_block_ids/up.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2024-04-04-201211_create_scanned_block_ids/up.sql deleted file mode 100644 index 77a058d50f..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2024-04-04-201211_create_scanned_block_ids/up.sql +++ /dev/null @@ -1,16 +0,0 @@ --- Latest scanned blocks, separately by committee (epoch + shard) --- Used mostly for efficient scanning of events in the whole network -create table scanned_block_ids -( - id integer not NULL primary key AUTOINCREMENT, - epoch bigint not NULL, - shard_group integer not null, - last_block_id blob not null -); - - --- There should only be one last scanned block by committee (epoch + shard) -create unique index scanned_block_ids_unique_committee on scanned_block_ids (epoch, shard_group); - --- DB index for faster retrieval of the latest block by committee -create index scanned_block_ids_committee on scanned_block_ids (epoch, shard_group); \ No newline at end of file diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2024-06-18-095000_add_metadata_to_events_and_substates/down.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2024-06-18-095000_add_metadata_to_events_and_substates/down.sql deleted file mode 100644 index d9a93fe9a1..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2024-06-18-095000_add_metadata_to_events_and_substates/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2024-06-18-095000_add_metadata_to_events_and_substates/up.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2024-06-18-095000_add_metadata_to_events_and_substates/up.sql deleted file mode 100644 index 1bc1b64cdd..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2024-06-18-095000_add_metadata_to_events_and_substates/up.sql +++ /dev/null @@ -1,19 +0,0 @@ --- The transaction hash column will be similar to the one in the "events" table -alter table substates - drop column transaction_hash; -alter table substates - add column tx_hash text not NULL; - --- Tempalte address for component substates -alter table substates - add column template_address text NULL; - --- Name of the template module for components -alter table substates - add column module_name text NULL; - --- block timestamp for events and substates -alter table events - add column timestamp bigint not NULL; -alter table substates - add column timestamp bigint not NULL; \ No newline at end of file diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2025-06-25-111041_create_transactions/down.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2025-06-25-111041_create_transactions/down.sql deleted file mode 100644 index d9a93fe9a1..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2025-06-25-111041_create_transactions/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` diff --git a/applications/tari_indexer/src/storage_sqlite/migrations/2025-06-25-111041_create_transactions/up.sql b/applications/tari_indexer/src/storage_sqlite/migrations/2025-06-25-111041_create_transactions/up.sql deleted file mode 100644 index 1bd064636d..0000000000 --- a/applications/tari_indexer/src/storage_sqlite/migrations/2025-06-25-111041_create_transactions/up.sql +++ /dev/null @@ -1,9 +0,0 @@ -create table transactions -( - id integer not NULL primary key AUTOINCREMENT, - transaction_id text not NULL, - body text not null, - created_at timestamp not null default current_timestamp -); - -create unique index transactions_transaction_id_uniq_idx on transactions (transaction_id); \ No newline at end of file diff --git a/applications/tari_indexer/src/storage_sqlite/models/events.rs b/applications/tari_indexer/src/storage_sqlite/models/events.rs index 0d4992a8f8..383760202b 100644 --- a/applications/tari_indexer/src/storage_sqlite/models/events.rs +++ b/applications/tari_indexer/src/storage_sqlite/models/events.rs @@ -23,24 +23,24 @@ use std::{convert::TryFrom, str::FromStr}; -use diesel::sql_types::{Integer, Nullable, Text}; +use diesel::sql_types::{Nullable, Text}; use serde::{Deserialize, Serialize}; use tari_engine_types::substate::SubstateId; +use tari_ootle_storage::time::PrimitiveDateTime; use tari_template_lib::types::Hash; use crate::storage_sqlite::schema::*; #[derive(Debug, Identifiable, Queryable)] #[diesel(table_name = events)] -pub struct Event { +pub struct EventDb { pub id: i32, pub template_address: String, pub tx_hash: String, pub topic: String, pub payload: String, - pub version: i32, pub substate_id: Option, - pub timestamp: i64, + pub created_at: PrimitiveDateTime, } #[derive(Debug, Clone, Insertable, AsChangeset)] @@ -51,18 +51,7 @@ pub struct NewEvent { pub tx_hash: String, pub topic: String, pub payload: String, - pub version: i32, pub substate_id: Option, - pub timestamp: i64, -} - -#[derive(Debug, Clone, Insertable, AsChangeset)] -#[diesel(table_name = event_payloads)] -#[diesel(treat_none_as_null = true)] -pub struct NewEventPayloadField { - pub payload_key: String, - pub payload_value: String, - pub event_id: i32, } #[derive(Clone, Debug, QueryableByName, Deserialize, Serialize)] @@ -75,8 +64,6 @@ pub struct EventData { pub topic: String, #[diesel(sql_type = Text)] pub payload: String, - #[diesel(sql_type = Integer)] - pub version: i32, #[diesel(sql_type = Nullable)] pub substate_id: Option, } diff --git a/applications/tari_indexer/src/storage_sqlite/models/key_value.rs b/applications/tari_indexer/src/storage_sqlite/models/key_value.rs new file mode 100644 index 0000000000..80639e904e --- /dev/null +++ b/applications/tari_indexer/src/storage_sqlite/models/key_value.rs @@ -0,0 +1,58 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use tari_ootle_storage::time::PrimitiveDateTime; + +use crate::storage_sqlite::schema::key_values; + +pub struct KeyValue { + pub _key: String, + pub value: T, + pub _created_at: PrimitiveDateTime, + pub _updated_at: PrimitiveDateTime, +} + +impl From for KeyValue { + fn from(entry: KeyValueEntry) -> Self { + KeyValue { + _key: entry.key, + value: entry.value, + _created_at: entry.created_at, + _updated_at: entry.updated_at, + } + } +} + +#[derive(Debug, Identifiable, Queryable)] +#[diesel(table_name = key_values)] +pub(crate) struct KeyValueEntry { + pub id: i32, + pub key: String, + pub value: String, + pub created_at: PrimitiveDateTime, + pub updated_at: PrimitiveDateTime, +} + +pub enum Key { + /// The network that applies to this database. Used to determine if the network has changed. + /// type: Network + Network, + /// A summary of the sync progress. Used to resume sync after restarts. + /// type: SyncProgress + SyncProgress, +} + +impl Key { + pub fn as_key_str(&self) -> &'static str { + match self { + Self::Network => "network", + Self::SyncProgress => "sync_progress", + } + } +} + +impl AsRef for Key { + fn as_ref(&self) -> &str { + self.as_key_str() + } +} diff --git a/applications/tari_indexer/src/storage_sqlite/models/mod.rs b/applications/tari_indexer/src/storage_sqlite/models/mod.rs index dddd9dc522..31bcf6b5bd 100644 --- a/applications/tari_indexer/src/storage_sqlite/models/mod.rs +++ b/applications/tari_indexer/src/storage_sqlite/models/mod.rs @@ -20,5 +20,12 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -pub mod events; -pub mod substate; +mod events; +mod key_value; +mod substate; +mod utxo; + +pub use events::*; +pub use key_value::*; +pub use substate::*; +pub(crate) use utxo::*; diff --git a/applications/tari_indexer/src/storage_sqlite/models/substate.rs b/applications/tari_indexer/src/storage_sqlite/models/substate.rs index 3a22704c09..7dde7b4b74 100644 --- a/applications/tari_indexer/src/storage_sqlite/models/substate.rs +++ b/applications/tari_indexer/src/storage_sqlite/models/substate.rs @@ -23,8 +23,10 @@ use std::convert::TryFrom; +use tari_ootle_storage::time::PrimitiveDateTime; + use crate::{ - storage_sqlite::{models::substate::Substate as SubstateRow, schema::*}, + storage_sqlite::{models::substate::Substate as SubstateRow, schema::substates}, substate_manager::SubstateResponse, }; @@ -34,11 +36,11 @@ pub struct Substate { pub address: String, pub version: i32, pub data: String, - // TODO: unused - pub tx_hash: String, pub template_address: Option, pub module_name: Option, - pub timestamp: i64, + pub timestamp: PrimitiveDateTime, + pub updated_at: PrimitiveDateTime, + pub created_at: PrimitiveDateTime, } impl TryFrom for SubstateResponse { @@ -59,9 +61,7 @@ pub struct NewSubstate { pub address: String, pub version: i32, pub data: String, - // TODO: unused - pub tx_hash: String, pub template_address: Option, pub module_name: Option, - pub timestamp: i64, + pub timestamp: PrimitiveDateTime, } diff --git a/applications/tari_indexer/src/storage_sqlite/models/utxo.rs b/applications/tari_indexer/src/storage_sqlite/models/utxo.rs new file mode 100644 index 0000000000..49a1e210e6 --- /dev/null +++ b/applications/tari_indexer/src/storage_sqlite/models/utxo.rs @@ -0,0 +1,95 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use std::str::FromStr; + +use diesel::internal::derives::multiconnection::time::PrimitiveDateTime; +use tari_engine_types::{substate::SubstateId, Utxo}; +use tari_indexer_client::types::{UtxoSpent, UtxoUnspent, UtxoUpdate}; +use tari_ootle_common_types::{shard::Shard, StateVersion, VersionedSubstateId}; +use tari_ootle_storage::StorageError; + +use crate::storage_sqlite::{schema::utxos, serialization::deserialize_json}; + +#[derive(AsChangeset, Default)] +#[diesel(table_name = utxos)] +pub(crate) struct UtxoRecordUpdate { + pub version: Option, + pub output: Option>, + pub state_version: Option, + pub is_spent: Option, + pub is_burnt: Option, + pub is_frozen: Option, +} + +#[derive(Insertable)] +#[diesel(table_name = utxos)] +pub(crate) struct UtxoRecordInsert { + pub substate_id: String, + pub version: i32, + pub shard: i32, + pub resource_address: String, + pub state_version: i64, + pub output: Option, + pub utxo_tag_byte: Option, + pub is_spent: bool, + pub is_burnt: bool, + pub is_frozen: bool, +} +#[derive(Queryable)] +#[diesel(table_name = utxos)] +pub(crate) struct UtxoRecord { + #[allow(dead_code)] + pub id: i32, + pub substate_id: String, + pub version: i32, + #[allow(dead_code)] + pub resource_address: String, + pub shard: i32, + pub state_version: i64, + pub output: Option, + #[allow(dead_code)] + pub utxo_tag_byte: Option, + pub is_spent: bool, + #[allow(dead_code)] + pub is_burnt: bool, + pub is_frozen: bool, + #[allow(dead_code)] + pub created_at: PrimitiveDateTime, +} + +impl UtxoRecord { + pub fn try_convert(self) -> Result { + let substate_id = SubstateId::from_str(&self.substate_id).map_err(|e| StorageError::DecodingError { + operation: "UtxoRecord::try_convert", + item: "Utxo", + details: format!("Failed to parse SubstateId from string: {}", e), + })?; + let substate_id = VersionedSubstateId::new(substate_id, self.version as u32); + + let update = if self.is_spent { + UtxoUpdate::Spent(UtxoSpent { + versioned_substate_id: substate_id, + state_version: StateVersion::new(self.state_version as u64), + }) + } else { + UtxoUpdate::Unspent(UtxoUnspent { + versioned_substate_id: substate_id, + shard: Shard::from(self.shard as u32), + state_version: StateVersion::new(self.state_version as u64), + utxo: Utxo { + output: self.output.as_ref().map(deserialize_json).transpose().map_err(|e| { + StorageError::DecodingError { + operation: "UtxoRecord::try_convert", + item: "Utxo", + details: format!("Failed to parse Utxo from string: {}", e), + } + })?, + is_frozen: self.is_frozen, + }, + }) + }; + + Ok(update) + } +} diff --git a/applications/tari_indexer/src/storage_sqlite/schema.rs b/applications/tari_indexer/src/storage_sqlite/schema.rs index 5dea2f67a8..9d96406c0a 100644 --- a/applications/tari_indexer/src/storage_sqlite/schema.rs +++ b/applications/tari_indexer/src/storage_sqlite/schema.rs @@ -1,11 +1,13 @@ // @generated automatically by Diesel CLI. diesel::table! { - event_payloads (id) { + epoch_checkpoints (id) { id -> Integer, - payload_key -> Text, - payload_value -> Text, - event_id -> Integer, + epoch -> BigInt, + shard_group -> Text, + json_data -> Text, + created_at -> Timestamp, + updated_at -> Timestamp, } } @@ -16,9 +18,18 @@ diesel::table! { tx_hash -> Text, topic -> Text, payload -> Text, - version -> Integer, substate_id -> Nullable, - timestamp -> BigInt, + created_at -> Timestamp, + } +} + +diesel::table! { + key_values (id) { + id -> Integer, + key -> Text, + value -> Text, + created_at -> Timestamp, + updated_at -> Timestamp, } } @@ -40,16 +51,32 @@ diesel::table! { } } +diesel::table! { + substate_transitions (id) { + id -> Integer, + shard -> Integer, + state_version -> BigInt, + epoch -> BigInt, + substate_id -> Text, + version -> Integer, + substate_type -> Text, + is_up -> Bool, + value_hash -> Nullable, + created_at -> Timestamp, + } +} + diesel::table! { substates (id) { id -> Integer, address -> Text, version -> Integer, data -> Text, - tx_hash -> Text, template_address -> Nullable, module_name -> Nullable, - timestamp -> BigInt, + timestamp -> Timestamp, + updated_at -> Timestamp, + created_at -> Timestamp, } } @@ -62,13 +89,31 @@ diesel::table! { } } -diesel::joinable!(event_payloads -> events (event_id)); +diesel::table! { + utxos (id) { + id -> Integer, + substate_id -> Text, + version -> Integer, + resource_address -> Text, + shard -> Integer, + state_version -> BigInt, + output -> Nullable, + utxo_tag_byte -> Nullable, + is_spent -> Bool, + is_burnt -> Bool, + is_frozen -> Bool, + created_at -> Timestamp, + } +} diesel::allow_tables_to_appear_in_same_query!( - event_payloads, + epoch_checkpoints, events, + key_values, non_fungible_indexes, scanned_block_ids, + substate_transitions, substates, transactions, + utxos, ); diff --git a/applications/tari_indexer/src/storage_sqlite/serialization.rs b/applications/tari_indexer/src/storage_sqlite/serialization.rs index ca8d492c10..04bfcd8b81 100644 --- a/applications/tari_indexer/src/storage_sqlite/serialization.rs +++ b/applications/tari_indexer/src/storage_sqlite/serialization.rs @@ -14,8 +14,8 @@ pub fn serialize_json(t: &T) -> Result(s: &str) -> Result { - serde_json::from_str(s).map_err(|e| StorageError::DecodingError { +pub fn deserialize_json>(s: S) -> Result { + serde_json::from_str(s.as_ref()).map_err(|e| StorageError::DecodingError { operation: "deserialize_json", item: type_name::(), details: e.to_string(), @@ -25,3 +25,24 @@ pub fn deserialize_json(s: &str) -> Result>(bytes: T) -> String { hex::encode(bytes.as_ref()) } + +fn deserialize_hex(s: &str) -> Result, StorageError> { + hex::decode(s).map_err(|e| StorageError::DecodingError { + operation: "deserialize_hex", + item: "Vec", + details: e.to_string(), + }) +} + +pub fn deserialize_hex_try_from>(s: U) -> Result +where + for<'a> T: TryFrom<&'a [u8]>, + for<'a> >::Error: std::fmt::Display, +{ + let bytes = deserialize_hex(s.as_ref())?; + T::try_from(&bytes).map_err(|e| StorageError::DecodingError { + operation: "deserialize_hex_try_from", + item: type_name::(), + details: e.to_string(), + }) +} diff --git a/applications/tari_indexer/src/storage_sqlite/store_factory.rs b/applications/tari_indexer/src/storage_sqlite/store_factory.rs index 7965839e86..4e18123830 100644 --- a/applications/tari_indexer/src/storage_sqlite/store_factory.rs +++ b/applications/tari_indexer/src/storage_sqlite/store_factory.rs @@ -21,7 +21,8 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use std::{ - collections::BTreeMap, + collections::HashSet, + fmt::Debug, fs::create_dir_all, ops::{Deref, DerefMut}, path::PathBuf, @@ -32,24 +33,34 @@ use std::{ use diesel::{prelude::*, sql_query, SqliteConnection}; use diesel_migrations::{EmbeddedMigrations, MigrationHarness}; use log::*; +use serde::{de::DeserializeOwned, Serialize}; use tari_consensus_types::BlockId; use tari_crypto::tari_utilities::hex::to_hex; -use tari_engine_types::substate::{SubstateId, SubstateValue}; -use tari_indexer_client::types::{ListSubstateItem, TransactionEntry}; +use tari_engine_types::{ + events::Event, + substate::{SubstateId, SubstateValue}, +}; +use tari_indexer_client::types::{ListSubstateItem, TransactionEntry, UtxoUpdate}; use tari_indexer_lib::NonFungibleSubstate; -use tari_ootle_common_types::{substate_type::SubstateType, Epoch, ShardGroup}; -use tari_ootle_storage::{time::PrimitiveDateTime, StorageError}; +use tari_ootle_common_types::{shard::Shard, substate_type::SubstateType, Epoch, ShardGroup, StateVersion}; +use tari_ootle_storage::{ + consensus_models::{EpochCheckpoint, SubstateUpdateProof}, + time::PrimitiveDateTime, + StorageError, +}; use tari_ootle_storage_sqlite::{error::SqliteStorageError, SqliteTransaction}; -use tari_template_lib::{models::ResourceAddress, types::TemplateAddress}; +use tari_template_lib::{ + models::ResourceAddress, + types::{crypto::UtxoTagByte, TemplateAddress}, +}; use tari_transaction::{Transaction, TransactionId}; -use super::models::events::{NewEvent, NewScannedBlockId}; +use super::models::{NewEvent, NewScannedBlockId, UtxoRecordInsert, UtxoRecordUpdate}; use crate::storage_sqlite::{ - models::{ - events::{Event, NewEventPayloadField, ScannedBlockId}, - substate::{NewSubstate, Substate}, - }, - serialization::{deserialize_json, serialize_hex, serialize_json}, + models, + models::{EventDb, KeyValue, NewSubstate, ScannedBlockId, Substate}, + schema, + serialization::{deserialize_hex_try_from, deserialize_json, serialize_hex, serialize_json}, }; const LOG_TARGET: &str = "tari::indexer::storage_sqlite"; @@ -81,25 +92,16 @@ impl SqliteIndexerStore { connection: Arc::new(Mutex::new(connection)), }) } - - pub fn find_by_address(address: String, conn: &mut SqliteConnection) -> Result, StorageError> { - use crate::storage_sqlite::schema::substates; - - let substate_option = substates::table - .filter(substates::address.eq(address)) - .first(&mut *conn) - .optional() - .map_err(|e| StorageError::QueryError { - reason: format!("find_by_address: {}", e), - })?; - - Ok(substate_option) +} +impl Debug for SqliteIndexerStore { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "SqliteIndexerStore {{ connection: ... }}") } } pub trait IndexerStore { type ReadTransaction<'a>: IndexerStoreReadTransaction where Self: 'a; - type WriteTransaction<'a>: IndexerStoreWriteTransaction + Deref> + type WriteTransaction<'a>: IndexerStoreWriteTransaction + Deref> + DerefMut where Self: 'a; fn create_read_tx(&self) -> Result, StorageError>; @@ -182,8 +184,7 @@ pub trait IndexerStoreReadTransaction { topic_filter: Option, offset: u32, limit: u32, - ) -> Result, StorageError>; - fn event_exists(&mut self, event: &NewEvent) -> Result; + ) -> Result, StorageError>; fn get_oldest_scanned_epoch(&mut self) -> Result, StorageError>; fn get_last_scanned_block_id( &mut self, @@ -195,6 +196,19 @@ pub trait IndexerStoreReadTransaction { last_transaction_id: Option, limit: usize, ) -> Result, StorageError>; + + // -------------------------------- KeyValues -------------------------------- // + fn key_value_get_value, T: DeserializeOwned>(&mut self, key: K) -> Result; + fn key_value_get_raw>(&mut self, key: K) -> Result, StorageError>; + + fn get_utxo_updates( + &mut self, + resource_address: ResourceAddress, + shard: Shard, + from_state_version: StateVersion, + filter_tag_bytes: &HashSet, + limit: u32, + ) -> Result, StorageError>; } impl IndexerStoreReadTransaction for SqliteStoreReadTransaction<'_> { @@ -236,9 +250,9 @@ impl IndexerStoreReadTransaction for SqliteStoreReadTransaction<'_> { .into_iter() .map(|s| { let substate_id = SubstateId::from_str(&s.address)?; - let version = u32::try_from(s.version)?; - let template_address = s.template_address.map(|h| TemplateAddress::from_hex(&h)).transpose()?; - let timestamp = u64::try_from(s.timestamp)?; + let version = s.version as u32; + let template_address = s.template_address.map(|h| deserialize_hex_try_from(&h)).transpose()?; + let timestamp = s.timestamp; Ok(ListSubstateItem { substate_id, module_name: s.module_name, @@ -333,7 +347,7 @@ impl IndexerStoreReadTransaction for SqliteStoreReadTransaction<'_> { topic_filter: Option, offset: u32, limit: u32, - ) -> Result, StorageError> { + ) -> Result, StorageError> { // TODO: allow to query by payload as well, unifying all event methods into one info!( target: LOG_TARGET, @@ -361,7 +375,7 @@ impl IndexerStoreReadTransaction for SqliteStoreReadTransaction<'_> { let events = query .order(events::id.desc()) - .get_results::(self.connection()) + .get_results::(self.connection()) .map_err(|e| StorageError::QueryError { reason: format!("get_events: {}", e), })?; @@ -369,29 +383,6 @@ impl IndexerStoreReadTransaction for SqliteStoreReadTransaction<'_> { Ok(events) } - fn event_exists(&mut self, value: &NewEvent) -> Result { - use crate::storage_sqlite::schema::events; - - let count = events::table - .filter( - events::substate_id - .eq(&value.substate_id) - .and(events::template_address.eq(&value.template_address)) - .and(events::topic.eq(&value.topic)) - .and(events::version.eq(&value.version)) - .and(events::payload.eq(&value.payload)) - .and(events::tx_hash.eq(&value.tx_hash)), - ) - .count() - .get_result::(self.connection()) - .map_err(|e| StorageError::QueryError { - reason: format!("event_exists: {}", e), - })?; - let exists = count > 0; - - Ok(exists) - } - fn get_oldest_scanned_epoch(&mut self) -> Result, StorageError> { use crate::storage_sqlite::schema::scanned_block_ids; @@ -480,6 +471,73 @@ impl IndexerStoreReadTransaction for SqliteStoreReadTransaction<'_> { }) .collect() } + + // -------------------------------- KeyValues -------------------------------- // + fn key_value_get_value, T: DeserializeOwned>(&mut self, key: K) -> Result { + let key_value = self.key_value_get_raw(key)?; + deserialize_json(&key_value.value) + } + + fn key_value_get_raw>(&mut self, key: K) -> Result, StorageError> { + const OPERATION: &str = "key_value_get_json"; + use schema::key_values; + + let key_value = key_values::table + .filter(key_values::key.eq(key.as_ref())) + .first::(self.connection()) + .optional() + .map_err(|e| StorageError::general(OPERATION, e))? + .ok_or_else(|| StorageError::NotFound { + item: "key_value", + key: key.as_ref().to_string(), + })?; + + Ok(key_value.into()) + } + + fn get_utxo_updates( + &mut self, + resource_address: ResourceAddress, + shard: Shard, + from_state_version: StateVersion, + filter_tag_bytes: &HashSet, + limit: u32, + ) -> Result, StorageError> { + const OPERATION: &str = "get_utxo_updates"; + use crate::storage_sqlite::schema::utxos; + + let mut query = utxos::table + .filter(utxos::resource_address.eq(resource_address.to_string())) + .filter(utxos::state_version.gt(from_state_version.as_u64() as i64)) + .filter(utxos::shard.eq(shard.as_u32() as i32)) + .into_boxed(); + + if !filter_tag_bytes.is_empty() { + query = query.filter(utxos::utxo_tag_byte.eq_any(filter_tag_bytes.iter().map(|b| i32::from(b.as_byte())))); + } + + let rows = query + .limit(i64::from(limit)) + .order_by(utxos::state_version.asc()) + .load_iter::(self.connection()) + .map_err(|e| StorageError::QueryError { + reason: format!("{OPERATION}: {}", e), + })?; + + // NOTE: I doubt the size hint > 0 + let (lower, upper) = rows.size_hint(); + let size_hint = upper.unwrap_or(lower); + let mut updates = Vec::with_capacity(size_hint); + for row in rows { + let row = row.map_err(|e| StorageError::QueryError { + reason: format!("{OPERATION}: {}", e), + })?; + + updates.push(row.try_convert()?); + } + + Ok(updates) + } } pub struct SqliteStoreWriteTransaction<'a> { @@ -503,15 +561,21 @@ impl<'a> SqliteStoreWriteTransaction<'a> { pub trait IndexerStoreWriteTransaction { fn commit(self) -> Result<(), StorageError>; fn rollback(self) -> Result<(), StorageError>; - fn insert_substate(&mut self, new_substate: NewSubstate) -> Result<(), StorageError>; - #[allow(dead_code)] - fn delete_substate(&mut self, address: String) -> Result<(), StorageError>; - #[allow(dead_code)] - fn clear_substates(&mut self) -> Result<(), StorageError>; - fn save_event(&mut self, new_event: NewEvent) -> Result<(), StorageError>; + fn key_value_set, V: Serialize>(&mut self, key: K, value: V) -> Result<(), StorageError>; + fn batch_insert_substate_transitions>( + &mut self, + shard: Shard, + state_version: StateVersion, + updates: I, + ) -> Result<(), StorageError>; + fn batch_insert_utxo_updates>(&mut self, updates: I) + -> Result<(), StorageError>; + fn upsert_substate(&mut self, new_substate: NewSubstate) -> Result<(), StorageError>; + fn batch_insert_events>(&mut self, events: I) -> Result<(), StorageError>; fn save_scanned_block_id(&mut self, new_scanned_block_id: NewScannedBlockId) -> Result<(), StorageError>; fn delete_scanned_epochs_older_than(&mut self, epoch: Epoch) -> Result<(), StorageError>; fn insert_or_ignore_transaction(&mut self, transaction: &Transaction) -> Result<(), StorageError>; + fn insert_or_ignore_epoch_checkpoint(&mut self, epoch_checkpoint: &EpochCheckpoint) -> Result<(), StorageError>; } impl IndexerStoreWriteTransaction for SqliteStoreWriteTransaction<'_> { @@ -525,19 +589,175 @@ impl IndexerStoreWriteTransaction for SqliteStoreWriteTransaction<'_> { Ok(()) } - fn insert_substate(&mut self, new_substate: NewSubstate) -> Result<(), StorageError> { + fn key_value_set, V: Serialize>(&mut self, key: K, value: V) -> Result<(), StorageError> { + const OPERATION: &str = "key_value_set"; + use schema::key_values; + let json = serialize_json(&value)?; + + diesel::insert_into(key_values::table) + .values((key_values::key.eq(key.as_ref()), key_values::value.eq(&json))) + .on_conflict(key_values::key) + .do_update() + .set(key_values::value.eq(&json)) + .execute(self.connection()) + .map_err(|e| StorageError::general(OPERATION, e))?; + + Ok(()) + } + + fn batch_insert_substate_transitions>( + &mut self, + shard: Shard, + state_version: StateVersion, + updates: I, + ) -> Result<(), StorageError> { + const OPERATION: &str = "batch_insert_substate_transitions"; + use schema::substate_transitions; + + diesel::insert_into(substate_transitions::table) + .values( + updates + .into_iter() + .map(|(epoch, proof)| { + ( + substate_transitions::shard.eq(shard.as_u32() as i32), + substate_transitions::state_version.eq(state_version.as_u64() as i64), + substate_transitions::epoch.eq(epoch.as_u64() as i64), + substate_transitions::substate_id.eq(proof.substate_id().to_string()), + substate_transitions::substate_type.eq(SubstateType::from(proof.substate_id()).to_string()), + substate_transitions::version.eq(proof.version() as i32), + substate_transitions::is_up.eq(proof.is_create()), + substate_transitions::value_hash.eq(proof + .as_create() + .map(|v| serialize_hex(v.substate.value.to_value_hash(proof.version())))), + // substate_transitions::utxo_tag_byte.eq(proof + ) + }) + .collect::>(), + ) + .execute(self.connection()) + .map_err(|e| StorageError::general(OPERATION, e))?; + + Ok(()) + } + + fn batch_insert_utxo_updates>( + &mut self, + updates: I, + ) -> Result<(), StorageError> { + const OPERATION: &str = "batch_insert_utxo_updates"; + use crate::storage_sqlite::schema::utxos; + + fn utxo_exists(connection: &mut SqliteConnection, substate_id: &str) -> Result { + use crate::storage_sqlite::schema::utxos; + + let count = utxos::table + .filter(utxos::substate_id.eq(substate_id)) + .count() + .limit(1) + .get_result::(connection) + .map_err(|e| StorageError::QueryError { + reason: format!("utxo_exists: {}", e), + })?; + Ok(count > 0) + } + + let (inserts, updates) = + updates + .into_iter() + .try_fold((Vec::new(), Vec::new()), |(mut inserts, mut updates), update| { + match update { + UtxoUpdate::Unspent(unspent) => { + let substate_id = unspent.versioned_substate_id.substate_id().to_string(); + if utxo_exists(self.connection(), &substate_id)? { + // If the UTXO already exists, we update it instead of inserting a new one + let update = UtxoRecordUpdate { + version: Some(unspent.versioned_substate_id.version() as i32), + output: Some(unspent.utxo.output().map(serialize_json).transpose()?), + state_version: Some(unspent.state_version.as_u64() as i64), + is_spent: Some(false), + is_burnt: Some(unspent.utxo.is_burnt()), + is_frozen: Some(unspent.utxo.is_frozen()), + }; + updates.push((substate_id, update)); + } else { + inserts.push(UtxoRecordInsert { + substate_id, + version: unspent.versioned_substate_id.version() as i32, + output: unspent.utxo.output().map(serialize_json).transpose()?, + shard: unspent.shard.as_u32() as i32, + resource_address: unspent + .versioned_substate_id + .substate_id() + .as_utxo_address() + .map(|a| a.resource_address().to_string()) + .ok_or_else(|| StorageError::QueryError { + reason: format!( + "[{OPERATION}] Substate ID {} is not a valid UTXO address", + unspent.versioned_substate_id.substate_id() + ), + })?, + state_version: unspent.state_version.as_u64() as i64, + utxo_tag_byte: unspent.utxo.output().map(|o| i32::from(o.tag.as_byte())), + is_spent: false, + is_burnt: unspent.utxo.is_burnt(), + is_frozen: unspent.utxo.is_frozen(), + }); + } + }, + UtxoUpdate::Spent(spent) => { + let update = UtxoRecordUpdate { + version: Some(spent.versioned_substate_id.version() as i32), + // Prune the UTXO data for spent outputs + output: Some(None), + // Update to deleted state version + state_version: Some(spent.state_version.as_u64() as i64), + is_spent: Some(true), + ..Default::default() + }; + updates.push((spent.versioned_substate_id.substate_id().to_string(), update)); + }, + } + + Ok::<_, StorageError>((inserts, updates)) + })?; + + for insert in inserts { + // batch insert results in "cannot start a transaction within a transaction" error + diesel::insert_into(utxos::table) + .values(insert) + .execute(self.connection()) + .map_err(|e| StorageError::general(OPERATION, format!("insert error: {e}")))?; + } + + for (substate_id, update) in updates { + diesel::update(utxos::table.filter(utxos::substate_id.eq(substate_id.to_string()))) + .set(update) + .execute(self.connection()) + .map_err(|e| StorageError::general(OPERATION, format!("update error: {e}")))?; + } + + Ok(()) + } + + fn upsert_substate(&mut self, new_substate: NewSubstate) -> Result<(), StorageError> { use crate::storage_sqlite::schema::substates; let address = &new_substate.address; - let conn = self.connection(); - let current_substate = SqliteIndexerStore::find_by_address(address.clone(), conn)?; + let current_substate = substates::table + .filter(substates::address.eq(address)) + .first::(self.connection()) + .optional() + .map_err(|e| StorageError::QueryError { + reason: format!("find_by_address: {}", e), + })?; match current_substate { Some(_) => { diesel::update(substates::table) .set(&new_substate) .filter(substates::address.eq(address)) - .execute(&mut *conn) + .execute(self.connection()) .map_err(|e| StorageError::QueryError { reason: format!("Update leaf node: {}", e), })?; @@ -549,7 +769,7 @@ impl IndexerStoreWriteTransaction for SqliteStoreWriteTransaction<'_> { None => { diesel::insert_into(substates::table) .values(&new_substate) - .execute(&mut *conn) + .execute(self.connection()) .map_err(|e| StorageError::QueryError { reason: format!("Update substate error: {}", e), })?; @@ -563,75 +783,30 @@ impl IndexerStoreWriteTransaction for SqliteStoreWriteTransaction<'_> { Ok(()) } - fn delete_substate(&mut self, address: String) -> Result<(), StorageError> { - use crate::storage_sqlite::schema::substates; - - diesel::delete(substates::table) - .filter(substates::address.eq(address)) - .execute(&mut *self.connection()) - .map_err(|e| StorageError::QueryError { - reason: format!("delete substate error: {}", e), - })?; - - Ok(()) - } - - fn clear_substates(&mut self) -> Result<(), StorageError> { - use crate::storage_sqlite::schema::substates; - - diesel::delete(substates::table) - .execute(&mut *self.connection()) - .map_err(|e| StorageError::QueryError { - reason: format!("clear_substates error: {}", e), - })?; - - Ok(()) - } + fn batch_insert_events>(&mut self, events: I) -> Result<(), StorageError> { + const OPERATION: &str = "batch_insert_events"; + use crate::storage_sqlite::schema::events; - fn save_event(&mut self, new_event: NewEvent) -> Result<(), StorageError> { - use crate::storage_sqlite::schema::{event_payloads, events}; + let events = events.into_iter().map(|event| { + Ok::<_, StorageError>(NewEvent { + template_address: event.template_address().to_string(), + tx_hash: event.tx_hash().to_string(), + topic: event.topic(), + payload: serialize_json(event.payload())?, + substate_id: event.substate_id().map(|s| s.to_string()), + }) + }); - // Save the event into the database - let event_row: Event = diesel::insert_into(events::table) - .values(&new_event) - .get_result::(self.connection()) - .map_err(|e| StorageError::QueryError { - reason: format!("save_event: {}", e), - })?; + for result in events { + let event = result?; - // Save all the key-value pairs of the payload to be able to query them later - let payload: BTreeMap = - serde_json::from_str(new_event.payload.as_str()).map_err(|e| StorageError::QueryError { - reason: format!("save_event: {}", e), - })?; - let new_payload_fields = payload - .into_iter() - .map(|(key, value)| NewEventPayloadField { - payload_key: key, - payload_value: value, - event_id: event_row.id, - }) - .collect::>(); - // diesel fails if we try to pass all the new rows in a single insert - // so the workaround is to loop over them - // TODO: make diesel work with a single insert instruction instead of looping - for field in new_payload_fields { - diesel::insert_into(event_payloads::table) - .values(&field) + diesel::insert_into(events::table) + .values(event) .execute(self.connection()) .map_err(|e| StorageError::QueryError { - reason: format!("save_event: {}", e), + reason: format!("{OPERATION}: {}", e), })?; } - debug!( - target: LOG_TARGET, - "Added new event to the database with substate_id = {:?}, template_address = {} and for transaction \ - hash = {}, version = {}", - new_event.substate_id, - new_event.template_address, - new_event.tx_hash, - new_event.version, - ); Ok(()) } @@ -686,6 +861,27 @@ impl IndexerStoreWriteTransaction for SqliteStoreWriteTransaction<'_> { Ok(()) } + + fn insert_or_ignore_epoch_checkpoint(&mut self, epoch_checkpoint: &EpochCheckpoint) -> Result<(), StorageError> { + const OPERATION: &str = "insert_or_ignore_epoch_checkpoint"; + use crate::storage_sqlite::schema::epoch_checkpoints; + + diesel::insert_into(epoch_checkpoints::table) + .values(( + epoch_checkpoints::epoch.eq(epoch_checkpoint.epoch().as_u64() as i64), + epoch_checkpoints::shard_group.eq(epoch_checkpoint + .checked_shard_group() + .expect("shard group should be valid") + .to_parsable_string()), + epoch_checkpoints::json_data.eq(serialize_json(epoch_checkpoint)?), + )) + .on_conflict((epoch_checkpoints::epoch, epoch_checkpoints::shard_group)) + .do_nothing() + .execute(self.connection()) + .map_err(|e| StorageError::general(OPERATION, e))?; + + Ok(()) + } } impl<'a> Deref for SqliteStoreWriteTransaction<'a> { diff --git a/applications/tari_indexer/src/substate_manager.rs b/applications/tari_indexer/src/substate_manager.rs index b52c6ecba0..e433b8b345 100644 --- a/applications/tari_indexer/src/substate_manager.rs +++ b/applications/tari_indexer/src/substate_manager.rs @@ -20,17 +20,26 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{convert::TryInto, sync::Arc}; +use std::{collections::HashSet, convert::TryInto}; use serde::{Deserialize, Serialize}; use tari_common_types::types::FixedHash; use tari_engine_types::substate::{SubstateId, SubstateValue}; use tari_epoch_manager::service::EpochManagerHandle; -use tari_indexer_client::types::ListSubstateItem; +use tari_indexer_client::types::{ListSubstateItem, UtxoUpdate}; use tari_indexer_lib::{substate_scanner::SubstateScanner, NonFungibleSubstate}; use tari_ootle_app_utilities::substate_file_cache::SubstateFileCache; -use tari_ootle_common_types::{substate_type::SubstateType, PeerAddress, VersionedSubstateIdRef}; -use tari_template_lib::{models::ResourceAddress, types::TemplateAddress}; +use tari_ootle_common_types::{ + shard::Shard, + substate_type::SubstateType, + PeerAddress, + StateVersion, + VersionedSubstateIdRef, +}; +use tari_template_lib::{ + models::ResourceAddress, + types::{crypto::UtxoTagByte, TemplateAddress}, +}; use tari_validator_node_rpc::client::{SubstateResult, TariValidatorNodeRpcClientFactory}; use crate::storage_sqlite::store_factory::{IndexerStore, IndexerStoreReadTransaction, SqliteIndexerStore}; @@ -48,16 +57,19 @@ pub struct EventResponse { pub created_by_transaction: FixedHash, } +#[derive(Debug, Clone)] pub struct SubstateManager { substate_scanner: - Arc, TariValidatorNodeRpcClientFactory, SubstateFileCache>>, + SubstateScanner, TariValidatorNodeRpcClientFactory, SubstateFileCache>, substate_store: SqliteIndexerStore, } impl SubstateManager { pub fn new( - substate_scanner: Arc< - SubstateScanner, TariValidatorNodeRpcClientFactory, SubstateFileCache>, + substate_scanner: SubstateScanner< + EpochManagerHandle, + TariValidatorNodeRpcClientFactory, + SubstateFileCache, >, substate_store: SqliteIndexerStore, ) -> Self { @@ -67,18 +79,33 @@ impl SubstateManager { } } - pub async fn list_substates( + pub fn get_stored_substates_by_filters( &self, filter_by_type: Option, filter_by_template: Option, limit: Option, offset: Option, ) -> Result, anyhow::Error> { - let mut tx = self.substate_store.create_read_tx()?; - let substates = tx.list_substates(filter_by_type, filter_by_template, limit, offset)?; + let substates = self + .substate_store + .with_read_tx(|tx| tx.list_substates(filter_by_type, filter_by_template, limit, offset))?; Ok(substates) } + pub fn get_utxo_updates( + &self, + resource_address: ResourceAddress, + shard: Shard, + from_state_version: StateVersion, + filter_tag_bytes: &HashSet, + limit: u32, + ) -> Result, anyhow::Error> { + let utxos = self.substate_store.with_read_tx(|tx| { + tx.get_utxo_updates(resource_address, shard, from_state_version, filter_tag_bytes, limit) + })?; + Ok(utxos) + } + pub async fn get_substate( &self, substate_address: &SubstateId, diff --git a/applications/tari_validator_node/src/p2p/rpc/block_sync_task.rs b/applications/tari_validator_node/src/p2p/rpc/block_sync_task.rs index 029fe863c6..c781b2b256 100644 --- a/applications/tari_validator_node/src/p2p/rpc/block_sync_task.rs +++ b/applications/tari_validator_node/src/p2p/rpc/block_sync_task.rs @@ -178,7 +178,7 @@ impl BlockSyncTask { } })?; - let updates = matches!(substates_selection, proto::rpc::StreamSubstateSelection::All) + let updates = matches!(substates_selection, proto::rpc::StreamSubstateSelection::AllSubstates) .then(|| child.get_substate_updates(tx, self.num_preshards)) .transpose()? .unwrap_or_default(); @@ -299,7 +299,7 @@ impl BlockSyncTask { match proto::rpc::StreamSubstateSelection::try_from(req.stream_substates).map_err(|_| ())? { proto::rpc::StreamSubstateSelection::No => {}, - proto::rpc::StreamSubstateSelection::All => { + proto::rpc::StreamSubstateSelection::AllSubstates => { match u32::try_from(updates.len()) { Ok(count) => { self.send(Ok(SyncBlocksResponse { diff --git a/applications/tari_validator_node/src/p2p/rpc/service_impl.rs b/applications/tari_validator_node/src/p2p/rpc/service_impl.rs index 8ad9fed70c..ef999d8611 100644 --- a/applications/tari_validator_node/src/p2p/rpc/service_impl.rs +++ b/applications/tari_validator_node/src/p2p/rpc/service_impl.rs @@ -20,7 +20,10 @@ // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH // DAMAGE. -use std::convert::{TryFrom, TryInto}; +use std::{ + convert::{TryFrom, TryInto}, + num::NonZeroUsize, +}; use log::*; use tari_bor::encode; @@ -39,8 +42,8 @@ use tari_ootle_common_types::{ use tari_ootle_p2p::{ proto, proto::rpc::{ - GetCheckpointRequest, - GetCheckpointResponse, + GetCheckpointsRequest, + GetCheckpointsResponse, GetSubstateRequest, GetSubstateResponse, GetTransactionResultRequest, @@ -56,7 +59,7 @@ use tari_ootle_p2p::{ }, }; use tari_ootle_storage::{ - consensus_models::{Block, EpochCheckpoint, SubstateRecord, TransactionRecord}, + consensus_models::{Block, EpochCheckpoint, SubstateRecord, SubstateValueFilterFlags, TransactionRecord}, StateStore, }; use tari_rpc_framework::{Request, Response, RpcStatus, Streaming}; @@ -327,10 +330,10 @@ impl ValidatorNodeRpcSe Ok(Streaming::new(receiver)) } - async fn get_checkpoint( + async fn get_checkpoints( &self, - request: Request, - ) -> Result, RpcStatus> { + request: Request, + ) -> Result, RpcStatus> { let msg = request.into_message(); if !self .epoch_manager @@ -352,23 +355,37 @@ impl ValidatorNodeRpcSe current_epoch, consensus_epoch ))); } + let from_epoch = msg + .from_epoch + .ok_or_else(|| RpcStatus::bad_request("from_epoch is required"))? + .into(); - if msg.epoch >= consensus_epoch.as_u64() { + if from_epoch >= consensus_epoch { // This may occur if one of the nodes has not fully scanned the base layer return Err(RpcStatus::bad_request(format!( "Peer requested checkpoint with epoch {} but the current epoch is {}", - msg.epoch, consensus_epoch + from_epoch, consensus_epoch ))); } - let checkpoint = self + if msg.num_to_return > 100 { + return Err(RpcStatus::bad_request("num_to_return must be less than 100")); + } + + let limit = NonZeroUsize::new(msg.num_to_return as usize).ok_or_else(|| { + RpcStatus::bad_request(format!( + "Invalid number of checkpoints requested: {}. Must be a integer.", + msg.num_to_return + )) + })?; + + let checkpoints = self .state_store - .with_read_tx(|tx| EpochCheckpoint::get(tx, Epoch(msg.epoch))) - .optional() + .with_read_tx(|tx| EpochCheckpoint::get_all_from_epoch(tx, from_epoch, limit.get())) .map_err(RpcStatus::log_internal_error(LOG_TARGET))?; - Ok(Response::new(GetCheckpointResponse { - checkpoint: checkpoint.map(Into::into), + Ok(Response::new(GetCheckpointsResponse { + checkpoints: checkpoints.into_iter().map(Into::into).collect(), })) } @@ -386,12 +403,22 @@ impl ValidatorNodeRpcSe ))); } - let end_epoch = Some(req.until_epoch).filter(|e| *e > 0).map(Epoch::from); - info!(target: LOG_TARGET, "🌍peer initiated sync with this node (start: v{}, {}) to {}", req.start_state_version, shard, end_epoch.display()); + let end_epoch = req.until_epoch.map(Epoch::from); if req.start_state_version == 0 { return Err(RpcStatus::bad_request("start_state_version must be greater than 0")); } + let value_filter_flags = SubstateValueFilterFlags::from_bits_truncate(req.value_filters); + + info!( + target: LOG_TARGET, + "🌍 peer initiated sync with this node (start: v{}, {}) to {} (values: {:?})", + req.start_state_version, + shard, + end_epoch.display(), + value_filter_flags + ); + task::spawn( StateSyncTask::new( self.state_store.clone(), @@ -402,6 +429,7 @@ impl ValidatorNodeRpcSe STATE_SYNC_MAX_BATCH_SIZE .try_into() .expect("STATE_SYNC_MAX_BATCH_SIZE is not zero"), + value_filter_flags, ) .run(), ); @@ -439,4 +467,34 @@ impl ValidatorNodeRpcSe Ok(Streaming::new(rx)) } + + // async fn get_chain_summary( + // &self, + // _req: Request, + // ) -> Result { + // let current_epoch = self.epoch_manager.get_current_epoch(); + // let committee_into = self + // .epoch_manager + // .get_local_committee_info(current_epoch) + // .await + // .map_err(RpcStatus::log_internal_error(LOG_TARGET))?; + // + // self.state_store + // .with_read_tx(|tx| { + // let mut sharded_state_versions = IndexMap::with_capacity(committee_into.shard_group().len()); + // for shard in committee_into.shard_group().shard_iter() { + // let state_version = tx.state_tree_versions_get_latest(shard)?.unwrap_or_default(); + // sharded_state_versions.insert(shard, state_version); + // } + // + // let leaf = LeafBlock::get(tx, current_epoch)?; + // Ok(GetChainSummaryResponse { + // epoch: Some(current_epoch.into()), + // committee_info: Some(committee_into.into()), + // sharded_state_versions, + // leaf_block: Some(leaf.into()), + // }) + // }) + // .map_err(RpcStatus::log_internal_error(LOG_TARGET)) + // } } diff --git a/applications/tari_validator_node/src/p2p/rpc/state_sync_task.rs b/applications/tari_validator_node/src/p2p/rpc/state_sync_task.rs index 81840715da..a8cae8f172 100644 --- a/applications/tari_validator_node/src/p2p/rpc/state_sync_task.rs +++ b/applications/tari_validator_node/src/p2p/rpc/state_sync_task.rs @@ -5,9 +5,9 @@ use std::num::NonZeroUsize; use log::*; use tari_ootle_common_types::{optional::Optional, shard::Shard, Epoch}; -use tari_ootle_p2p::proto::rpc::SyncStateResponse; +use tari_ootle_p2p::proto::rpc; use tari_ootle_storage::{ - consensus_models::{StateTransition, StateVersionTransitions}, + consensus_models::{StateTransition, StateVersionTransitions, SubstateValueFilterFlags}, StateStore, StorageError, }; @@ -19,21 +19,23 @@ const LOG_TARGET: &str = "tari::ootle::rpc::sync_task"; pub struct StateSyncTask { store: TStateStore, - sender: mpsc::Sender>, + sender: mpsc::Sender>, shard: Shard, start_state_version: Version, end_epoch: Option, batch_size: NonZeroUsize, + value_filters: SubstateValueFilterFlags, } impl StateSyncTask { pub fn new( store: TStateStore, - sender: mpsc::Sender>, + sender: mpsc::Sender>, shard: Shard, start_state_version: Version, end_epoch: Option, batch_size: NonZeroUsize, + value_filters: SubstateValueFilterFlags, ) -> Self { Self { store, @@ -42,6 +44,7 @@ impl StateSyncTask { start_state_version, end_epoch, batch_size, + value_filters, } } @@ -54,7 +57,7 @@ impl StateSyncTask { info!(target: LOG_TARGET, "🌍 Fetched {} state transition(s) up to v{}", transitions.updates.len(), transitions.state_version); if let Some(end_epoch) = self.end_epoch { // TODO(perf): might be better to not load in the first place, however also might incur the cost - // of a db index or loading from db anyway + // of a db index, more complex keys or loading from db anyway if transitions.epoch > end_epoch { info!(target: LOG_TARGET, "🌍 Reached end of requested epoch: {}", end_epoch); return Ok(()); @@ -90,13 +93,12 @@ impl StateSyncTask { current_state_version: Version, ) -> Result, StorageError> { let transitions = self.store.with_read_tx(|tx| { - // TODO: make it optional for the client to request values - StateTransition::get_for_shard(tx, self.shard, current_state_version, true).optional() + StateTransition::get_for_shard(tx, self.shard, current_state_version, self.value_filters).optional() })?; Ok(transitions) } - async fn send(&mut self, result: Result) -> Result<(), ()> { + async fn send(&mut self, result: Result) -> Result<(), ()> { if self.sender.send(result).await.is_err() { debug!( target: LOG_TARGET, @@ -114,7 +116,7 @@ impl StateSyncTask { for (i, chunk) in chunks.into_iter().enumerate() { let updates = chunk.updates.into_iter().map(Into::into).collect(); - self.send(Ok(SyncStateResponse { + self.send(Ok(rpc::SyncStateResponse { state_version: chunk.state_version, updates, has_more: i < num_chunks - 1, diff --git a/applications/tari_validator_node/web_ui/src/routes/VN/Components/Fees.tsx b/applications/tari_validator_node/web_ui/src/routes/VN/Components/Fees.tsx index 079f3e6513..48041cb7c0 100644 --- a/applications/tari_validator_node/web_ui/src/routes/VN/Components/Fees.tsx +++ b/applications/tari_validator_node/web_ui/src/routes/VN/Components/Fees.tsx @@ -21,7 +21,6 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import { useContext, useEffect, useState } from "react"; -import { getFees } from "../../../utils/json_rpc"; import { VNContext } from "../../../App"; import EChartsReact from "echarts-for-react"; @@ -37,31 +36,31 @@ function Fees() { if (epoch !== undefined && identity !== undefined) { // console.log(identity) // TODO: broken - getFees({ epoch_range: { start: 0, end: epoch.current_epoch }, validator_public_key: identity.public_key }).then( - (resp) => { - let min_epoch = epoch.current_epoch; - let max_epoch = 0; - let total_fees: { [epoch: number]: number } = {}; - let fees_due: { [epoch: number]: number } = {}; - for (let fees of resp.fees) { - min_epoch = Math.min(min_epoch, fees.epoch); - max_epoch = Math.max(max_epoch, fees.epoch); - if (!(fees.epoch in total_fees)) { - total_fees[fees.epoch] = fees.total_transaction_fee; - fees_due[fees.epoch] = fees.total_fee_due; - } else { - total_fees[fees.epoch] += fees.total_transaction_fee; - fees_due[fees.epoch] += fees.total_fee_due; - } - } - setMinEpoch(min_epoch); - setMaxEpoch(max_epoch); - setTotalFeesPerEpoch( - Array.from({ length: max_epoch - min_epoch + 1 }, (_, i) => total_fees[i + min_epoch] || 0), - ); - setDueFeesPerEpoch(Array.from({ length: max_epoch - min_epoch + 1 }, (_, i) => fees_due[i + min_epoch] || 0)); - }, - ); + // getFees({ epoch_range: { start: 0, end: epoch.current_epoch }, validator_public_key: identity.public_key }).then( + // (resp) => { + // let min_epoch = epoch.current_epoch; + // let max_epoch = 0; + // let total_fees: { [epoch: number]: number } = {}; + // let fees_due: { [epoch: number]: number } = {}; + // for (let fees of resp.fees) { + // min_epoch = Math.min(min_epoch, fees.epoch); + // max_epoch = Math.max(max_epoch, fees.epoch); + // if (!(fees.epoch in total_fees)) { + // total_fees[fees.epoch] = fees.total_transaction_fee; + // fees_due[fees.epoch] = fees.total_fee_due; + // } else { + // total_fees[fees.epoch] += fees.total_transaction_fee; + // fees_due[fees.epoch] += fees.total_fee_due; + // } + // } + // setMinEpoch(min_epoch); + // setMaxEpoch(max_epoch); + // setTotalFeesPerEpoch( + // Array.from({ length: max_epoch - min_epoch + 1 }, (_, i) => total_fees[i + min_epoch] || 0), + // ); + // setDueFeesPerEpoch(Array.from({ length: max_epoch - min_epoch + 1 }, (_, i) => fees_due[i + min_epoch] || 0)); + // }, + // ); } }, [identity, epoch]); diff --git a/applications/tari_validator_node/web_ui/src/routes/VN/Components/TemplateFunctions.tsx b/applications/tari_validator_node/web_ui/src/routes/VN/Components/TemplateFunctions.tsx index 1401a860f1..54eab48b7e 100644 --- a/applications/tari_validator_node/web_ui/src/routes/VN/Components/TemplateFunctions.tsx +++ b/applications/tari_validator_node/web_ui/src/routes/VN/Components/TemplateFunctions.tsx @@ -33,7 +33,7 @@ import { DataTableCell, BoxHeading, BoxHeading2 } from "../../../Components/Styl import PageHeading from "../../../Components/PageHeading"; import Grid from "@mui/material/Grid"; import { StyledPaper } from "../../../Components/StyledComponents"; -import type { VNArgDef, GetTemplateResponse } from "@tari-project/typescript-bindings"; +import type { GetTemplateResponse } from "@tari-project/typescript-bindings"; function TemplateFunctions() { const { address } = useParams(); @@ -69,7 +69,7 @@ function TemplateFunctions() { {fn.name} {fn.arguments - .map((a: VNArgDef) => { + .map((a) => { return a.name + ":" + a.arg_type; }) .join(", ")} diff --git a/applications/tari_validator_node/web_ui/src/routes/VN/Components/Templates.tsx b/applications/tari_validator_node/web_ui/src/routes/VN/Components/Templates.tsx index 708c2c816d..d12c8f2620 100644 --- a/applications/tari_validator_node/web_ui/src/routes/VN/Components/Templates.tsx +++ b/applications/tari_validator_node/web_ui/src/routes/VN/Components/Templates.tsx @@ -43,12 +43,12 @@ import SearchFilter from "../../../Components/SearchFilter"; import Typography from "@mui/material/Typography"; import Fade from "@mui/material/Fade"; import { emptyRows } from "../../../utils/helpers"; -import type { TemplateMetadata } from "@tari-project/typescript-bindings"; +import type { VNTemplateMetadata } from "@tari-project/typescript-bindings"; -type ColumnKey = keyof TemplateMetadata; +type ColumnKey = keyof VNTemplateMetadata; function Templates() { - const [templates, setTemplates] = useState([]); + const [templates, setTemplates] = useState([]); const [lastSort, setLastSort] = useState({ column: "", order: -1 }); useEffect(() => { @@ -98,7 +98,7 @@ function Templates() { { title: "Template Address", value: "id", - filterFn: (value: string, row: TemplateMetadata) => + filterFn: (value: string, row: VNTemplateMetadata) => row.address.toLowerCase().includes(value.toLowerCase()), }, ]} diff --git a/applications/tari_validator_node/web_ui/src/utils/json_rpc.tsx b/applications/tari_validator_node/web_ui/src/utils/json_rpc.tsx index 58f8fe902a..2a1f3a655f 100644 --- a/applications/tari_validator_node/web_ui/src/utils/json_rpc.tsx +++ b/applications/tari_validator_node/web_ui/src/utils/json_rpc.tsx @@ -45,8 +45,6 @@ import type { GetStateResponse, VNGetSubstateRequest, VNGetSubstateResponse, - GetSubstatesByTransactionRequest, - GetSubstatesByTransactionResponse, GetTemplateRequest, GetTemplateResponse, GetTemplatesRequest, @@ -60,8 +58,6 @@ import type { ListBlocksResponse, VNSubmitTransactionRequest, VNSubmitTransactionResponse, - VNGetValidatorFeesRequest, - VNGetValidatorFeesResponse, } from "@tari-project/typescript-bindings"; @@ -143,8 +139,8 @@ export const getCommittee = (request: GetCommitteeRequest): Promise => jsonRpc("get_all_vns", request); export const getNetworkCommittees = (): Promise => jsonRpc("get_network_committees", {}); -export const getFees = (request: VNGetValidatorFeesRequest): Promise => - jsonRpc("get_fees", request); +// export const getFees = (request: VNGetValidatorFeesRequest): Promise => +// jsonRpc("get_fees", request); // Comms export const addPeer = (request: VNAddPeerRequest) => jsonRpc("add_peer", request); diff --git a/applications/tari_walletd/src/indexer_jrpc_impl.rs b/applications/tari_walletd/src/indexer_jrpc_impl.rs index 3153ce9ff9..846f050e1e 100644 --- a/applications/tari_walletd/src/indexer_jrpc_impl.rs +++ b/applications/tari_walletd/src/indexer_jrpc_impl.rs @@ -13,7 +13,6 @@ use tari_indexer_client::{ GetSubstateRequest, GetTransactionResultRequest, IndexerTransactionFinalizedResult, - ListSubstateItem, ListSubstatesRequest, SubmitTransactionRequest, }, @@ -110,21 +109,12 @@ impl WalletNetworkInterface for IndexerJsonRpcNetworkInterface { let substates = result .substates .into_iter() - .map(|s| { - let ListSubstateItem { - substate_id, - module_name, - version, - template_address, - timestamp, - } = s; - SubstateListItem { - substate_id, - module_name, - version, - template_address, - timestamp, - } + .map(|s| SubstateListItem { + substate_id: s.substate_id, + module_name: s.module_name, + version: s.version, + template_address: s.template_address, + timestamp: s.timestamp, }) .collect(); Ok(SubstateListResult { substates }) diff --git a/applications/tari_walletd/src/services/account_monitor.rs b/applications/tari_walletd/src/services/account_monitor.rs index 1a66120702..addc3f6ff5 100644 --- a/applications/tari_walletd/src/services/account_monitor.rs +++ b/applications/tari_walletd/src/services/account_monitor.rs @@ -649,7 +649,7 @@ where // Update UTXOs let stealth_outputs_api = self.wallet_sdk.stealth_outputs_api(); - let utxos = diff.up_iter().filter(|(id, _)| id.is_utxo_address()).map(|(id, s)| { + let utxos = diff.up_iter().filter(|(id, _)| id.is_utxo()).map(|(id, s)| { let utxo = s .substate_value() .as_utxo() diff --git a/bindings/build.sh b/bindings/build.sh index 6eadffe2ec..81e403828e 100755 --- a/bindings/build.sh +++ b/bindings/build.sh @@ -25,15 +25,6 @@ fi mkdir -p $SOURCE_PATH/$TYPES_DIR cargo test --workspace --exclude integration_tests export_bindings --features ts -echo "Moving ../crates/bindings/src to $SOURCE_PATH/$TYPES_DIR" -npx shx mv ../crates/bindings/src/types/* ./src/types/ -npx shx rm -rf ../crates/bindings/ -echo "Moving ../clients/bindings/src to $SOURCE_PATH/$TYPES_DIR" -npx shx mv ../clients/bindings/src/types/* ./src/types/ -npx shx rm -rf ../clients/bindings/ -echo "Moving ../crates/wallet/bindings/src to $SOURCE_PATH/$TYPES_DIR" -npx shx mv ../crates/wallet/bindings/src/types/* ./src/types/ -npx shx rm -rf ../crates/wallet/bindings/ # Add the license header echo "// Copyright $(date +%Y) The Tari Project" >> $SOURCE_PATH/$MAIN_INDEX_FILE diff --git a/bindings/src/index.ts b/bindings/src/index.ts index 04a8fb6c27..5209a48f9c 100644 --- a/bindings/src/index.ts +++ b/bindings/src/index.ts @@ -98,6 +98,7 @@ export * from "./types/ShardGroupEvidence"; export * from "./types/ShardGroup"; export * from "./types/ShardStateVersions"; export * from "./types/Shard"; +export * from "./types/StateVersion"; export * from "./types/StealthInputsStatement"; export * from "./types/StealthInput"; export * from "./types/StealthOutputsStatement"; diff --git a/bindings/src/tari-indexer-client.ts b/bindings/src/tari-indexer-client.ts index 02d4a6527a..0f946ac1f1 100644 --- a/bindings/src/tari-indexer-client.ts +++ b/bindings/src/tari-indexer-client.ts @@ -3,21 +3,27 @@ export * from "./types/tari-indexer-client/IndexerSubmitTransactionResponse"; export * from "./types/tari-indexer-client/GetTemplateDefinitionRequest"; +export * from "./types/tari-indexer-client/TemplateMetadata"; +export * from "./types/tari-indexer-client/GetUtxoUpdatesRequest"; export * from "./types/tari-indexer-client/ListSubstatesResponse"; export * from "./types/tari-indexer-client/IndexerAddPeerResponse"; export * from "./types/tari-indexer-client/TransactionEntry"; export * from "./types/tari-indexer-client/InspectSubstateRequest"; export * from "./types/tari-indexer-client/ListSubstateItem"; +export * from "./types/tari-indexer-client/UtxoUnspent"; export * from "./types/tari-indexer-client/ListSubstatesRequest"; export * from "./types/tari-indexer-client/IndexerTransactionFinalizedResult"; +export * from "./types/tari-indexer-client/GetUtxoUpdatesResponse"; export * from "./types/tari-indexer-client/IndexerGetSubstateResponse"; export * from "./types/tari-indexer-client/IndexerGetCommsStatsResponse"; export * from "./types/tari-indexer-client/IndexerConnection"; export * from "./types/tari-indexer-client/GetNonFungiblesRequest"; export * from "./types/tari-indexer-client/ListRecentTransactionsResponse"; export * from "./types/tari-indexer-client/IndexerAddPeerRequest"; +export * from "./types/tari-indexer-client/UtxoUpdate"; export * from "./types/tari-indexer-client/GetNonFungiblesResponse"; export * from "./types/tari-indexer-client/GetTemplateDefinitionResponse"; +export * from "./types/tari-indexer-client/UtxoSpent"; export * from "./types/tari-indexer-client/IndexerGetConnectionsResponse"; export * from "./types/tari-indexer-client/IndexerSubmitTransactionRequest"; export * from "./types/tari-indexer-client/ListTemplatesResponse"; diff --git a/bindings/src/types/BlockHeader.ts b/bindings/src/types/BlockHeader.ts index 63f3bc2903..707b426ef5 100644 --- a/bindings/src/types/BlockHeader.ts +++ b/bindings/src/types/BlockHeader.ts @@ -56,8 +56,8 @@ export type BlockHeader = { */ signature: SchnorrSignatureBytes | null; /** - * The time indicating the creation time of the block. Currently, this can be chosen arbitrarily and is only - * informational/used for metrics. + * The Unix Epoch timestamp indicating the creation time of the block. Currently, this can be chosen arbitrarily + * and is only informational/used for metrics. */ timestamp: number; /** diff --git a/bindings/src/types/Event.ts b/bindings/src/types/Event.ts index 683e39294f..4258aabb9e 100644 --- a/bindings/src/types/Event.ts +++ b/bindings/src/types/Event.ts @@ -1,11 +1,12 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Hash } from "./Hash"; import type { Metadata } from "./Metadata"; import type { SubstateId } from "./SubstateId"; export type Event = { substate_id: SubstateId | null; - template_address: string; - tx_hash: string; + template_address: Hash; + tx_hash: Hash; topic: string; payload: Metadata; }; diff --git a/bindings/src/types/validator-node-client/VNArgDef.ts b/bindings/src/types/StateVersion.ts similarity index 65% rename from bindings/src/types/validator-node-client/VNArgDef.ts rename to bindings/src/types/StateVersion.ts index 242a84260e..391d4bdadb 100644 --- a/bindings/src/types/validator-node-client/VNArgDef.ts +++ b/bindings/src/types/StateVersion.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type VNArgDef = { name: string; arg_type: string }; +export type StateVersion = number | bigint; diff --git a/bindings/src/types/tari-indexer-client/GetUtxoUpdatesRequest.ts b/bindings/src/types/tari-indexer-client/GetUtxoUpdatesRequest.ts new file mode 100644 index 0000000000..638298ec15 --- /dev/null +++ b/bindings/src/types/tari-indexer-client/GetUtxoUpdatesRequest.ts @@ -0,0 +1,12 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ResourceAddress } from "../ResourceAddress"; +import type { Shard } from "../Shard"; +import type { StateVersion } from "../StateVersion"; +import type { UtxoTagByte } from "../UtxoTagByte"; + +export type GetUtxoUpdatesRequest = { + shard_state_versions: Array<[Shard, StateVersion]>; + filter_tag_bytes: Array; + resource_address: ResourceAddress; + per_shard_limit: number; +}; diff --git a/bindings/src/types/tari-indexer-client/GetUtxoUpdatesResponse.ts b/bindings/src/types/tari-indexer-client/GetUtxoUpdatesResponse.ts new file mode 100644 index 0000000000..8ee005b6b3 --- /dev/null +++ b/bindings/src/types/tari-indexer-client/GetUtxoUpdatesResponse.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { UtxoUpdate } from "./UtxoUpdate"; + +export type GetUtxoUpdatesResponse = { utxo_updates: Array }; diff --git a/bindings/src/types/tari-indexer-client/ListSubstateItem.ts b/bindings/src/types/tari-indexer-client/ListSubstateItem.ts index 4a2ba72b34..bdaef8cb2b 100644 --- a/bindings/src/types/tari-indexer-client/ListSubstateItem.ts +++ b/bindings/src/types/tari-indexer-client/ListSubstateItem.ts @@ -7,5 +7,5 @@ export type ListSubstateItem = { module_name: string | null; version: number; template_address: Hash | null; - timestamp: bigint; + timestamp: string; }; diff --git a/bindings/src/types/tari-indexer-client/ListTemplatesResponse.ts b/bindings/src/types/tari-indexer-client/ListTemplatesResponse.ts index 78efdb9665..0d24827d5d 100644 --- a/bindings/src/types/tari-indexer-client/ListTemplatesResponse.ts +++ b/bindings/src/types/tari-indexer-client/ListTemplatesResponse.ts @@ -1,4 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { TemplateMetadata } from "../validator-node-client/TemplateMetadata"; +import type { TemplateMetadata } from "./TemplateMetadata"; export type ListTemplatesResponse = { templates: Array }; diff --git a/bindings/src/types/validator-node-client/TemplateMetadata.ts b/bindings/src/types/tari-indexer-client/TemplateMetadata.ts similarity index 89% rename from bindings/src/types/validator-node-client/TemplateMetadata.ts rename to bindings/src/types/tari-indexer-client/TemplateMetadata.ts index 95f6f9d7e9..451fcd3ad1 100644 --- a/bindings/src/types/validator-node-client/TemplateMetadata.ts +++ b/bindings/src/types/tari-indexer-client/TemplateMetadata.ts @@ -7,5 +7,5 @@ export type TemplateMetadata = { /** * SHA hash of binary */ - binary_sha: Array; + binary_sha: string; }; diff --git a/bindings/src/types/tari-indexer-client/UtxoSpent.ts b/bindings/src/types/tari-indexer-client/UtxoSpent.ts new file mode 100644 index 0000000000..e5b99cb737 --- /dev/null +++ b/bindings/src/types/tari-indexer-client/UtxoSpent.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { StateVersion } from "../StateVersion"; +import type { VersionedSubstateId } from "../VersionedSubstateId"; + +export type UtxoSpent = { versioned_substate_id: VersionedSubstateId; state_version: StateVersion }; diff --git a/bindings/src/types/tari-indexer-client/UtxoUnspent.ts b/bindings/src/types/tari-indexer-client/UtxoUnspent.ts new file mode 100644 index 0000000000..a1b2ef6ddf --- /dev/null +++ b/bindings/src/types/tari-indexer-client/UtxoUnspent.ts @@ -0,0 +1,12 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Shard } from "../Shard"; +import type { StateVersion } from "../StateVersion"; +import type { Utxo } from "../Utxo"; +import type { VersionedSubstateId } from "../VersionedSubstateId"; + +export type UtxoUnspent = { + versioned_substate_id: VersionedSubstateId; + shard: Shard; + state_version: StateVersion; + utxo: Utxo; +}; diff --git a/bindings/src/types/tari-indexer-client/UtxoUpdate.ts b/bindings/src/types/tari-indexer-client/UtxoUpdate.ts new file mode 100644 index 0000000000..8dda6381e3 --- /dev/null +++ b/bindings/src/types/tari-indexer-client/UtxoUpdate.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { UtxoSpent } from "./UtxoSpent"; +import type { UtxoUnspent } from "./UtxoUnspent"; + +export type UtxoUpdate = { Unspent: UtxoUnspent } | { Spent: UtxoSpent }; diff --git a/bindings/src/types/validator-node-client/GetTemplateResponse.ts b/bindings/src/types/validator-node-client/GetTemplateResponse.ts index 7767ed5d22..700fe8be74 100644 --- a/bindings/src/types/validator-node-client/GetTemplateResponse.ts +++ b/bindings/src/types/validator-node-client/GetTemplateResponse.ts @@ -1,5 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { TemplateAbi } from "./TemplateAbi"; -import type { TemplateMetadata } from "./TemplateMetadata"; +import type { VNTemplateMetadata } from "./VNTemplateMetadata"; -export type GetTemplateResponse = { registration_metadata: TemplateMetadata; abi: TemplateAbi }; +export type GetTemplateResponse = { registration_metadata: VNTemplateMetadata; abi: TemplateAbi }; diff --git a/bindings/src/types/validator-node-client/GetTemplatesResponse.ts b/bindings/src/types/validator-node-client/GetTemplatesResponse.ts index 49d192cd45..cea9ab233b 100644 --- a/bindings/src/types/validator-node-client/GetTemplatesResponse.ts +++ b/bindings/src/types/validator-node-client/GetTemplatesResponse.ts @@ -1,4 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { TemplateMetadata } from "./TemplateMetadata"; +import type { VNTemplateMetadata } from "./VNTemplateMetadata"; -export type GetTemplatesResponse = { templates: Array }; +export type GetTemplatesResponse = { templates: Array }; diff --git a/bindings/src/types/validator-node-client/VNFunctionDef.ts b/bindings/src/types/validator-node-client/VNFunctionDef.ts index c0a0477d8f..18b2237e24 100644 --- a/bindings/src/types/validator-node-client/VNFunctionDef.ts +++ b/bindings/src/types/validator-node-client/VNFunctionDef.ts @@ -1,4 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { VNArgDef } from "./VNArgDef"; +import type { ArgDef } from "../ArgDef"; -export type VNFunctionDef = { name: string; arguments: Array; output: string; is_mut: boolean }; +export type VNFunctionDef = { name: string; arguments: Array; output: string; is_mut: boolean }; diff --git a/bindings/src/types/validator-node-client/VNTemplateMetadata.ts b/bindings/src/types/validator-node-client/VNTemplateMetadata.ts new file mode 100644 index 0000000000..b45411c2b2 --- /dev/null +++ b/bindings/src/types/validator-node-client/VNTemplateMetadata.ts @@ -0,0 +1,11 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Hash } from "../Hash"; + +export type VNTemplateMetadata = { + name: string; + address: Hash; + /** + * SHA hash of binary + */ + binary_sha: Array; +}; diff --git a/bindings/src/validator-node-client.ts b/bindings/src/validator-node-client.ts index 66d99cff54..929dc000be 100644 --- a/bindings/src/validator-node-client.ts +++ b/bindings/src/validator-node-client.ts @@ -3,7 +3,6 @@ export * from "./types/validator-node-client/ValidatorNodeChange"; export * from "./types/validator-node-client/VNSubmitTransactionRequest"; -export * from "./types/validator-node-client/TemplateMetadata"; export * from "./types/validator-node-client/GetFilteredBlocksCountRequest"; export * from "./types/validator-node-client/VNLogEntry"; export * from "./types/validator-node-client/GetShardKeyRequest"; @@ -40,6 +39,7 @@ export * from "./types/validator-node-client/ListBlocksResponse"; export * from "./types/validator-node-client/GetBlockRequest"; export * from "./types/validator-node-client/VNGetTransactionResultRequest"; export * from "./types/validator-node-client/GetRecentTransactionsRequest"; +export * from "./types/validator-node-client/VNTemplateMetadata"; export * from "./types/validator-node-client/VNLogLevel"; export * from "./types/validator-node-client/GetRecentTransactionsResponse"; export * from "./types/validator-node-client/VNAddPeerResponse"; @@ -55,7 +55,6 @@ export * from "./types/validator-node-client/TemplateAbi"; export * from "./types/validator-node-client/GetTemplatesRequest"; export * from "./types/validator-node-client/VNGetSubstateResponse"; export * from "./types/validator-node-client/VNGetAllVnsResponse"; -export * from "./types/validator-node-client/VNArgDef"; export * from "./types/validator-node-client/GetEpochManagerStatsResponse"; export * from "./types/validator-node-client/GetBlockResponse"; export * from "./types/validator-node-client/VNCommitteeShardInfo"; diff --git a/clients/base_node_client/src/types.rs b/clients/base_node_client/src/types.rs index 154a019809..ba3b3b4f2b 100644 --- a/clients/base_node_client/src/types.rs +++ b/clients/base_node_client/src/types.rs @@ -27,11 +27,7 @@ pub struct BlockInfo { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/base-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "base-node-client/"))] pub struct BaseLayerValidatorNode { pub public_key: RistrettoPublicKeyBytes, pub shard_key: SubstateAddress, diff --git a/clients/tari_indexer_client/Cargo.toml b/clients/tari_indexer_client/Cargo.toml index 67a4d3c3e5..76a21654ee 100644 --- a/clients/tari_indexer_client/Cargo.toml +++ b/clients/tari_indexer_client/Cargo.toml @@ -17,13 +17,16 @@ tari_template_abi = { workspace = true } tari_template_lib_types = { workspace = true } tari_consensus_types = { workspace = true } -anyhow = { workspace = true } -reqwest = { workspace = true, features = ["json"] } +anyhow = { workspace = true, optional = true } +reqwest = { workspace = true, features = ["json"], optional = true } multiaddr = { workspace = true } serde = { workspace = true, default-features = true } serde_json = { workspace = true } -thiserror = { workspace = true } +serde_with = { workspace = true } +thiserror = { workspace = true, optional = true } ts-rs = { workspace = true, optional = true } [features] -ts = ["ts-rs"] +default = ["client"] +ts = ["ts-rs", "tari_ootle_common_types/ts", "tari_engine_types/ts", "tari_template_abi/ts", "tari_template_lib_types/ts", "tari_consensus_types/ts", "tari_transaction/ts"] +client = ["dep:reqwest", "dep:anyhow", "dep:thiserror"] diff --git a/clients/tari_indexer_client/src/lib.rs b/clients/tari_indexer_client/src/lib.rs index 7b2de6999c..d53a09ae49 100644 --- a/clients/tari_indexer_client/src/lib.rs +++ b/clients/tari_indexer_client/src/lib.rs @@ -20,7 +20,10 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#[cfg(feature = "client")] pub mod error; +#[cfg(feature = "client")] pub mod graphql_client; +#[cfg(feature = "client")] pub mod json_rpc_client; pub mod types; diff --git a/clients/tari_indexer_client/src/types.rs b/clients/tari_indexer_client/src/types.rs index 23666a2d5a..cec95b3d0e 100644 --- a/clients/tari_indexer_client/src/types.rs +++ b/clients/tari_indexer_client/src/types.rs @@ -1,29 +1,33 @@ // Copyright 2023 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use std::time::Duration; +use std::{ + collections::{HashMap, HashSet}, + time::Duration, +}; use multiaddr::Multiaddr; use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, Seq}; use tari_common_types::types::FixedHash; use tari_consensus_types::Decision; use tari_engine_types::{ commit_result::ExecuteResult, substate::{SubstateId, SubstateValue}, template_lib_models::{NonFungibleAddress, ResourceAddress}, + Utxo, }; -use tari_ootle_common_types::{substate_type::SubstateType, Epoch}; +use tari_ootle_common_types::{shard::Shard, substate_type::SubstateType, Epoch, StateVersion, VersionedSubstateId}; use tari_ootle_storage::time::PrimitiveDateTime; use tari_template_abi::TemplateDef; -use tari_template_lib_types::{crypto::RistrettoPublicKeyBytes, TemplateAddress}; +use tari_template_lib_types::{ + crypto::{RistrettoPublicKeyBytes, UtxoTagByte}, + TemplateAddress, +}; use tari_transaction::{Transaction, TransactionId}; #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct ListSubstatesRequest { pub filter_by_template: Option, pub filter_by_type: Option, @@ -32,38 +36,27 @@ pub struct ListSubstatesRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct ListSubstatesResponse { pub substates: Vec, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct ListSubstateItem { pub substate_id: SubstateId, pub module_name: Option, pub version: u32, pub template_address: Option, - pub timestamp: u64, + #[cfg_attr(feature = "ts", ts(type = "string"))] + pub timestamp: PrimitiveDateTime, } #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/tari-indexer-client/", - rename = "IndexerGetSubstateRequest" - ) + ts(export, export_to = "tari-indexer-client/", rename = "IndexerGetSubstateRequest") )] pub struct GetSubstateRequest { #[cfg_attr(feature = "ts", ts(type = "string"))] @@ -77,11 +70,7 @@ pub struct GetSubstateRequest { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/tari-indexer-client/", - rename = "IndexerGetSubstateResponse" - ) + ts(export, export_to = "tari-indexer-client/", rename = "IndexerGetSubstateResponse") )] pub struct GetSubstateResponse { pub address: SubstateId, @@ -90,11 +79,7 @@ pub struct GetSubstateResponse { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct InspectSubstateRequest { #[cfg_attr(feature = "ts", ts(type = "string"))] pub address: SubstateId, @@ -102,11 +87,7 @@ pub struct InspectSubstateRequest { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct InspectSubstateResponse { pub address: SubstateId, pub version: u32, @@ -119,7 +100,7 @@ pub struct InspectSubstateResponse { derive(ts_rs::TS), ts( export, - export_to = "../../bindings/src/types/tari-indexer-client/", + export_to = "tari-indexer-client/", rename = "IndexerSubmitTransactionRequest" ) )] @@ -134,7 +115,7 @@ pub struct SubmitTransactionRequest { derive(ts_rs::TS), ts( export, - export_to = "../../bindings/src/types/tari-indexer-client/", + export_to = "tari-indexer-client/", rename = "IndexerSubmitTransactionResponse" ) )] @@ -144,31 +125,19 @@ pub struct SubmitTransactionResponse { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct ListTemplatesRequest { pub limit: u32, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct ListTemplatesResponse { pub templates: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct TemplateMetadata { pub name: String, pub address: TemplateAddress, @@ -182,7 +151,7 @@ pub struct TemplateMetadata { derive(ts_rs::TS), ts( export, - export_to = "../../bindings/src/types/tari-indexer-client/", + export_to = "tari-indexer-client/", rename = "IndexerGetTransactionResultRequest" ) )] @@ -196,7 +165,7 @@ pub struct GetTransactionResultRequest { derive(ts_rs::TS), ts( export, - export_to = "../../bindings/src/types/tari-indexer-client/", + export_to = "tari-indexer-client/", rename = "IndexerGetTransactionResultResponse" ) )] @@ -205,11 +174,7 @@ pub struct GetTransactionResultResponse { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct ListRecentTransactionsRequest { pub limit: Option, #[serde(default)] @@ -217,21 +182,13 @@ pub struct ListRecentTransactionsRequest { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct ListRecentTransactionsResponse { pub transactions: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct TransactionEntry { pub transaction_id: TransactionId, pub transaction: Transaction, @@ -240,11 +197,7 @@ pub struct TransactionEntry { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub enum IndexerTransactionFinalizedResult { Pending, Finalized { @@ -262,11 +215,7 @@ pub enum IndexerTransactionFinalizedResult { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/tari-indexer-client/", - rename = "IndexerGetIdentityResponse" - ) + ts(export, export_to = "tari-indexer-client/", rename = "IndexerGetIdentityResponse") )] pub struct GetIdentityResponse { pub peer_id: String, @@ -276,11 +225,7 @@ pub struct GetIdentityResponse { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct GetNonFungiblesRequest { pub address: ResourceAddress, #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -290,21 +235,13 @@ pub struct GetNonFungiblesRequest { } #[derive(Debug, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct GetNonFungiblesResponse { pub non_fungibles: Vec, } #[derive(Debug, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct NonFungibleSubstate { pub address: NonFungibleAddress, pub version: u32, @@ -315,11 +252,7 @@ pub struct NonFungibleSubstate { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/tari-indexer-client/", - rename = "IndexerAddPeerRequest" - ) + ts(export, export_to = "tari-indexer-client/", rename = "IndexerAddPeerRequest") )] pub struct AddPeerRequest { pub public_key: RistrettoPublicKeyBytes, @@ -332,11 +265,7 @@ pub struct AddPeerRequest { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/tari-indexer-client/", - rename = "IndexerAddPeerResponse" - ) + ts(export, export_to = "tari-indexer-client/", rename = "IndexerAddPeerResponse") )] pub struct AddPeerResponse {} @@ -344,11 +273,7 @@ pub struct AddPeerResponse {} #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/tari-indexer-client/", - rename = "IndexerGetCommsStatsResponse" - ) + ts(export, export_to = "tari-indexer-client/", rename = "IndexerGetCommsStatsResponse") )] pub struct GetCommsStatsResponse { pub connection_status: String, @@ -360,7 +285,7 @@ pub struct GetCommsStatsResponse { derive(ts_rs::TS), ts( export, - export_to = "../../bindings/src/types/tari-indexer-client/", + export_to = "tari-indexer-client/", rename = "IndexerGetEpochManagerStatsResponse" ) )] @@ -376,11 +301,7 @@ pub struct GetEpochManagerStatsResponse { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/tari-indexer-client/", - rename = "IndexerConnection" - ) + ts(export, export_to = "tari-indexer-client/", rename = "IndexerConnection") )] pub struct Connection { pub connection_id: String, @@ -399,11 +320,7 @@ pub struct Connection { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/tari-indexer-client/", - rename = "IndexerConnectionDirection" - ) + ts(export, export_to = "tari-indexer-client/", rename = "IndexerConnectionDirection") )] pub enum ConnectionDirection { Inbound, @@ -414,41 +331,66 @@ pub enum ConnectionDirection { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/tari-indexer-client/", - rename = "IndexerGetConnectionsResponse" - ) + ts(export, export_to = "tari-indexer-client/", rename = "IndexerGetConnectionsResponse") )] pub struct GetConnectionsResponse { pub connections: Vec, } #[derive(Debug, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct GetTemplateDefinitionRequest { pub template_address: TemplateAddress, } #[derive(Debug, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct GetTemplateDefinitionResponse { pub name: String, pub definition: TemplateDef, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/tari-indexer-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] pub struct IndexerReadyResponse {} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] +pub struct GetUtxoUpdatesRequest { + #[cfg_attr(feature = "ts", ts(as = "Vec<(Shard, StateVersion)>"))] + #[serde_as(as = "Seq<(_, _)>")] + pub shard_state_versions: HashMap, + pub filter_tag_bytes: HashSet, + pub resource_address: ResourceAddress, + pub per_shard_limit: u32, +} + +#[derive(Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] +pub struct GetUtxoUpdatesResponse { + pub utxo_updates: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] +pub enum UtxoUpdate { + Unspent(UtxoUnspent), + Spent(UtxoSpent), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] +pub struct UtxoUnspent { + pub versioned_substate_id: VersionedSubstateId, + pub shard: Shard, + pub state_version: StateVersion, + pub utxo: Utxo, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "tari-indexer-client/"))] +pub struct UtxoSpent { + pub versioned_substate_id: VersionedSubstateId, + pub state_version: StateVersion, +} diff --git a/clients/validator_node_client/Cargo.toml b/clients/validator_node_client/Cargo.toml index b891b1ee12..7c419cbac3 100644 --- a/clients/validator_node_client/Cargo.toml +++ b/clients/validator_node_client/Cargo.toml @@ -17,6 +17,7 @@ tari_ootle_storage = { workspace = true } tari_sidechain = { workspace = true } tari_template_lib_types = { workspace = true } tari_consensus_types = { workspace = true } +tari_template_abi = { workspace = true } reqwest = { workspace = true, features = ["json"] } multiaddr = { workspace = true } diff --git a/clients/validator_node_client/src/types.rs b/clients/validator_node_client/src/types.rs index 8a81175313..f986822f8f 100644 --- a/clients/validator_node_client/src/types.rs +++ b/clients/validator_node_client/src/types.rs @@ -47,6 +47,7 @@ use tari_ootle_storage::{ Ordering, }; use tari_sidechain::QuorumDecision; +use tari_template_abi::ArgDef; use tari_template_lib_types::{crypto::RistrettoPublicKeyBytes, TemplateAddress}; use tari_transaction::{Transaction, TransactionId}; @@ -54,11 +55,7 @@ use tari_transaction::{Transaction, TransactionId}; #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNGetIdentityResponse" - ) + ts(export, export_to = "validator-node-client/", rename = "VNGetIdentityResponse") )] pub struct GetIdentityResponse { pub peer_id: String, @@ -71,32 +68,20 @@ pub struct GetIdentityResponse { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetTemplateRequest { pub template_address: TemplateAddress, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetTemplateResponse { pub registration_metadata: TemplateMetadata, pub abi: TemplateAbi, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct TemplateAbi { pub template_name: String, pub functions: Vec, @@ -107,11 +92,7 @@ pub struct TemplateAbi { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNFunctionDef" - ) + ts(export, export_to = "validator-node-client/", rename = "VNFunctionDef") )] pub struct FunctionDef { pub name: String, @@ -121,37 +102,14 @@ pub struct FunctionDef { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNArgDef" - ) -)] -pub struct ArgDef { - pub name: String, - pub arg_type: String, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetTemplatesRequest { #[cfg_attr(feature = "ts", ts(type = "number"))] pub limit: u64, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetTemplatesResponse { pub templates: Vec, } @@ -160,7 +118,7 @@ pub struct GetTemplatesResponse { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") + ts(export, export_to = "validator-node-client/", rename = "VNTemplateMetadata") )] pub struct TemplateMetadata { pub name: String, @@ -174,11 +132,7 @@ pub struct TemplateMetadata { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNSubmitTransactionRequest" - ) + ts(export, export_to = "validator-node-client/", rename = "VNSubmitTransactionRequest") )] pub struct SubmitTransactionRequest { pub transaction: Transaction, @@ -189,11 +143,7 @@ pub struct SubmitTransactionRequest { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNSubmitTransactionResponse" - ) + ts(export, export_to = "validator-node-client/", rename = "VNSubmitTransactionResponse") )] pub struct SubmitTransactionResponse { pub transaction_id: TransactionId, @@ -202,11 +152,7 @@ pub struct SubmitTransactionResponse { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct DryRunTransactionFinalizeResult { #[cfg_attr(feature = "ts", ts(type = "string"))] pub decision: QuorumDecision, @@ -218,11 +164,7 @@ pub struct DryRunTransactionFinalizeResult { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNGetAllVnsRequest" - ) + ts(export, export_to = "validator-node-client/", rename = "VNGetAllVnsRequest") )] pub struct GetAllVnsRequest { pub epoch: Epoch, @@ -232,43 +174,27 @@ pub struct GetAllVnsRequest { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNGetAllVnsResponse" - ) + ts(export, export_to = "validator-node-client/", rename = "VNGetAllVnsResponse") )] pub struct GetAllVnsResponse { pub vns: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetBaseLayerEpochChangesRequest { pub start_epoch: Epoch, pub end_epoch: Epoch, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetBaseLayerEpochChangesResponse { pub changes: Vec<(Epoch, Vec)>, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetConsensusStatusResponse { pub epoch: Epoch, pub height: NodeHeight, @@ -276,11 +202,7 @@ pub struct GetConsensusStatusResponse { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] /// Represents a validator node state change pub enum ValidatorNodeChange { Add { @@ -295,21 +217,13 @@ pub enum ValidatorNodeChange { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetTransactionRequest { pub transaction_id: TransactionId, } #[derive(Debug, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetTransactionResponse { pub transaction: Transaction, } @@ -320,7 +234,7 @@ pub struct GetTransactionResponse { derive(ts_rs::TS), ts( export, - export_to = "../../bindings/src/types/validator-node-client/", + export_to = "validator-node-client/", rename = "VNGetTransactionResultRequest" ) )] @@ -334,7 +248,7 @@ pub struct GetTransactionResultRequest { derive(ts_rs::TS), ts( export, - export_to = "../../bindings/src/types/validator-node-client/", + export_to = "validator-node-client/", rename = "VNGetTransactionResultResponse" ) )] @@ -346,29 +260,17 @@ pub struct GetTransactionResultResponse { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetRecentTransactionsRequest {} #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetRecentTransactionsResponse { pub transactions: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct ListBlocksRequest { /// If provided, `limit` blocks from the specified block back will be returned. Otherwise `limit` blocks from the /// leaf block will be provided. @@ -378,51 +280,31 @@ pub struct ListBlocksRequest { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct ListBlocksResponse { pub blocks: Vec, } #[derive(Debug, Clone, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetTxPoolResponse { pub tx_pool: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetBlockResponse { pub block: Block, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetBlocksResponse { pub blocks: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetBlocksCountResponse { #[cfg_attr(feature = "ts", ts(type = "number"))] pub count: u64, @@ -432,11 +314,7 @@ pub struct GetBlocksCountResponse { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNLogEntry" - ) + ts(export, export_to = "validator-node-client/", rename = "VNLogEntry") )] pub struct LogEntry { #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -449,11 +327,7 @@ pub struct LogEntry { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNLogLevel" - ) + ts(export, export_to = "validator-node-client/", rename = "VNLogLevel") )] pub enum LogLevel { Error, @@ -463,32 +337,20 @@ pub enum LogLevel { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetCommitteeRequest { pub epoch: Epoch, pub substate_address: SubstateAddress, } #[derive(Debug, Clone, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetCommitteeResponse { pub committee: Committee, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetNetworkCommitteeResponse { pub current_epoch: Epoch, pub committees: Vec, @@ -498,11 +360,7 @@ pub struct GetNetworkCommitteeResponse { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNCommitteeShardInfo" - ) + ts(export, export_to = "validator-node-client/", rename = "VNCommitteeShardInfo") )] pub struct CommitteeShardInfo { #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -512,11 +370,7 @@ pub struct CommitteeShardInfo { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct ValidatorNode { #[cfg_attr(feature = "ts", ts(type = "string"))] pub address: PeerAddress, @@ -539,42 +393,26 @@ impl From> for ValidatorNode { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetShardKeyRequest { pub epoch: Epoch, pub public_key: RistrettoPublicKeyBytes, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetShardKeyResponse { pub shard_key: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetStateRequest { pub address: SubstateAddress, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetStateResponse { pub data: Vec, } @@ -583,11 +421,7 @@ pub struct GetStateResponse { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNGetSubstateRequest" - ) + ts(export, export_to = "validator-node-client/", rename = "VNGetSubstateRequest") )] pub struct GetSubstateRequest { pub address: SubstateId, @@ -598,11 +432,7 @@ pub struct GetSubstateRequest { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNGetSubstateResponse" - ) + ts(export, export_to = "validator-node-client/", rename = "VNGetSubstateResponse") )] pub struct GetSubstateResponse { pub value: Option, @@ -610,11 +440,7 @@ pub struct GetSubstateResponse { } #[derive(Debug, Clone, Copy, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub enum SubstateStatus { Up, Down, @@ -625,11 +451,7 @@ pub enum SubstateStatus { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNAddPeerRequest" - ) + ts(export, export_to = "validator-node-client/", rename = "VNAddPeerRequest") )] pub struct AddPeerRequest { #[cfg_attr(feature = "ts", ts(type = "string"))] @@ -643,11 +465,7 @@ pub struct AddPeerRequest { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNAddPeerResponse" - ) + ts(export, export_to = "validator-node-client/", rename = "VNAddPeerResponse") )] pub struct AddPeerResponse {} @@ -655,22 +473,14 @@ pub struct AddPeerResponse {} #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNGetCommsStatsResponse" - ) + ts(export, export_to = "validator-node-client/", rename = "VNGetCommsStatsResponse") )] pub struct GetCommsStatsResponse { pub connection_status: String, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetEpochManagerStatsResponse { pub current_epoch: Epoch, #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -684,22 +494,14 @@ pub struct GetEpochManagerStatsResponse { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetBlockRequest { #[cfg_attr(feature = "ts", ts(type = "string"))] pub block_id: BlockId, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetBlocksRequest { #[cfg_attr(feature = "ts", ts(type = "number"))] pub limit: u64, @@ -712,11 +514,7 @@ pub struct GetBlocksRequest { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetFilteredBlocksCountRequest { pub filter_index: Option, pub filter: Option, @@ -726,11 +524,7 @@ pub struct GetFilteredBlocksCountRequest { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNConnection" - ) + ts(export, export_to = "validator-node-client/", rename = "VNConnection") )] pub struct Connection { pub connection_id: String, @@ -749,11 +543,7 @@ pub struct Connection { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNConnectionDirection" - ) + ts(export, export_to = "validator-node-client/", rename = "VNConnectionDirection") )] pub enum ConnectionDirection { Inbound, @@ -764,52 +554,32 @@ pub enum ConnectionDirection { #[cfg_attr( feature = "ts", derive(ts_rs::TS), - ts( - export, - export_to = "../../bindings/src/types/validator-node-client/", - rename = "VNGetConnectionsResponse" - ) + ts(export, export_to = "validator-node-client/", rename = "VNGetConnectionsResponse") )] pub struct GetConnectionsResponse { pub connections: Vec, } #[derive(Serialize, Debug)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct GetMempoolStatsResponse { pub size: usize, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct PrepareLayerOneTransactionRequest { pub params: LayerOneTransactionParams, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub enum LayerOneTransactionParams { Registration, Exit, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/validator-node-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "validator-node-client/"))] pub struct PrepareLayerOneTransactionResponse { pub path: PathBuf, } diff --git a/clients/wallet_daemon_client/src/component_address.rs b/clients/wallet_daemon_client/src/component_address.rs index bc1f77203b..91197b6ab6 100644 --- a/clients/wallet_daemon_client/src/component_address.rs +++ b/clients/wallet_daemon_client/src/component_address.rs @@ -11,11 +11,7 @@ use serde::{Deserialize, Serialize}; use tari_template_lib::models::ComponentAddress; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub enum ComponentAddressOrName { ComponentAddress(ComponentAddress), Name(String), diff --git a/clients/wallet_daemon_client/src/permissions.rs b/clients/wallet_daemon_client/src/permissions.rs index 011ee9bd37..4739e16d87 100644 --- a/clients/wallet_daemon_client/src/permissions.rs +++ b/clients/wallet_daemon_client/src/permissions.rs @@ -12,11 +12,7 @@ use tari_engine_types::substate::SubstateId; use tari_template_lib::models::{ComponentAddress, ResourceAddress}; #[derive(Debug, Clone, Deserialize, Serialize, Hash, Eq, PartialEq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum JrpcPermission { AccountInfo, NftGetOwnershipProof(Option), @@ -98,11 +94,7 @@ impl Display for JrpcPermission { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct JrpcPermissions(HashSet); impl FromStr for JrpcPermissions { @@ -145,11 +137,7 @@ impl TryFrom<&[String]> for JrpcPermissions { } #[derive(Debug, Serialize, Deserialize, Clone)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Claims { #[cfg_attr(feature = "ts", ts(type = "number"))] pub id: u64, diff --git a/clients/wallet_daemon_client/src/types.rs b/clients/wallet_daemon_client/src/types.rs index 094e63dcef..22145c59ea 100644 --- a/clients/wallet_daemon_client/src/types.rs +++ b/clients/wallet_daemon_client/src/types.rs @@ -68,11 +68,7 @@ use crate::{ }; #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct CallInstructionRequest { pub instructions: Vec, #[serde(deserialize_with = "string_or_struct")] @@ -99,11 +95,7 @@ pub struct CallInstructionRequest { } #[derive(Debug, Clone, Default, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionSubmitRequest { pub transaction: UnsignedTransaction, #[cfg_attr(feature = "ts", ts(type = "number | null"))] @@ -125,21 +117,13 @@ const fn return_true() -> bool { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionSubmitResponse { pub transaction_id: TransactionId, } #[derive(Debug, Clone, Default, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionSubmitDryRunRequest { pub transaction: UnsignedTransaction, #[cfg_attr(feature = "ts", ts(type = "number | null"))] @@ -151,22 +135,14 @@ pub struct TransactionSubmitDryRunRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionSubmitDryRunResponse { pub transaction_id: TransactionId, pub result: ExecuteResult, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionSubmitManifestRequest { pub manifest: String, pub variables: HashMap, @@ -178,22 +154,14 @@ pub struct TransactionSubmitManifestRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionSubmitManifestResponse { pub transaction_id: TransactionId, pub result: Option, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct PublishTemplateRequest { #[cfg_attr(feature = "ts", ts(type = "string"))] #[serde(with = "serde_with::base64")] @@ -209,11 +177,7 @@ pub struct PublishTemplateRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct PublishTemplateResponse { pub transaction_id: TransactionId, #[cfg_attr(feature = "ts", ts(type = "number | null"))] @@ -221,21 +185,13 @@ pub struct PublishTemplateResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionGetRequest { pub transaction_id: TransactionId, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionGetResponse { pub transaction: Transaction, pub result: Option, @@ -245,42 +201,26 @@ pub struct TransactionGetResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionGetAllRequest { pub status: Option, pub component: Option, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionGetAllResponse { pub transactions: Vec, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionGetResultRequest { pub transaction_id: TransactionId, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionGetResultResponse { pub transaction_id: TransactionId, pub status: TransactionStatus, @@ -288,11 +228,7 @@ pub struct TransactionGetResultResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionWaitResultRequest { pub transaction_id: TransactionId, #[cfg_attr(feature = "ts", ts(type = "number | null"))] @@ -300,11 +236,7 @@ pub struct TransactionWaitResultRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionWaitResultResponse { pub transaction_id: TransactionId, pub result: Option, @@ -315,11 +247,7 @@ pub struct TransactionWaitResultResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransactionClaimBurnResponse { pub transaction_id: TransactionId, pub inputs: Vec, @@ -327,21 +255,13 @@ pub struct TransactionClaimBurnResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct KeysListRequest { pub branch: KeyBranch, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct KeysListResponse { /// (index, public key, is_active) #[cfg_attr(feature = "ts", ts(type = "Array<[number, string, boolean]>"))] @@ -349,32 +269,20 @@ pub struct KeysListResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct KeysSetActiveRequest { #[cfg_attr(feature = "ts", ts(type = "number"))] pub index: u64, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct KeysSetActiveResponse { pub public_key: RistrettoPublicKeyBytes, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct KeysCreateRequest { pub branch: KeyBranch, #[cfg_attr(feature = "ts", ts(type = "number | null"))] @@ -382,11 +290,7 @@ pub struct KeysCreateRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct KeysCreateResponse { #[cfg_attr(feature = "ts", ts(type = "number"))] pub id: u64, @@ -395,11 +299,7 @@ pub struct KeysCreateResponse { } #[derive(Debug, Clone, Default, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountsCreateRequest { pub account_name: Option, pub is_default: Option, @@ -408,11 +308,7 @@ pub struct AccountsCreateRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountsCreateResponse { pub account: Account, #[cfg_attr(feature = "ts", ts(type = "string"))] @@ -420,11 +316,7 @@ pub struct AccountsCreateResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountsCreateOrGetRequest { pub account: Option, pub is_default: Option, @@ -433,11 +325,7 @@ pub struct AccountsCreateOrGetRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountsCreateOrGetResponse { pub account: Account, #[cfg_attr(feature = "ts", ts(type = "string"))] @@ -446,11 +334,7 @@ pub struct AccountsCreateOrGetResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountsListRequest { #[cfg_attr(feature = "ts", ts(type = "number"))] pub offset: u64, @@ -459,11 +343,7 @@ pub struct AccountsListRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountInfo { pub account: Account, #[cfg_attr(feature = "ts", ts(type = "string"))] @@ -471,11 +351,7 @@ pub struct AccountInfo { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountsListResponse { pub accounts: Vec, #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -483,11 +359,7 @@ pub struct AccountsListResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountsGetBalancesRequest { #[serde(deserialize_with = "opt_string_or_struct")] pub account: Option, @@ -496,22 +368,14 @@ pub struct AccountsGetBalancesRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountsGetBalancesResponse { pub address: ComponentAddress, pub balances: Vec, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct BalanceEntry { pub vault_address: Option, pub resource_address: ResourceAddress, @@ -549,42 +413,26 @@ impl BalanceEntry { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountGetRequest { #[serde(deserialize_with = "string_or_struct")] pub name_or_address: ComponentAddressOrName, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountGetDefaultRequest { // Intentionally empty. Fields may be added in the future. } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountGetByKeyIndexRequest { pub key_index: u64, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountGetResponse { pub account: Account, #[cfg_attr(feature = "ts", ts(type = "string"))] @@ -592,30 +440,18 @@ pub struct AccountGetResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountSetDefaultRequest { #[serde(deserialize_with = "string_or_struct")] pub account: ComponentAddressOrName, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountSetDefaultResponse {} #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountsTransferRequest { #[serde(deserialize_with = "opt_string_or_struct")] pub account: Option, @@ -629,11 +465,7 @@ pub struct AccountsTransferRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountsTransferResponse { pub transaction_id: TransactionId, #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -644,11 +476,7 @@ pub struct AccountsTransferResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ProofsGenerateRequest { pub amount: Amount, pub reveal_amount: Amount, @@ -661,11 +489,7 @@ pub struct ProofsGenerateRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ProofsGenerateResponse { #[cfg_attr(feature = "ts", ts(type = "number"))] pub proof_id: OutputLockId, @@ -673,61 +497,37 @@ pub struct ProofsGenerateResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ProofsFinalizeRequest { #[cfg_attr(feature = "ts", ts(type = "number"))] pub proof_id: OutputLockId, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ProofsFinalizeResponse {} #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ProofsCancelRequest { #[cfg_attr(feature = "ts", ts(type = "number"))] pub proof_id: OutputLockId, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ConfidentialCreateOutputProofRequest { pub amount: Amount, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ConfidentialCreateOutputProofResponse { pub proof: ConfidentialOutputStatement, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ConfidentialTransferRequest { #[serde(deserialize_with = "opt_string_or_struct")] pub account: Option, @@ -743,11 +543,7 @@ pub struct ConfidentialTransferRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ConfidentialTransferResponse { pub transaction_id: TransactionId, #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -756,11 +552,7 @@ pub struct ConfidentialTransferResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ConfidentialViewVaultBalanceRequest { pub vault_id: VaultId, #[cfg_attr(feature = "ts", ts(type = "number | null"))] @@ -772,22 +564,14 @@ pub struct ConfidentialViewVaultBalanceRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ConfidentialViewVaultBalanceResponse { #[cfg_attr(feature = "ts", ts(type = "Record"))] pub balances: HashMap>, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ClaimBurnRequest { pub account: ComponentAddressOrName, pub claim_proof: ClaimBurnProof, @@ -796,11 +580,7 @@ pub struct ClaimBurnRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ClaimBurnProof { pub reciprocal_claim_public_key: RistrettoPublicKeyBytes, pub commitment: PedersenCommitmentBytes, @@ -809,11 +589,7 @@ pub struct ClaimBurnProof { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ClaimBurnResponse { pub transaction_id: TransactionId, #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -822,19 +598,11 @@ pub struct ClaimBurnResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ProofsCancelResponse {} #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct RevealFundsRequest { /// Account with funds to reveal #[serde(deserialize_with = "opt_string_or_struct")] @@ -849,11 +617,7 @@ pub struct RevealFundsRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct RevealFundsResponse { pub transaction_id: TransactionId, #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -862,11 +626,7 @@ pub struct RevealFundsResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountsCreateFreeTestCoinsRequest { pub account: ComponentAddressOrName, pub amount: Amount, @@ -875,11 +635,7 @@ pub struct AccountsCreateFreeTestCoinsRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AccountsCreateFreeTestCoinsResponse { pub account: Account, pub transaction_id: TransactionId, @@ -892,21 +648,13 @@ pub struct AccountsCreateFreeTestCoinsResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WebRtcStart { pub jwt: String, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WebRtcStartRequest { pub signaling_server_token: String, #[cfg_attr(feature = "ts", ts(type = "object"))] @@ -915,19 +663,11 @@ pub struct WebRtcStartRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WebRtcStartResponse {} #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AuthLoginRequest { pub permissions: Vec, #[cfg_attr(feature = "ts", ts(type = "{secs: number, nanos: number} | null"))] @@ -939,11 +679,7 @@ pub struct AuthLoginRequest { pub type EncodedJwtString = Zeroizing; #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AuthLoginResponse { #[cfg_attr(feature = "ts", ts(type = "string"))] pub auth_token: EncodedJwtString, @@ -952,11 +688,7 @@ pub struct AuthLoginResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AuthLoginAcceptRequest { #[cfg_attr(feature = "ts", ts(type = "string"))] pub auth_token: EncodedJwtString, @@ -964,59 +696,35 @@ pub struct AuthLoginAcceptRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AuthLoginAcceptResponse { #[cfg_attr(feature = "ts", ts(type = "string"))] pub permissions_token: EncodedJwtString, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AuthLoginDenyRequest { #[cfg_attr(feature = "ts", ts(type = "string"))] pub auth_token: EncodedJwtString, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AuthLoginDenyResponse {} #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AuthRevokeTokenRequest { pub permission_token_id: i32, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AuthRevokeTokenResponse {} #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct MintFaucetNftRequest { pub account: ComponentAddressOrName, #[cfg_attr(feature = "ts", ts(type = "object"))] @@ -1027,11 +735,7 @@ pub struct MintFaucetNftRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct MintFaucetNftResponse { pub transaction_id: TransactionId, pub finalize: FinalizeResult, @@ -1039,11 +743,7 @@ pub struct MintFaucetNftResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct GetNftRequest { pub resource_address: ResourceAddress, pub nft_id: NonFungibleId, @@ -1052,11 +752,7 @@ pub struct GetNftRequest { pub type GetNftResponse = NonFungibleToken; #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ListNftsRequest { #[serde(deserialize_with = "opt_string_or_struct")] pub account: Option, @@ -1067,50 +763,30 @@ pub struct ListNftsRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ListNftsResponse { pub nfts: Vec, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AuthGetAllJwtRequest {} #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AuthGetAllJwtResponse { pub jwt: Vec, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct GetValidatorFeesRequest { pub account_or_key: AccountOrKeyIndex, pub shard_group: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub enum AccountOrKeyIndex { /// Query by account. None signifies the default account. Account(Option), @@ -1119,21 +795,13 @@ pub enum AccountOrKeyIndex { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct GetValidatorFeesResponse { pub fees: HashMap, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct FeePoolDetails { pub address: ValidatorFeePoolAddress, #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -1141,11 +809,7 @@ pub struct FeePoolDetails { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ClaimValidatorFeesRequest { #[serde(default, deserialize_with = "opt_string_or_struct")] pub account: Option, @@ -1158,11 +822,7 @@ pub struct ClaimValidatorFeesRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct ClaimValidatorFeesResponse { pub transaction_id: TransactionId, #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -1171,51 +831,31 @@ pub struct ClaimValidatorFeesResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct SettingsSetRequest { pub indexer_url: String, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct SettingsSetResponse {} #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct SettingsGetResponse { pub indexer_url: String, pub network: NetworkInfo, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct NetworkInfo { pub name: String, pub byte: u8, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct SubstatesListRequest { #[serde(default, deserialize_with = "serde_with::string::option::deserialize")] #[cfg_attr(feature = "ts", ts(type = "string | null"))] @@ -1228,43 +868,27 @@ pub struct SubstatesListRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct SubstatesListResponse { pub substates: Vec, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct SubstatesGetRequest { #[cfg_attr(feature = "ts", ts(type = "string"))] pub substate_id: SubstateId, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct SubstatesGetResponse { pub record: Option, pub substate: Option, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WalletSubstateRecord { pub substate_id: SubstateId, pub parent_id: Option, @@ -1276,31 +900,19 @@ pub struct WalletSubstateRecord { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TemplatesGetRequest { pub template_address: TemplateAddress, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TemplatesGetResponse { pub template_definition: TemplateDef, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TemplatesListAuthoredRequest { #[cfg_attr(feature = "ts", ts(type = "string"))] pub author_public_key: RistrettoPublicKeyBytes, @@ -1310,11 +922,7 @@ pub struct TemplatesListAuthoredRequest { pub page_size: u64, } -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] #[derive(Debug, Clone, Deserialize, Serialize)] pub struct AuthoredTemplate { pub author_public_key: RistrettoPublicKeyBytes, @@ -1337,11 +945,7 @@ impl From<&AuthoredTemplateModel> for AuthoredTemplate { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TemplatesListAuthoredResponse { pub templates: Vec, #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -1349,19 +953,11 @@ pub struct TemplatesListAuthoredResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AuthGetMethodRequest {} #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] #[serde(rename_all = "lowercase")] pub enum AuthMethod { None, @@ -1369,51 +965,31 @@ pub enum AuthMethod { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct AuthGetMethodResponse { pub method: AuthMethod, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WebauthnAlreadyRegisteredRequest { pub username: String, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WebauthnAlreadyRegisteredResponse { pub registered: bool, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WebauthnStartRegisterRequest { pub username: String, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WebauthnStartRegisterResponse { /// Unique ID of the current registration Session. pub session_id: String, @@ -1423,11 +999,7 @@ pub struct WebauthnStartRegisterResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WebauthnFinishRegisterRequest { /// Session ID received from [`WebauthnStartRegisterResponse`]. pub session_id: String, @@ -1437,29 +1009,17 @@ pub struct WebauthnFinishRegisterRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WebauthnFinishRegisterResponse {} #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WebauthnStartAuthRequest { pub username: String, } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WebauthnStartAuthResponse { /// Session ID. pub session_id: String, @@ -1469,11 +1029,7 @@ pub struct WebauthnStartAuthResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WebauthnFinishAuthRequest { /// Session ID received from [`WebauthnStartAuthResponse`]. pub session_id: String, @@ -1483,19 +1039,11 @@ pub struct WebauthnFinishAuthRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WalletGetInfoRequest {} #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct WalletGetInfoResponse { pub version: String, pub network: String, @@ -1503,11 +1051,7 @@ pub struct WalletGetInfoResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransferNftRequest { pub resource_address: ResourceAddress, pub nfts: Vec, @@ -1523,11 +1067,7 @@ pub struct TransferNftRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct TransferNftResponse { pub transaction_id: TransactionId, #[cfg_attr(feature = "ts", ts(type = "number"))] @@ -1538,11 +1078,7 @@ pub struct TransferNftResponse { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct StealthTransferRequest { pub owner_account: ComponentAddressOrName, pub input_selection: ConfidentialTransferInputSelection, @@ -1556,11 +1092,7 @@ pub struct StealthTransferRequest { } #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] pub struct StealthTransferResponse { pub transaction_id: TransactionId, } diff --git a/crates/common_types/src/committee.rs b/crates/common_types/src/committee.rs index 4ddaf268e1..8187b2b5a4 100644 --- a/crates/common_types/src/committee.rs +++ b/crates/common_types/src/committee.rs @@ -11,21 +11,13 @@ use tari_template_lib_types::crypto::RistrettoPublicKeyBytes; use crate::{Epoch, NumPreshards, ShardGroup, SubstateAddress, VersionedSubstateIdRef, VotePower}; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Default, Hash)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Committee { members: Vec>, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, Hash)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct CommitteeMember { pub address: TAddr, #[cfg_attr(feature = "ts", ts(type = "string"))] @@ -222,11 +214,7 @@ impl FromIterator> for Committee { /// Represents a "slice" of the 256-bit shard space #[derive(Debug, Clone, Copy, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct CommitteeInfo { num_shards: NumPreshards, num_shard_group_members: u32, diff --git a/crates/common_types/src/epoch.rs b/crates/common_types/src/epoch.rs index 2699a7e611..104c43bd28 100644 --- a/crates/common_types/src/epoch.rs +++ b/crates/common_types/src/epoch.rs @@ -29,7 +29,7 @@ use serde::{Deserialize, Serialize}; use ts_rs::TS; #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, BorshSerialize)] -#[cfg_attr(feature = "ts", derive(TS), ts(export, export_to = "../../bindings/src/types/"))] +#[cfg_attr(feature = "ts", derive(TS), ts(export))] pub struct Epoch(#[cfg_attr(feature = "ts", ts(type = "number"))] pub u64); impl Epoch { diff --git a/crates/common_types/src/era.rs b/crates/common_types/src/era.rs index 1cccafaabc..4ac4377ac2 100644 --- a/crates/common_types/src/era.rs +++ b/crates/common_types/src/era.rs @@ -28,7 +28,7 @@ use serde::{Deserialize, Serialize}; use ts_rs::TS; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] -#[cfg_attr(feature = "ts", derive(TS), ts(export, export_to = "../../bindings/src/types/"))] +#[cfg_attr(feature = "ts", derive(TS), ts(export))] pub struct Era(#[cfg_attr(feature = "ts", ts(type = "number"))] pub u64); impl Era { diff --git a/crates/common_types/src/extra_data.rs b/crates/common_types/src/extra_data.rs index 49751b597a..5480351407 100644 --- a/crates/common_types/src/extra_data.rs +++ b/crates/common_types/src/extra_data.rs @@ -40,7 +40,7 @@ pub enum ExtraFieldKey { } #[derive(Clone, Debug, Deserialize, Serialize, Default, BorshSerialize)] -#[cfg_attr(feature = "ts", derive(TS), ts(export, export_to = "../../bindings/src/types/"))] +#[cfg_attr(feature = "ts", derive(TS), ts(export))] pub struct ExtraData(#[cfg_attr(feature = "ts", ts(type = "string"))] BTreeMap); impl ExtraData { diff --git a/crates/common_types/src/lib.rs b/crates/common_types/src/lib.rs index 8b83be093f..800809ea34 100644 --- a/crates/common_types/src/lib.rs +++ b/crates/common_types/src/lib.rs @@ -68,4 +68,8 @@ pub use vote_power::*; pub mod base_layer_hashing; mod shard_state_versions; + pub use shard_state_versions::*; + +mod state_version; +pub use state_version::*; diff --git a/crates/common_types/src/lock_intent.rs b/crates/common_types/src/lock_intent.rs index dbdd1ca275..71d965e0fd 100644 --- a/crates/common_types/src/lock_intent.rs +++ b/crates/common_types/src/lock_intent.rs @@ -28,11 +28,7 @@ impl ToSubstateAddress for T { /// Substate lock flags #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum SubstateLockType { Read, Write, diff --git a/crates/common_types/src/network.rs b/crates/common_types/src/network.rs index 96dba94e4b..81f73cedb8 100644 --- a/crates/common_types/src/network.rs +++ b/crates/common_types/src/network.rs @@ -35,11 +35,7 @@ use serde::{Deserialize, Serialize}; /// Represents the available Tari networks. The variants and assigned byte needs to match the L1 network enum. #[repr(u8)] #[derive(Clone, Debug, PartialEq, Eq, Copy, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] #[serde(rename_all = "lowercase")] pub enum Network { MainNet = 0x00, diff --git a/crates/common_types/src/node_height.rs b/crates/common_types/src/node_height.rs index 69b4677a1c..9d4c1807c8 100644 --- a/crates/common_types/src/node_height.rs +++ b/crates/common_types/src/node_height.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; use ts_rs::TS; #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, BorshSerialize)] -#[cfg_attr(feature = "ts", derive(TS), ts(export, export_to = "../../bindings/src/types/"))] +#[cfg_attr(feature = "ts", derive(TS), ts(export))] #[serde(transparent)] pub struct NodeHeight(#[cfg_attr(feature = "ts", ts(type = "number"))] pub u64); diff --git a/crates/common_types/src/num_preshards.rs b/crates/common_types/src/num_preshards.rs index 22ccb6c588..485e5a9a08 100644 --- a/crates/common_types/src/num_preshards.rs +++ b/crates/common_types/src/num_preshards.rs @@ -7,11 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::{shard::Shard, ShardGroup}; -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] #[derive(Clone, Debug, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)] pub enum NumPreshards { P1 = 1, diff --git a/crates/common_types/src/peer_address.rs b/crates/common_types/src/peer_address.rs index 98543e9da9..59850c4ec2 100644 --- a/crates/common_types/src/peer_address.rs +++ b/crates/common_types/src/peer_address.rs @@ -12,7 +12,7 @@ use ts_rs::TS; use crate::{DerivableFromPublicKey, NodeAddressable, ToPeerId}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize)] -#[cfg_attr(feature = "ts", derive(TS), ts(export, export_to = "../../bindings/src/types/"))] +#[cfg_attr(feature = "ts", derive(TS), ts(export))] pub struct PeerAddress(#[cfg_attr(feature = "ts", ts(type = "string"))] PeerId); impl PeerAddress { diff --git a/crates/common_types/src/shard.rs b/crates/common_types/src/shard.rs index f198192459..7ca3b294b9 100644 --- a/crates/common_types/src/shard.rs +++ b/crates/common_types/src/shard.rs @@ -9,11 +9,7 @@ use serde::{Deserialize, Serialize}; use crate::{uint::U256, NumPreshards, ShardGroup, SubstateAddress}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] #[serde(transparent)] pub struct Shard(#[cfg_attr(feature = "ts", ts(type = "number"))] u32); diff --git a/crates/common_types/src/shard_group.rs b/crates/common_types/src/shard_group.rs index 5508fe5bd5..66c1c924ed 100644 --- a/crates/common_types/src/shard_group.rs +++ b/crates/common_types/src/shard_group.rs @@ -15,11 +15,7 @@ use serde::{Deserialize, Serialize}; use crate::{shard::Shard, uint::U256, NumPreshards, SubstateAddress}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ShardGroup { start: Shard, end_inclusive: Shard, diff --git a/crates/common_types/src/shard_state_versions.rs b/crates/common_types/src/shard_state_versions.rs index 117550314c..c718829301 100644 --- a/crates/common_types/src/shard_state_versions.rs +++ b/crates/common_types/src/shard_state_versions.rs @@ -19,11 +19,7 @@ type BoundedVersionVec = BoundedVec; /// elements. The first element is always the global shard (shard 0) version. The second element is the state /// version for shard 1, third is shard 2, and forth is shard 3. #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] #[serde(transparent)] pub struct ShardStateVersions { #[cfg_attr(feature = "ts", ts(type = "number[]"))] diff --git a/crates/common_types/src/state_version.rs b/crates/common_types/src/state_version.rs new file mode 100644 index 0000000000..c95a18c0f8 --- /dev/null +++ b/crates/common_types/src/state_version.rs @@ -0,0 +1,32 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use std::fmt::Display; + +use tari_bor::{Deserialize, Serialize}; + +// TODO: use this new-type where appropriate in the codebase +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Deserialize, Serialize)] +#[serde(transparent)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] +pub struct StateVersion(#[cfg_attr(feature = "ts", ts(type = "number | bigint"))] u64); + +impl StateVersion { + pub const fn new(version: u64) -> Self { + Self(version) + } + + pub const fn zero() -> Self { + Self(0) + } + + pub const fn as_u64(&self) -> u64 { + self.0 + } +} + +impl Display for StateVersion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/crates/common_types/src/substate_address.rs b/crates/common_types/src/substate_address.rs index bcb67123df..084680db57 100644 --- a/crates/common_types/src/substate_address.rs +++ b/crates/common_types/src/substate_address.rs @@ -26,11 +26,7 @@ pub trait ToSubstateAddress { } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct SubstateAddress( #[serde(with = "serde_with::hex")] #[cfg_attr(feature = "ts", ts(type = "string"))] diff --git a/crates/common_types/src/substate_type.rs b/crates/common_types/src/substate_type.rs index 98f1d6dd34..f947f3c91c 100644 --- a/crates/common_types/src/substate_type.rs +++ b/crates/common_types/src/substate_type.rs @@ -7,11 +7,7 @@ use serde::{Deserialize, Serialize}; use tari_engine_types::substate::{Substate, SubstateId, SubstateValue}; #[derive(Debug, Clone, Copy, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum SubstateType { Component, Resource, @@ -96,6 +92,6 @@ impl From<&Substate> for SubstateType { impl Display for SubstateType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.as_prefix_str()) + write!(f, "{:?}", self) } } diff --git a/crates/common_types/src/versioned_substate_id.rs b/crates/common_types/src/versioned_substate_id.rs index 49bbf2d317..77ca5fb7a9 100644 --- a/crates/common_types/src/versioned_substate_id.rs +++ b/crates/common_types/src/versioned_substate_id.rs @@ -10,11 +10,7 @@ use tari_engine_types::{substate::SubstateId, transaction_receipt::TransactionRe use crate::{displayable::Displayable, shard::Shard, NumPreshards, ShardGroup, SubstateAddress, ToSubstateAddress}; #[derive(Debug, Clone, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct SubstateRequirement { #[cfg_attr(feature = "ts", ts(type = "string"))] pub substate_id: SubstateId, @@ -300,11 +296,7 @@ impl Display for SubstateRequirementRef<'_> { pub struct SubstateRequirementParseError(String); #[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize, Serialize, BorshSerialize, BorshDeserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct VersionedSubstateId { substate_id: SubstateId, version: u32, diff --git a/crates/common_types/src/vote_power.rs b/crates/common_types/src/vote_power.rs index 858ad2c100..6d8e5975c3 100644 --- a/crates/common_types/src/vote_power.rs +++ b/crates/common_types/src/vote_power.rs @@ -6,11 +6,7 @@ use std::fmt::Display; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Default)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct VotePower(u64); impl VotePower { diff --git a/crates/consensus/src/hotstuff/worker.rs b/crates/consensus/src/hotstuff/worker.rs index 2479f3f64a..386e526d7f 100644 --- a/crates/consensus/src/hotstuff/worker.rs +++ b/crates/consensus/src/hotstuff/worker.rs @@ -1055,6 +1055,10 @@ impl HotstuffWorker { zero_block.commit_block_without_state_changes(tx, &zero_block.justify().calculate_id())?; } + if !Block::get_ids_by_epoch_and_height(&**tx, epoch, NodeHeight::zero())?.is_empty() { + return Ok(()); + } + let state_merkle_root = ShardedStateTree::new(&**tx).calculate_state_root(shard_group)?; let mut genesis = Block::genesis( @@ -1065,19 +1069,19 @@ impl HotstuffWorker { FixedHash::new(state_merkle_root.into_array()), self.config.sidechain_id, ); - if !genesis.exists(&**tx)? { - info!(target: LOG_TARGET, "✨Creating genesis block {genesis}"); - genesis.justify().save(tx)?; - genesis.insert(tx)?; - genesis.add_justify_qc(tx, &QcId::zero())?; - genesis.as_locked().set(tx)?; - genesis.as_leaf().set(tx)?; - genesis.as_highest_seen().set(tx)?; - genesis.as_last_executed().set(tx)?; - genesis.as_last_voted().set(tx)?; - genesis.justify().as_high_pc().set(tx)?; - genesis.commit_block_without_state_changes(tx, &genesis.justify().calculate_id())?; - } + // Warn: you cannot use genesis.exists(tx) here, because we're calculating the current state merkle root, + // not the merkle root at height = 0. + info!(target: LOG_TARGET, "✨Creating genesis block {genesis}"); + genesis.justify().save(tx)?; + genesis.insert(tx)?; + genesis.add_justify_qc(tx, &QcId::zero())?; + genesis.as_locked().set(tx)?; + genesis.as_leaf().set(tx)?; + genesis.as_highest_seen().set(tx)?; + genesis.as_last_executed().set(tx)?; + genesis.as_last_voted().set(tx)?; + genesis.justify().as_high_pc().set(tx)?; + genesis.commit_block_without_state_changes(tx, &genesis.justify().calculate_id())?; Ok(()) }) diff --git a/crates/consensus/src/traits/mod.rs b/crates/consensus/src/traits/mod.rs index 839258b802..86ddc18654 100644 --- a/crates/consensus/src/traits/mod.rs +++ b/crates/consensus/src/traits/mod.rs @@ -22,7 +22,7 @@ pub use sync::*; use tari_epoch_manager::EpochManagerReader; use tari_ootle_common_types::DerivableFromPublicKey; use tari_ootle_storage::StateStore; -pub use tasks::*; +pub(crate) use tasks::*; pub use transaction_executor::*; use crate::traits::hooks::ConsensusHooks; diff --git a/crates/consensus/src/traits/tasks.rs b/crates/consensus/src/traits/tasks.rs index 0722be88f9..363d718826 100644 --- a/crates/consensus/src/traits/tasks.rs +++ b/crates/consensus/src/traits/tasks.rs @@ -10,7 +10,7 @@ use crate::tracing::TraceTimer; const LOG_TARGET: &str = "tari::ootle::consensus::tasks"; -pub trait PeriodicTask { +pub(crate) trait PeriodicTask { fn name() -> &'static str; fn do_work_periodically(self, interval: Duration) -> AbortOnDropGuard @@ -35,7 +35,7 @@ pub trait PeriodicTask { fn do_work(&self) -> impl Future + Send; } -pub struct AbortOnDropGuard { +pub(crate) struct AbortOnDropGuard { handle: AbortHandle, } diff --git a/crates/consensus_tests/src/state_tree.rs b/crates/consensus_tests/src/state_tree.rs index 20fbac0975..dc535cfaaa 100644 --- a/crates/consensus_tests/src/state_tree.rs +++ b/crates/consensus_tests/src/state_tree.rs @@ -6,7 +6,7 @@ use std::time::Duration; use tari_consensus::hotstuff::HotStuffError; use tari_consensus_types::Decision; use tari_ootle_common_types::{optional::Optional, Epoch, NodeHeight}; -use tari_ootle_storage::{StateStore, StateStoreReadTransaction}; +use tari_ootle_storage::{consensus_models::SubstateValueFilterFlags, StateStore, StateStoreReadTransaction}; use tari_state_tree::{ key_mapper::SpreadPrefixKeyMapper, memory_store::MemoryTreeStore, @@ -60,13 +60,17 @@ async fn check_state_transitions() { test.get_validator(&TestAddress::new("1")) .state_store .with_read_tx(|tx| { - let checkpoint = tx.epoch_checkpoint_get(Epoch(1)).unwrap(); + let checkpoint = tx + .epoch_checkpoint_get_all_from_epoch(Epoch(1), 1) + .unwrap() + .pop() + .unwrap(); for shard in TEST_NUM_PRESHARDS.all_shards_iter() { let mut all_transitions = vec![]; let mut next_state_version = 1; while let Some(transitions) = tx - .state_transitions_get_starting_at(shard, next_state_version, false) + .state_transitions_get_starting_at(shard, next_state_version, SubstateValueFilterFlags::empty()) .optional() .unwrap() { diff --git a/crates/consensus_tests/src/support/epoch_manager.rs b/crates/consensus_tests/src/support/epoch_manager.rs index 8bfe45f5b2..1c803e9408 100644 --- a/crates/consensus_tests/src/support/epoch_manager.rs +++ b/crates/consensus_tests/src/support/epoch_manager.rs @@ -390,6 +390,32 @@ impl EpochManagerReader for TestEpochManager { Ok(vn.clone()) } + + async fn get_committee_info( + &self, + epoch: Epoch, + shard_group: ShardGroup, + ) -> Result { + let state = self.state_lock().await; + let committee = state.committees.get(&shard_group).ok_or_else(|| { + EpochManagerError::StorageError(StorageError::NotFound { + item: "committee", + key: format!("for shard group {shard_group}"), + }) + })?; + + let num_members = committee.len(); + let total_power = committee.total_power(); + + Ok(CommitteeInfo::new( + TEST_NUM_PRESHARDS, + num_members as u32, + state.committees.len() as u32, + shard_group, + epoch, + total_power, + )) + } } #[derive(Debug, Clone)] diff --git a/crates/consensus_types/src/certificates/proposal_certificate.rs b/crates/consensus_types/src/certificates/proposal_certificate.rs index 7d7eea4db6..397f08bebf 100644 --- a/crates/consensus_types/src/certificates/proposal_certificate.rs +++ b/crates/consensus_types/src/certificates/proposal_certificate.rs @@ -17,11 +17,7 @@ use crate::{ }; #[derive(Debug, Clone, Deserialize, Serialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ProposalCertificate { height: NodeHeight, #[cfg_attr(feature = "ts", ts(type = "string"))] diff --git a/crates/consensus_types/src/certificates/timeout_certificate.rs b/crates/consensus_types/src/certificates/timeout_certificate.rs index 00c8a5e124..d3f1607e02 100644 --- a/crates/consensus_types/src/certificates/timeout_certificate.rs +++ b/crates/consensus_types/src/certificates/timeout_certificate.rs @@ -10,11 +10,7 @@ use tari_ootle_common_types::{hashing::timeout_certificate_id_hasher, Epoch, Nod use crate::{validator_signature::ValidatorSignatureBytes, HighTc, TcId}; #[derive(Debug, Clone, Hash, Deserialize, Serialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct TimeoutCertificate { epoch: Epoch, height: NodeHeight, diff --git a/crates/consensus_types/src/decision.rs b/crates/consensus_types/src/decision.rs index 74f590b79d..d629b57daa 100644 --- a/crates/consensus_types/src/decision.rs +++ b/crates/consensus_types/src/decision.rs @@ -11,11 +11,7 @@ use serde::{Deserialize, Serialize}; use tari_engine_types::commit_result::{AbortReason, TransactionResult}; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum Decision { /// Decision to COMMIT the transaction Commit, diff --git a/crates/consensus_types/src/validator_signature.rs b/crates/consensus_types/src/validator_signature.rs index 20f5d14ffc..1b55848fc7 100644 --- a/crates/consensus_types/src/validator_signature.rs +++ b/crates/consensus_types/src/validator_signature.rs @@ -11,11 +11,7 @@ use tari_template_lib::types::crypto::{RistrettoPublicKeyBytes, SchnorrSignature pub type ValidatorSchnorrSignature = SchnorrSignature; #[derive(Clone, Debug, Hash, Deserialize, Serialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ValidatorSignatureBytes { pub public_key: RistrettoPublicKeyBytes, pub signature: SchnorrSignatureBytes, diff --git a/crates/engine_types/src/commit_result.rs b/crates/engine_types/src/commit_result.rs index ce50aaf147..583b71cae4 100644 --- a/crates/engine_types/src/commit_result.rs +++ b/crates/engine_types/src/commit_result.rs @@ -38,11 +38,7 @@ use crate::{ }; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ExecuteResult { /// The finalized result to commit. If the fee transaction succeeds but the transaction fails, this will be accept. pub finalize: FinalizeResult, @@ -135,11 +131,7 @@ impl ExecuteResult { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct FinalizeResult { pub transaction_hash: Hash, pub events: Vec, @@ -222,11 +214,7 @@ impl FinalizeResult { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum TransactionResult { Accept(SubstateDiff), AcceptFeeRejectRest(SubstateDiff, RejectReason), @@ -309,11 +297,7 @@ impl Display for TransactionResult { } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum RejectReason { ExecutionFailure(String), OneOrMoreInputsNotFound(String), @@ -358,11 +342,7 @@ impl Display for RejectReason { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum AbortReason { ForeignPledgeInputConflict, LockInputsFailed, diff --git a/crates/engine_types/src/component.rs b/crates/engine_types/src/component.rs index 2bb3671c91..5e635d4791 100644 --- a/crates/engine_types/src/component.rs +++ b/crates/engine_types/src/component.rs @@ -53,11 +53,7 @@ pub fn derive_component_address_from_public_key( } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ComponentHeader { pub template_address: TemplateAddress, pub module_name: String, @@ -105,11 +101,7 @@ impl ComponentHeader { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ComponentBody { #[serde(with = "serde_with::cbor_value")] #[cfg_attr(feature = "ts", ts(type = "any"))] diff --git a/crates/engine_types/src/component_call.rs b/crates/engine_types/src/component_call.rs index 2166321601..e07ebebbcc 100644 --- a/crates/engine_types/src/component_call.rs +++ b/crates/engine_types/src/component_call.rs @@ -7,11 +7,7 @@ use tari_bor::{Deserialize, Serialize}; use tari_template_lib::{args::WorkspaceId, models::ComponentAddress}; #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum ComponentCall { Address(ComponentAddress), Workspace(WorkspaceId), diff --git a/crates/engine_types/src/confidential/claim.rs b/crates/engine_types/src/confidential/claim.rs index 606340246b..0d94244116 100644 --- a/crates/engine_types/src/confidential/claim.rs +++ b/crates/engine_types/src/confidential/claim.rs @@ -9,11 +9,7 @@ use tari_template_lib::{ }; #[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ConfidentialClaim { pub public_key: RistrettoPublicKeyBytes, pub output_address: UnclaimedConfidentialOutputAddress, diff --git a/crates/engine_types/src/confidential/unclaimed.rs b/crates/engine_types/src/confidential/unclaimed.rs index dfead77e4a..f5fe78a246 100644 --- a/crates/engine_types/src/confidential/unclaimed.rs +++ b/crates/engine_types/src/confidential/unclaimed.rs @@ -28,11 +28,7 @@ use tari_template_lib::{ }; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct UnclaimedConfidentialOutput { #[cfg_attr(feature = "ts", ts(type = "string"))] pub commitment: PedersenCommitmentBytes, diff --git a/crates/engine_types/src/crypto/elgamal.rs b/crates/engine_types/src/crypto/elgamal.rs index 9b510ddb20..9bd904ee40 100644 --- a/crates/engine_types/src/crypto/elgamal.rs +++ b/crates/engine_types/src/crypto/elgamal.rs @@ -128,11 +128,7 @@ pub fn validate_elgamal_verifiable_balance_proof( } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct CompressedElgamalVerifiableBalance { pub encrypted: RistrettoPublicKeyBytes, pub public_nonce: RistrettoPublicKeyBytes, diff --git a/crates/engine_types/src/crypto/output.rs b/crates/engine_types/src/crypto/output.rs index af7a78d04e..26d5d13e0d 100644 --- a/crates/engine_types/src/crypto/output.rs +++ b/crates/engine_types/src/crypto/output.rs @@ -12,11 +12,7 @@ use crate::{ }; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct PrivateOutput { pub public_nonce: RistrettoPublicKeyBytes, pub encrypted_data: EncryptedData, diff --git a/crates/engine_types/src/events.rs b/crates/engine_types/src/events.rs index 538382e916..6b65757576 100644 --- a/crates/engine_types/src/events.rs +++ b/crates/engine_types/src/events.rs @@ -27,10 +27,8 @@ use tari_template_lib::{ models::Metadata, types::{Hash, TemplateAddress}, }; -#[cfg(feature = "ts")] -use ts_rs::TS; -use crate::{serde_with, substate::SubstateId}; +use crate::substate::SubstateId; // Topics for builtin events emitted by the engine const STANDARD_TOPIC_PREFIX: &str = "std."; @@ -40,14 +38,10 @@ fn std_event(object_name: &str, action_name: &str) -> String { } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "ts", derive(TS), ts(export, export_to = "../../bindings/src/types/"))] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Event { substate_id: Option, - #[serde(with = "serde_with::hex")] - #[cfg_attr(feature = "ts", ts(type = "string"))] template_address: TemplateAddress, - #[serde(with = "serde_with::hex")] - #[cfg_attr(feature = "ts", ts(type = "string"))] tx_hash: Hash, topic: String, payload: Metadata, diff --git a/crates/engine_types/src/fees.rs b/crates/engine_types/src/fees.rs index b45e13e067..ea92888b34 100644 --- a/crates/engine_types/src/fees.rs +++ b/crates/engine_types/src/fees.rs @@ -5,11 +5,7 @@ use indexmap::{map::Entry, IndexMap}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct FeeReceipt { /// The total amount of the fee payment(s) pub total_fee_payment: u64, @@ -62,11 +58,7 @@ impl FeeReceipt { } #[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum FeeSource { Initial, RuntimeCall, @@ -77,11 +69,7 @@ pub enum FeeSource { } #[derive(Debug, Clone, Serialize, Deserialize, Default)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct FeeBreakdown { breakdown: IndexMap, } @@ -110,11 +98,7 @@ impl FeeBreakdown { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct FeeCostBreakdown { pub total_fees_charged: u64, pub breakdown: FeeBreakdown, diff --git a/crates/engine_types/src/indexed_value.rs b/crates/engine_types/src/indexed_value.rs index d7370e11e6..927b741b02 100644 --- a/crates/engine_types/src/indexed_value.rs +++ b/crates/engine_types/src/indexed_value.rs @@ -34,11 +34,7 @@ use crate::{ const MAX_VISITOR_DEPTH: usize = 50; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct IndexedValue { indexed: IndexedWellKnownTypes, #[serde(with = "serde_with::cbor_value")] @@ -143,11 +139,7 @@ impl Default for IndexedValue { } #[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct IndexedWellKnownTypes { bucket_ids: Vec, proof_ids: Vec, diff --git a/crates/engine_types/src/instruction.rs b/crates/engine_types/src/instruction.rs index aba8d29c0a..d930c5cb0b 100644 --- a/crates/engine_types/src/instruction.rs +++ b/crates/engine_types/src/instruction.rs @@ -20,11 +20,7 @@ use crate::{ }; #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum Instruction { CreateAccount { #[cfg_attr(feature = "ts", ts(type = "string"))] diff --git a/crates/engine_types/src/instruction_result.rs b/crates/engine_types/src/instruction_result.rs index 3aa95400ae..db5472a47d 100644 --- a/crates/engine_types/src/instruction_result.rs +++ b/crates/engine_types/src/instruction_result.rs @@ -29,7 +29,7 @@ use ts_rs::TS; use crate::indexed_value::{IndexedValue, IndexedValueError}; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "ts", derive(TS), ts(export, export_to = "../../bindings/src/types/"))] +#[cfg_attr(feature = "ts", derive(TS), ts(export))] pub struct InstructionResult { pub indexed: IndexedValue, pub return_type: Type, diff --git a/crates/engine_types/src/lock.rs b/crates/engine_types/src/lock.rs index d7c6a1b425..c98532e547 100644 --- a/crates/engine_types/src/lock.rs +++ b/crates/engine_types/src/lock.rs @@ -9,7 +9,7 @@ use ts_rs::TS; pub type LockId = u32; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[cfg_attr(feature = "ts", derive(TS), ts(export, export_to = "../../bindings/src/types/"))] +#[cfg_attr(feature = "ts", derive(TS), ts(export))] pub enum LockFlag { Read = 0x01, Write = 0x02, diff --git a/crates/engine_types/src/logs.rs b/crates/engine_types/src/logs.rs index cb1522b5a3..3528370f6e 100644 --- a/crates/engine_types/src/logs.rs +++ b/crates/engine_types/src/logs.rs @@ -28,7 +28,7 @@ pub use tari_template_lib::args::LogLevel; use ts_rs::TS; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "ts", derive(TS), ts(export, export_to = "../../bindings/src/types/"))] +#[cfg_attr(feature = "ts", derive(TS), ts(export))] pub struct LogEntry { pub message: String, pub level: LogLevel, diff --git a/crates/engine_types/src/non_fungible.rs b/crates/engine_types/src/non_fungible.rs index a8cee33ca2..7c189f5122 100644 --- a/crates/engine_types/src/non_fungible.rs +++ b/crates/engine_types/src/non_fungible.rs @@ -7,11 +7,7 @@ use tari_bor::BorError; use crate::serde_with; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct NonFungibleContainer(Option); impl NonFungibleContainer { @@ -41,11 +37,7 @@ impl NonFungibleContainer { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct NonFungible { #[cfg_attr(feature = "ts", ts(type = "any"))] #[serde(with = "serde_with::cbor_value")] diff --git a/crates/engine_types/src/published_template.rs b/crates/engine_types/src/published_template.rs index 22c211d3a0..5ed64f7ed1 100644 --- a/crates/engine_types/src/published_template.rs +++ b/crates/engine_types/src/published_template.rs @@ -18,11 +18,7 @@ use crate::hashing::{hasher32, EngineHashDomainLabel}; const TAG: u64 = BinaryTag::TemplateAddress.as_u64(); #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct PublishedTemplateAddress(#[cfg_attr(feature = "ts", ts(type = "string"))] BorTag); impl PublishedTemplateAddress { @@ -91,11 +87,7 @@ impl borsh::BorshDeserialize for PublishedTemplateAddress { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct PublishedTemplate { #[cfg_attr(feature = "ts", ts(type = "string"))] pub author: RistrettoPublicKeyBytes, diff --git a/crates/engine_types/src/resource.rs b/crates/engine_types/src/resource.rs index d10c187909..81d5d029fc 100644 --- a/crates/engine_types/src/resource.rs +++ b/crates/engine_types/src/resource.rs @@ -34,11 +34,7 @@ use tari_template_lib::{ use crate::FromByteType; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Resource { resource_type: ResourceType, owner_rule: OwnerRule, diff --git a/crates/engine_types/src/resource_address_ref.rs b/crates/engine_types/src/resource_address_ref.rs index b8cd4686ad..c45da51f8d 100644 --- a/crates/engine_types/src/resource_address_ref.rs +++ b/crates/engine_types/src/resource_address_ref.rs @@ -10,11 +10,7 @@ use tari_template_lib::{ }; #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum ResourceAddressRef { Address(ResourceAddress), Workspace(WorkspaceOffsetId), diff --git a/crates/engine_types/src/resource_container.rs b/crates/engine_types/src/resource_container.rs index 696ad50dfc..ef108b9ce1 100644 --- a/crates/engine_types/src/resource_container.rs +++ b/crates/engine_types/src/resource_container.rs @@ -25,11 +25,7 @@ use crate::{confidential, crypto::PrivateOutput, substate::SubstateId, ToByteTyp /// Instances of a single resource kept in Buckets and Vaults #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum ResourceContainer { Fungible { address: ResourceAddress, diff --git a/crates/engine_types/src/substate.rs b/crates/engine_types/src/substate.rs index da7e089f51..8849eecfd4 100644 --- a/crates/engine_types/src/substate.rs +++ b/crates/engine_types/src/substate.rs @@ -53,11 +53,7 @@ use crate::{ }; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Substate { substate: SubstateValue, version: u32, @@ -116,11 +112,7 @@ pub fn hash_substate(substate: &SubstateValue, version: u32) -> FixedHash { // BorshDeserialize is implemented for this struct because we de/encode keys in the database using this format /// Base object address, version tuples #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, BorshSerialize, BorshDeserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum SubstateId { Component(ComponentAddress), Resource(ResourceAddress), @@ -287,7 +279,7 @@ impl SubstateId { matches!(self, Self::ValidatorFeePool(_)) } - pub fn is_utxo_address(&self) -> bool { + pub fn is_utxo(&self) -> bool { matches!(self, Self::Utxo(_)) } @@ -563,11 +555,7 @@ impl_partial_eq!(ValidatorFeePoolAddress, ValidatorFeePool); impl_partial_eq!(UtxoAddress, Utxo); #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum SubstateValue { Component(ComponentHeader), Resource(Box), @@ -834,11 +822,7 @@ impl From for SubstateValue { } #[derive(Debug, Clone, Default, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct SubstateDiff { up_substates: Vec<(SubstateId, Substate)>, down_substates: Vec<(SubstateId, u32)>, diff --git a/crates/engine_types/src/transaction_receipt.rs b/crates/engine_types/src/transaction_receipt.rs index bc58e7583a..602efbfc7e 100644 --- a/crates/engine_types/src/transaction_receipt.rs +++ b/crates/engine_types/src/transaction_receipt.rs @@ -20,11 +20,7 @@ use crate::{events::Event, fees::FeeReceipt, logs::LogEntry}; const TAG: u64 = BinaryTag::TransactionReceipt.as_u64(); #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct TransactionReceiptAddress(#[cfg_attr(feature = "ts", ts(type = "string"))] BorTag); impl TransactionReceiptAddress { @@ -85,11 +81,7 @@ impl borsh::BorshDeserialize for TransactionReceiptAddress { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct TransactionReceipt { pub transaction_hash: Hash, pub events: Vec, diff --git a/crates/engine_types/src/utxo.rs b/crates/engine_types/src/utxo.rs index 2ac8d957d3..b7683ce412 100644 --- a/crates/engine_types/src/utxo.rs +++ b/crates/engine_types/src/utxo.rs @@ -18,22 +18,14 @@ use tari_template_lib::{ use crate::crypto::PrivateOutput; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Utxo { pub output: Option, pub is_frozen: bool, } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct UtxoOutput { pub output: PrivateOutput, /// The public key that must prove ownership of this UTXO. This is typically a one time "stealth" public key but is @@ -84,11 +76,7 @@ impl Utxo { const TAG: u64 = BinaryTag::Utxo.as_u64(); #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct UtxoAddress(BorTag); impl UtxoAddress { @@ -133,11 +121,7 @@ impl From for UtxoAddress { #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, BorshSerialize, BorshDeserialize, )] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct UtxoId( #[cfg_attr(feature = "ts", ts(type = "string"))] #[serde(with = "serde_helpers::fixed_hex")] @@ -182,11 +166,7 @@ impl Display for UtxoId { #[derive( Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord, BorshSerialize, BorshDeserialize, )] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct UtxoAddressContents { resource_address: ResourceAddress, id: UtxoId, diff --git a/crates/engine_types/src/validator_fee.rs b/crates/engine_types/src/validator_fee.rs index 20bfadee28..38366868fd 100644 --- a/crates/engine_types/src/validator_fee.rs +++ b/crates/engine_types/src/validator_fee.rs @@ -22,11 +22,7 @@ use crate::resource_container::{ResourceContainer, ResourceError}; const TAG: u64 = BinaryTag::ValidatorNodeFeePool.as_u64(); #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ValidatorFeePoolAddress(#[cfg_attr(feature = "ts", ts(type = "string"))] BorTag); impl ValidatorFeePoolAddress { @@ -101,11 +97,7 @@ impl borsh::BorshDeserialize for ValidatorFeePoolAddress { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ValidatorFeePool { #[cfg_attr(feature = "ts", ts(type = "ArrayBuffer"))] pub claim_public_key: RistrettoPublicKeyBytes, @@ -187,11 +179,7 @@ impl ValidatorFeePool { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ValidatorFeeWithdrawal { pub address: ValidatorFeePoolAddress, pub amount: u64, diff --git a/crates/engine_types/src/vault.rs b/crates/engine_types/src/vault.rs index f2bc819ad0..6c268d3d29 100644 --- a/crates/engine_types/src/vault.rs +++ b/crates/engine_types/src/vault.rs @@ -39,11 +39,7 @@ use crate::{ }; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Vault { resource_container: ResourceContainer, #[serde(default)] diff --git a/crates/epoch_manager/src/service/epoch_manager.rs b/crates/epoch_manager/src/service/epoch_manager.rs index 17cccbee42..a23f65cc83 100644 --- a/crates/epoch_manager/src/service/epoch_manager.rs +++ b/crates/epoch_manager/src/service/epoch_manager.rs @@ -52,7 +52,7 @@ use tokio::sync::{broadcast, oneshot}; use crate::{ error::EpochManagerError, - service::config::EpochManagerConfig, + service::{config::EpochManagerConfig, NetworkDescription, ShardGroupInfo}, traits::{EpochManagerSpec, LayerOneTransactionSubmitter}, EpochManagerEvent, }; @@ -325,7 +325,6 @@ where TSpec: EpochManagerSpec return self.get_validator_nodes_per_epoch(epoch); } - // A shard a equal slice of the shard space that a validator fits into let shard_group = substate_address.to_shard_group(self.config.num_preshards, num_committees); // TODO(perf): fetch full validator node records for the shard group in single query (current O(n + 1) queries) @@ -463,6 +462,15 @@ where TSpec: EpochManagerSpec ) -> Result { let num_committees = self.get_number_of_committees(epoch)?; let shard_group = substate_address.to_shard_group(self.config.num_preshards, num_committees); + self.get_committee_info(epoch, shard_group) + } + + pub fn get_committee_info( + &self, + epoch: Epoch, + shard_group: ShardGroup, + ) -> Result { + let num_committees = self.get_number_of_committees(epoch)?; let mut tx = self.global_db.create_transaction()?; let mut validator_node_db = self.global_db.validator_nodes(&mut tx); let num_validators = validator_node_db.count_in_shard_group(epoch, shard_group)?; @@ -470,7 +478,7 @@ where TSpec: EpochManagerSpec // validators. This may change in the future if e.g. we introduce staking. let total_vote_power = VotePower::of(num_validators); let num_validators = u32::try_from(num_validators).map_err(|_| EpochManagerError::IntegerOverflow { - func: "get_committee_shard", + func: "get_committee_info", })?; Ok(CommitteeInfo::new( self.config.num_preshards, @@ -565,6 +573,31 @@ where TSpec: EpochManagerSpec Ok(()) } + + pub fn get_network_description(&self) -> Result { + let epoch = self.current_epoch(); + let num_committees = self.get_number_of_committees(epoch)?; + let shard_groups = self.config.num_preshards.all_shard_groups_iter(num_committees); + + let mut tx = self.global_db.create_transaction()?; + let mut validator_node_db = self.global_db.validator_nodes(&mut tx); + + let shard_groups = shard_groups + .map(|shard_group| { + let num_members = validator_node_db.count_in_shard_group(epoch, shard_group)?; + let num_members = u32::try_from(num_members).map_err(|_| EpochManagerError::IntegerOverflow { + func: "get_network_description", + })?; + Ok((shard_group, ShardGroupInfo { num_members })) + }) + .collect::>()?; + + Ok(NetworkDescription { + epoch, + shard_groups, + num_preshards: self.config.num_preshards, + }) + } } fn calculate_num_committees(num_vns: u64, committee_size: NonZeroU32) -> u32 { diff --git a/crates/epoch_manager/src/service/epoch_manager_service.rs b/crates/epoch_manager/src/service/epoch_manager_service.rs index 9f46405a46..749e263963 100644 --- a/crates/epoch_manager/src/service/epoch_manager_service.rs +++ b/crates/epoch_manager/src/service/epoch_manager_service.rs @@ -336,7 +336,7 @@ impl EpochManagerService { EpochManagerRequest::GetOurValidatorNode { epoch, reply } => { handle(reply, self.inner.get_our_validator_node(epoch), context) }, - EpochManagerRequest::GetCommitteeInfo { + EpochManagerRequest::GetCommitteeInfoForSubstate { epoch, substate_address, reply, @@ -348,6 +348,11 @@ impl EpochManagerService { EpochManagerRequest::GetLocalCommitteeInfo { epoch, reply } => { handle(reply, self.inner.get_local_committee_info(epoch), context) }, + EpochManagerRequest::GetCommitteeInfo { + epoch, + shard_group, + reply, + } => handle(reply, self.inner.get_committee_info(epoch, shard_group), context), EpochManagerRequest::GetNumCommittees { epoch, reply } => { handle(reply, self.inner.get_num_committees(epoch), context) }, @@ -389,6 +394,9 @@ impl EpochManagerService { .get_random_committee_member_from_shard_group(epoch, shard_group, excluding), context, ), + EpochManagerRequest::GetNetworkDescription { reply } => { + handle(reply, self.inner.get_network_description(), context) + }, } } } diff --git a/crates/epoch_manager/src/service/handle.rs b/crates/epoch_manager/src/service/handle.rs index fc30a8f840..1f0f71e491 100644 --- a/crates/epoch_manager/src/service/handle.rs +++ b/crates/epoch_manager/src/service/handle.rs @@ -22,7 +22,7 @@ use tokio::sync::{broadcast, mpsc, oneshot}; use crate::{ error::EpochManagerError, - service::types::EpochManagerRequest, + service::{types::EpochManagerRequest, NetworkDescription}, traits::{EpochManagerReader, EpochManagerWriter}, EpochManagerEvent, }; @@ -71,6 +71,16 @@ impl EpochManagerHandle { pub fn get_current_epoch(&self) -> Epoch { Epoch(self.current_epoch.load(std::sync::atomic::Ordering::SeqCst)) } + + pub async fn get_network_description(&self) -> Result { + let (tx, rx) = oneshot::channel(); + self.tx_request + .send(EpochManagerRequest::GetNetworkDescription { reply: tx }) + .await + .map_err(|_| EpochManagerError::SendError)?; + + rx.await.map_err(|_| EpochManagerError::ReceiveError)? + } } impl EpochManagerWriter for EpochManagerHandle { @@ -224,6 +234,24 @@ impl EpochManagerReader for EpochManagerHandle { rx.await.map_err(|_| EpochManagerError::ReceiveError)? } + async fn get_committee_info( + &self, + epoch: Epoch, + shard_group: ShardGroup, + ) -> Result { + let (tx, rx) = oneshot::channel(); + self.tx_request + .send(EpochManagerRequest::GetCommitteeInfo { + epoch, + shard_group, + reply: tx, + }) + .await + .map_err(|_| EpochManagerError::SendError)?; + + rx.await.map_err(|_| EpochManagerError::ReceiveError)? + } + async fn get_committee_info_for_substate( &self, epoch: Epoch, @@ -231,7 +259,7 @@ impl EpochManagerReader for EpochManagerHandle { ) -> Result { let (tx, rx) = oneshot::channel(); self.tx_request - .send(EpochManagerRequest::GetCommitteeInfo { + .send(EpochManagerRequest::GetCommitteeInfoForSubstate { epoch, substate_address, reply: tx, @@ -239,7 +267,7 @@ impl EpochManagerReader for EpochManagerHandle { .await .map_err(|_| EpochManagerError::SendError)?; - Ok(rx.await.map_err(|_| EpochManagerError::ReceiveError).unwrap().unwrap()) + rx.await.map_err(|_| EpochManagerError::ReceiveError)? } async fn get_committee_info_by_validator_address( diff --git a/crates/epoch_manager/src/service/mod.rs b/crates/epoch_manager/src/service/mod.rs index 04bad0664a..d1b0b2735b 100644 --- a/crates/epoch_manager/src/service/mod.rs +++ b/crates/epoch_manager/src/service/mod.rs @@ -7,10 +7,12 @@ mod epoch_manager_service; mod error; mod handle; mod initializer; +mod network_description; mod types; pub use config::EpochManagerConfig; pub use epoch_manager::EpochManager; pub use handle::EpochManagerHandle; pub use initializer::spawn_service; +pub use network_description::*; pub use types::*; diff --git a/crates/epoch_manager/src/service/network_description.rs b/crates/epoch_manager/src/service/network_description.rs new file mode 100644 index 0000000000..e5bdb5b0b2 --- /dev/null +++ b/crates/epoch_manager/src/service/network_description.rs @@ -0,0 +1,37 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use std::collections::BTreeMap; + +use tari_ootle_common_types::{Epoch, NumPreshards, ShardGroup}; + +#[derive(Debug, Clone)] +pub struct NetworkDescription { + pub epoch: Epoch, + /// Ordered map of shard groups and their information. + pub shard_groups: BTreeMap, + pub num_preshards: NumPreshards, +} + +impl NetworkDescription { + pub fn get_shard_group_info(&self, shard_group: &ShardGroup) -> Option<&ShardGroupInfo> { + self.shard_groups.get(shard_group) + } + + pub fn epoch(&self) -> Epoch { + self.epoch + } + + pub fn shard_groups_iter(&self) -> impl Iterator + '_ { + self.shard_groups.keys().copied() + } + + pub fn num_committees(&self) -> usize { + self.shard_groups.len() + } +} + +#[derive(Debug, Clone)] +pub struct ShardGroupInfo { + pub num_members: u32, +} diff --git a/crates/epoch_manager/src/service/types.rs b/crates/epoch_manager/src/service/types.rs index 3aebde9e59..98be944465 100644 --- a/crates/epoch_manager/src/service/types.rs +++ b/crates/epoch_manager/src/service/types.rs @@ -16,7 +16,7 @@ use tari_sidechain::EvictionProof; use tari_template_lib_types::crypto::RistrettoPublicKeyBytes; use tokio::sync::oneshot; -use crate::error::EpochManagerError; +use crate::{error::EpochManagerError, service::NetworkDescription}; type Reply = oneshot::Sender>; @@ -79,7 +79,7 @@ pub enum EpochManagerRequest { epoch: Epoch, reply: Reply>, }, - GetCommitteeInfo { + GetCommitteeInfoForSubstate { epoch: Epoch, substate_address: SubstateAddress, reply: Reply, @@ -88,6 +88,11 @@ pub enum EpochManagerRequest { epoch: Epoch, reply: Reply, }, + GetCommitteeInfo { + epoch: Epoch, + shard_group: ShardGroup, + reply: Reply, + }, GetNumCommittees { epoch: Epoch, reply: Reply, @@ -116,4 +121,7 @@ pub enum EpochManagerRequest { excluding: Vec, reply: Reply>, }, + GetNetworkDescription { + reply: Reply, + }, } diff --git a/crates/epoch_manager/src/traits.rs b/crates/epoch_manager/src/traits.rs index ade220092b..abc835a6d0 100644 --- a/crates/epoch_manager/src/traits.rs +++ b/crates/epoch_manager/src/traits.rs @@ -116,6 +116,12 @@ pub trait EpochManagerReader: Send + Sync { epoch: Epoch, ) -> impl Future> + Send; + fn get_committee_info( + &self, + epoch: Epoch, + shard_group: ShardGroup, + ) -> impl Future> + Send; + fn get_committee_info_for_substate( &self, epoch: Epoch, diff --git a/crates/p2p/proto/rpc.proto b/crates/p2p/proto/rpc.proto index 1f7e8f9984..8fdc8da86a 100644 --- a/crates/p2p/proto/rpc.proto +++ b/crates/p2p/proto/rpc.proto @@ -173,7 +173,7 @@ message SyncBlocksRequest { // Clippy complains about too many bools and prefers an enum enum StreamSubstateSelection { No = 0; - All = 1; + AllSubstates = 1; TransactionReceiptsOnly = 2; } @@ -194,12 +194,13 @@ message QuorumCertificates { repeated tari.ootle.consensus.QuorumCertificate quorum_certificates = 1; } -message GetCheckpointRequest { - uint64 epoch = 1; +message GetCheckpointsRequest { + tari.ootle.common.Epoch from_epoch = 1; + uint32 num_to_return = 2; } -message GetCheckpointResponse { - EpochCheckpoint checkpoint = 1; +message GetCheckpointsResponse { + repeated EpochCheckpoint checkpoints = 1; } message EpochCheckpoint { @@ -215,7 +216,31 @@ message TreeRootSummary { message SyncStateRequest { uint64 start_state_version = 1; uint32 shard = 2; - uint64 until_epoch = 3; + // Optional - If not provided, state will be streamed until the current epoch + tari.ootle.common.Epoch until_epoch = 3; + // Bitflags representing which substates to return. + // enum StateSyncValueFilterFlags { + // // Includes all substates + // None = 0; + // All = 0x0001; + // // Includes Components + // Component = 0x0002; + // // Includes resources + // Resource = 0x0004; + // // Includes vaults + // Vault = 0x0008; + // // Includes fungible and non-fungible assets + // NonFungible = 0x0010; + // // Includes transaction receipts + // TransactionReceipt = 0x0020; + // // Includes published template metadata + // Template = 0x0040; + // // Includes validator fee pool substates + // ValidatorFeePool = 0x0080; + // // Includes UTXOs + // Utxo = 0x0100; + //} + uint32 value_filters = 4; } message SyncStateResponse { @@ -240,4 +265,6 @@ message SyncTemplatesResponse { TemplateType template_type = 3; string template_name = 4; bytes binary = 5; -} \ No newline at end of file +} + +message GetChainSummary {} \ No newline at end of file diff --git a/crates/rpc_state_sync/src/state_sync.rs b/crates/rpc_state_sync/src/state_sync.rs index 35f230eee2..2b68c50b84 100644 --- a/crates/rpc_state_sync/src/state_sync.rs +++ b/crates/rpc_state_sync/src/state_sync.rs @@ -23,7 +23,7 @@ use tari_ootle_common_types::{ VersionedSubstateId, VotePower, }; -use tari_ootle_p2p::proto::rpc::{GetCheckpointRequest, GetCheckpointResponse, SyncStateRequest}; +use tari_ootle_p2p::proto::rpc::{GetCheckpointsRequest, GetCheckpointsResponse, SyncStateRequest}; use tari_ootle_storage::{ consensus_models::{ BookkeepingModel, @@ -33,6 +33,7 @@ use tari_ootle_storage::{ SubstateTransition, SubstateUpdateBatch, SubstateUpdateProof, + SubstateValueFilterFlags, }, StateStore, StateStoreReadTransaction, @@ -81,7 +82,7 @@ where TConsensusSpec: ConsensusSpec } async fn establish_rpc_session(&self, addr: &PeerAddress) -> Result { - let mut rpc_client = self.client_factory.create_client(addr); + let rpc_client = self.client_factory.create_client(addr); let client = rpc_client.client_connection().await?; Ok(client) } @@ -93,34 +94,39 @@ where TConsensusSpec: ConsensusSpec prev_committee: &Committee, prev_epoch: Epoch, ) -> Result, RpcStateSyncError> { - if let Some(cp) = self.valid_checkpoints.get(&for_shard_group) { + let valid_checkpoint = self + .state_store + .with_read_tx(|tx| EpochCheckpoint::get_by_shard_group(tx, prev_epoch, for_shard_group)) + .optional()?; + + if let Some(cp) = valid_checkpoint { info!(target: LOG_TARGET, "πŸ›œ Checkpoint already fetched and valid: {cp}"); - return Ok(Some(cp.clone())); + return Ok(Some(cp)); } self.stats.total_requests += 1; match client - .get_checkpoint(GetCheckpointRequest { - epoch: prev_epoch.as_u64(), + .get_checkpoints(GetCheckpointsRequest { + from_epoch: Some(prev_epoch.into()), + num_to_return: 1, }) .await { - Ok(GetCheckpointResponse { - checkpoint: Some(checkpoint), - }) => match EpochCheckpoint::try_from(checkpoint) { - Ok(checkpoint) => { - info!(target: LOG_TARGET, "πŸ›œ Checkpoint: {checkpoint}"); - self.validate_checkpoint(&checkpoint, prev_committee, prev_epoch)?; - self.state_store.with_write_tx(|tx| checkpoint.save(tx))?; - self.valid_checkpoints.insert(for_shard_group, checkpoint.clone()); - Ok(Some(checkpoint)) - }, - Err(err) => Err(RpcStateSyncError::InvalidResponse(err)), + Ok(GetCheckpointsResponse { checkpoints }) if checkpoints.is_empty() => Ok(None), + Ok(GetCheckpointsResponse { mut checkpoints }) => { + match EpochCheckpoint::try_from(checkpoints.pop().expect("checked is_empty")) { + Ok(checkpoint) => { + info!(target: LOG_TARGET, "πŸ›œ Checkpoint: {checkpoint}"); + self.validate_checkpoint(&checkpoint, prev_committee, prev_epoch)?; + self.state_store.with_write_tx(|tx| checkpoint.save(tx))?; + self.valid_checkpoints.insert(for_shard_group, checkpoint.clone()); + Ok(Some(checkpoint)) + }, + Err(err) => Err(RpcStateSyncError::InvalidResponse(err)), + } }, Err(RpcError::RequestFailed(err)) if err.is_not_found() => Ok(None), - Ok(GetCheckpointResponse { checkpoint: None }) => Ok(None), - Err(RpcError::RequestFailed(err)) if err.is_not_found() => Ok(None), Err(err) => Err(err.into()), } } @@ -158,7 +164,8 @@ where TConsensusSpec: ConsensusSpec .sync_state(SyncStateRequest { start_state_version, shard: shard.as_u32(), - until_epoch: checkpoint.epoch().as_u64(), + until_epoch: Some(checkpoint.epoch().into()), + value_filters: SubstateValueFilterFlags::all().bits(), }) .await?; @@ -225,7 +232,7 @@ where TConsensusSpec: ConsensusSpec info!(target: LOG_TARGET, "πŸ›œ Buffering {} state update(s) (state version: v{})", updates_for_state_version.len(), state_version); for result in updates_for_state_version { let update = result?; - let (tree_change, template_change) = extract_tree_change(msg_epoch, &update)?; + let (tree_change, template_change) = extract_tree_and_template_changes(msg_epoch, &update)?; debug!(target: LOG_TARGET, "πŸ›œ -> state update (v{}) {}", state_version, update); template_changes.extend(template_change); @@ -408,7 +415,7 @@ where TConsensusSpec: ConsensusSpec } /// Synchronizes the given [`Shard`]. - pub async fn sync_shard( + async fn sync_shard( &mut self, shard: Shard, shard_group: ShardGroup, @@ -439,8 +446,6 @@ where TConsensusSpec: ConsensusSpec }; // fetch checkpoint - // TODO: NB refactor to fetch the checkpoint once for the shard group - instead of for each shard and each - // attempt - once it's validated, there is no need to fetch it again let prev_epoch = epoch .checked_sub(Epoch(1)) .ok_or_else(|| RpcStateSyncError::InvalidResponse(anyhow!("Epoch is zero")))?; @@ -453,7 +458,8 @@ where TConsensusSpec: ConsensusSpec // TODO: we should check with f + 1 validators in this case. If a single validator reports // this falsely, this will prevent us from continuing with consensus for a long time (state // root will mismatch). - // TODO: we should instead ask the epoch manager if this is the first epoch in the network + // TODO: we should instead ask the epoch manager if this is the first epoch in the network (NOTE: + // first epoch is not 0 but the first epoch where validators become active). warn!( target: LOG_TARGET, "❓No checkpoint for epoch {epoch}. This may mean that this is the first epoch in the network" @@ -516,6 +522,9 @@ where TConsensusSpec: ConsensusSpec let mut last_error = None; for (sg, prev_committee) in prev_committees { + // TODO: any checkpoint for the previous epoch will justify the global shard sync. + // Currently we'll fetch the checkpoint again even if we already have it if there are more than one + // shard groups. let result = self .sync_shard( Shard::global(), @@ -684,7 +693,7 @@ fn extract_template_change( } } -fn extract_tree_change( +fn extract_tree_and_template_changes( epoch: Epoch, update: &SubstateUpdateProof, ) -> Result<(SubstateTreeChange, Option), RpcStateSyncError> { diff --git a/crates/state_store_rocksdb/src/codecs/bincode.rs b/crates/state_store_rocksdb/src/codecs/bincode.rs index 5b947e5347..7d5200ff4a 100644 --- a/crates/state_store_rocksdb/src/codecs/bincode.rs +++ b/crates/state_store_rocksdb/src/codecs/bincode.rs @@ -1,12 +1,24 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use std::io::Read; + +use anyhow::anyhow; +use serde::Serialize; + use crate::{ codecs::{DbCodec, EncodeVec}, error::RocksDbStorageError, - utils::{bincode_decode, bincode_encode}, }; +const BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard(); + +fn bincode_encode(value: &T) -> Result, RocksDbStorageError> { + let bytes = bincode::serde::encode_to_vec(value, BINCODE_CONFIG) + .map_err(|e| RocksDbStorageError::EncodeError { source: e.into() })?; + Ok(bytes) +} + #[derive(Debug, Clone, Copy)] pub struct Bincode { _phantom: std::marker::PhantomData, @@ -24,13 +36,18 @@ impl DbCodec for Bincode where T: serde::Serialize + serde::de::DeserializeOwned { fn encode(&self, value: &T) -> Result { - let buf = bincode_encode(value)?; - Ok(buf.into()) + let bytes = bincode_encode(value)?; + Ok(bytes.into()) } - fn decode(&self, bytes: &[u8]) -> Result { - let ret = bincode_decode(bytes)?; - Ok(ret) + fn decode_reader(&self, reader: &mut R) -> Result { + bincode::serde::decode_from_std_read(reader, BINCODE_CONFIG).map_err(|e| RocksDbStorageError::DecodeError { + source: anyhow!( + "Bincode deserialization failed for type:{}: {}", + std::any::type_name::(), + e, + ), + }) } } @@ -61,8 +78,8 @@ where T: serde::Serialize Ok(buf.into()) } - fn decode(&self, _bytes: &[u8]) -> Result { - panic!("BincodeRef::decode() is not supported. You likely need to use the Bincode codec instead."); + fn decode_reader(&self, _reader: &mut R) -> Result { + panic!("BincodeRef::decode_reader() is not supported. You likely need to use the Bincode codec instead."); } } diff --git a/crates/state_store_rocksdb/src/codecs/block_diff.rs b/crates/state_store_rocksdb/src/codecs/block_diff.rs index 3b81b54fef..4d703113f7 100644 --- a/crates/state_store_rocksdb/src/codecs/block_diff.rs +++ b/crates/state_store_rocksdb/src/codecs/block_diff.rs @@ -1,6 +1,8 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use std::io::Read; + use anyhow::anyhow; use tari_common_types::types::FixedHash; use tari_consensus_types::BlockId; @@ -38,32 +40,19 @@ impl DbCodec for BlockDiffKeyCodec { ])) } - fn decode(&self, mut bytes: &[u8]) -> Result { - let reader = &mut bytes; + fn decode_reader(&self, reader: &mut R) -> Result { let block_id = FixedHash::new(read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!( - "BlockIdSubstateIdVersionCodec: Invalid bytes len={} for FixedHash", - reader.len() - ), + source: anyhow!("BlockIdSubstateIdVersionCodec: Invalid bytes for FixedHash",), })?); let sequence = u32::from_be_bytes(read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!( - "BlockIdSubstateIdVersionCodec: not enough bytes for sequence, remaining={}", - reader.len() - ), + source: anyhow!("BlockIdSubstateIdVersionCodec: not enough bytes for sequence"), })?); let substate_id = self.substate_id_codec.decode_reader(reader)?; let version = u32::from_be_bytes(read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!( - "BlockIdSubstateIdVersionCodec: Invalid bytes len={} for u32", - reader.len() - ), + source: anyhow!("BlockIdSubstateIdVersionCodec: Invalid bytes for u32",), })?); let is_up: [u8; 1] = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!( - "BlockIdSubstateIdVersionCodec: not enough bytes for bool, remaining={}", - reader.len() - ), + source: anyhow!("BlockIdSubstateIdVersionCodec: not enough bytes for bool",), })?; Ok(BlockDiffKey { @@ -92,29 +81,19 @@ impl DbCodec for BlockDiffKeyCodec { ])) } - fn decode(&self, mut bytes: &[u8]) -> Result { - let reader = &mut bytes; + fn decode_reader(&self, reader: &mut R) -> Result { let substate_id = self.substate_id_codec.decode_reader(reader)?; let block_id = FixedHash::new(read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { source: anyhow!("BlockIdSubstateIdVersionCodec: Invalid bytes for FixedHash",), })?); let version = u32::from_be_bytes(read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!( - "BlockIdSubstateIdVersionCodec: Invalid bytes len={} for u32", - reader.len() - ), + source: anyhow!("BlockIdSubstateIdVersionCodec: Invalid bytes for u32",), })?); let is_up: [u8; 1] = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!( - "BlockIdSubstateIdVersionCodec: not enough bytes for bool, remaining={}", - reader.len() - ), + source: anyhow!("BlockIdSubstateIdVersionCodec: not enough bytes for bool"), })?; let sequence = u32::from_be_bytes(read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!( - "BlockIdSubstateIdVersionCodec: not enough bytes for sequence, remaining={}", - reader.len() - ), + source: anyhow!("BlockIdSubstateIdVersionCodec: not enough bytes for sequence",), })?); Ok(BlockDiffKey { block_id: BlockId::from(block_id), diff --git a/crates/state_store_rocksdb/src/codecs/bytes.rs b/crates/state_store_rocksdb/src/codecs/bytes.rs index fa45a6c259..b8f21b000b 100644 --- a/crates/state_store_rocksdb/src/codecs/bytes.rs +++ b/crates/state_store_rocksdb/src/codecs/bytes.rs @@ -1,7 +1,7 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use std::any::type_name; +use std::{any::type_name, io::Read}; use anyhow::anyhow; @@ -11,7 +11,8 @@ use crate::{ utils::read_to_fixed, }; -/// NOTE: you cannot use this codec with prefixes unless T::try_from(bytes) does not error with excess bytes. +/// NOTE: you cannot use this codec with prefixes since it uses the entire reader to decode the bytes. +/// Use FixedBytesCodec for this case. #[derive(Default)] pub struct BytesCodec; @@ -25,8 +26,15 @@ where Ok(EncodeVec::from_slice(value.as_ref())) } - fn decode(&self, bytes: &[u8]) -> Result { - let ret = T::try_from(bytes).map_err(|e| RocksDbStorageError::DecodeError { + fn decode_reader(&self, reader: &mut R) -> Result { + let mut bytes = Vec::new(); + reader + .read_to_end(&mut bytes) + .map_err(|e| RocksDbStorageError::MalformedData { + operation: "decode bytes", + details: format!("Failed to read bytes for BytesCodec: {e}"), + })?; + let ret = T::try_from(bytes.as_slice()).map_err(|e| RocksDbStorageError::DecodeError { source: anyhow!("{}: {}", type_name::(), e), })?; Ok(ret) @@ -48,9 +56,9 @@ where Ok(EncodeVec::from_slice(value.as_ref())) } - fn decode(&self, mut bytes: &[u8]) -> Result { - let fixed = read_to_fixed(&mut bytes).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!("FixedBytesCodec: Expected {} bytes, got {}", LEN, bytes.len()), + fn decode_reader(&self, reader: &mut R) -> Result { + let fixed = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { + source: anyhow!("FixedBytesCodec: Expected {} bytes", LEN), })?; let ret = T::from(fixed); Ok(ret) diff --git a/crates/state_store_rocksdb/src/codecs/column.rs b/crates/state_store_rocksdb/src/codecs/column.rs index c7bb25fa1a..cd1887d71d 100644 --- a/crates/state_store_rocksdb/src/codecs/column.rs +++ b/crates/state_store_rocksdb/src/codecs/column.rs @@ -1,18 +1,16 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use std::{fmt, fmt::Display}; +use std::{fmt, fmt::Display, io::Read}; use anyhow::anyhow; -use tari_ootle_common_types::displayable::Displayable; use crate::{ codecs::{DbCodec, EncodeVec}, error::RocksDbStorageError, + utils::read_to_fixed, }; -const SZ_OF_U32: usize = size_of::(); - /// A const key used to differentiate "columns" in a reused column family. /// This hard codes 32 bytes (big-endian) from the encoded bytes. /// It is not recommended to use this on a shared column family that uses prefix lookups, as the codec used would need @@ -48,20 +46,17 @@ impl DbCodec> for ColumnCodec { Ok(EncodeVec::new_from_array(COL.to_be_bytes())) } - fn decode(&self, bytes: &[u8]) -> Result, RocksDbStorageError> { - if bytes.len() < SZ_OF_U32 { - return Err(RocksDbStorageError::DecodeError { - source: anyhow!("Invalid bytes len={} for ColumnCodec", bytes.len()), - }); - } - let col_bytes = bytes.get(..SZ_OF_U32).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!("Invalid bytes len={} for ColumnCodec", bytes.len()), + fn decode_reader(&self, reader: &mut R) -> Result, RocksDbStorageError> { + let arr = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { + source: anyhow!("Invalid bytes for ColumnCodec"), })?; - if col_bytes != COL.to_be_bytes() { + + let col = u32::from_be_bytes(arr); + if col != COL { return Err(RocksDbStorageError::DecodeError { source: anyhow!( - "Invalid column bytes '{}', ColumnCodec expected big-endian bytes for '{}'", - col_bytes.display(), + "Invalid column '{}', ColumnCodec expected big-endian bytes for '{}'", + col, COL ), }); @@ -75,17 +70,20 @@ impl DbCodec> for ColumnCodec { Ok(EncodeVec::new_from_array([COL])) } - fn decode(&self, bytes: &[u8]) -> Result, RocksDbStorageError> { - let Some(first_byte) = bytes.first() else { - return Err(RocksDbStorageError::DecodeError { - source: anyhow!("Invalid bytes len={} for ColumnCodec", bytes.len()), - }); - }; - if *first_byte != COL { + fn decode_reader(&self, reader: &mut R) -> Result, RocksDbStorageError> { + let mut buf = [0u8; 1]; + reader + .read_exact(&mut buf) + .map_err(|e| RocksDbStorageError::MalformedData { + operation: "decode ByteColumn", + details: format!("Failed to read 1 byte for ColumnCodec: {e}"), + })?; + + if buf[0] != COL { return Err(RocksDbStorageError::DecodeError { source: anyhow!( "Invalid byte column bytes '{}', ColumnCodec expected byte '{}'", - first_byte, + buf[0], COL ), }); diff --git a/crates/state_store_rocksdb/src/codecs/misc.rs b/crates/state_store_rocksdb/src/codecs/misc.rs index 6daf6a0754..ab7910c406 100644 --- a/crates/state_store_rocksdb/src/codecs/misc.rs +++ b/crates/state_store_rocksdb/src/codecs/misc.rs @@ -1,6 +1,8 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use std::io::Read; + use tari_ootle_common_types::{shard::Shard, Epoch, NodeHeight}; use crate::{ @@ -17,7 +19,7 @@ impl DbCodec<()> for UnitCodec { Ok(EncodeVec::empty()) } - fn decode(&self, _: &[u8]) -> Result<(), RocksDbStorageError> { + fn decode_reader(&self, _reader: &mut R) -> Result<(), RocksDbStorageError> { Ok(()) } } @@ -30,14 +32,15 @@ impl DbCodec for BoolCodec { Ok(EncodeVec::new_from_array([u8::from(*value)])) } - fn decode(&self, bytes: &[u8]) -> Result { - let Some(first_byte) = bytes.first() else { - return Err(RocksDbStorageError::MalformedData { - operation: "decode bool", - details: "Empty bytes".to_string(), - }); - }; - Ok(*first_byte != 0) + fn decode_reader(&self, reader: &mut R) -> Result { + let mut buf = [0u8; 1]; + reader + .read_exact(&mut buf) + .map_err(|e| RocksDbStorageError::MalformedData { + operation: "decode u8", + details: format!("Failed to read 1 byte for BoolCodec: {e}"), + })?; + Ok(buf[0] != 0) } } @@ -55,14 +58,15 @@ impl DbCodec for NumberCodec { Ok(EncodeVec::new_from_array([*value])) } - fn decode(&self, bytes: &[u8]) -> Result { - let Some(first_byte) = bytes.first() else { - return Err(RocksDbStorageError::MalformedData { + fn decode_reader(&self, reader: &mut R) -> Result { + let mut buf = [0u8; 1]; + reader + .read_exact(&mut buf) + .map_err(|e| RocksDbStorageError::MalformedData { operation: "decode u8", - details: "Empty bytes".to_string(), - }); - }; - Ok(*first_byte) + details: format!("Failed to read 1 byte for NumberCodec: {e}"), + })?; + Ok(buf[0]) } } @@ -71,12 +75,12 @@ impl DbCodec for NumberCodec { Ok(EncodeVec::new_from_array(value.to_be_bytes())) } - fn decode(&self, mut bytes: &[u8]) -> Result { - let buf = read_to_fixed(&mut bytes).ok_or_else(|| RocksDbStorageError::MalformedData { + fn decode_reader(&self, reader: &mut R) -> Result { + let arr = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::MalformedData { operation: "decode u32", - details: format!("Invalid bytes size {} for NumberCodec", bytes.len()), + details: "Invalid bytes size for NumberCodec".to_string(), })?; - Ok(u32::from_be_bytes(buf)) + Ok(u32::from_be_bytes(arr)) } } @@ -85,12 +89,12 @@ impl DbCodec for NumberCodec { Ok(EncodeVec::new_from_array(value.to_be_bytes())) } - fn decode(&self, mut bytes: &[u8]) -> Result { - let buf = read_to_fixed(&mut bytes).ok_or_else(|| RocksDbStorageError::MalformedData { + fn decode_reader(&self, reader: &mut R) -> Result { + let arr = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::MalformedData { operation: "decode u64", - details: format!("Invalid bytes size {} for NumberCodec", bytes.len()), + details: "Invalid bytes size for NumberCodec".to_string(), })?; - Ok(u64::from_be_bytes(buf)) + Ok(u64::from_be_bytes(arr)) } } @@ -99,10 +103,10 @@ impl DbCodec for NumberCodec { Ok(EncodeVec::new_from_array(epoch.to_be_bytes())) } - fn decode(&self, mut bytes: &[u8]) -> Result { - let arr = read_to_fixed(&mut bytes).ok_or_else(|| RocksDbStorageError::MalformedData { + fn decode_reader(&self, reader: &mut R) -> Result { + let arr = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::MalformedData { operation: "decode Epoch", - details: format!("Invalid bytes size {} for EpochCodec", bytes.len()), + details: "Invalid bytes size for NumberCodec".to_string(), })?; let epoch = u64::from_be_bytes(arr); Ok(Epoch(epoch)) @@ -114,12 +118,13 @@ impl DbCodec for NumberCodec { Ok(EncodeVec::new_from_array(value.as_u64().to_be_bytes())) } - fn decode(&self, mut bytes: &[u8]) -> Result { - let buf = read_to_fixed(&mut bytes).ok_or_else(|| RocksDbStorageError::MalformedData { + fn decode_reader(&self, reader: &mut R) -> Result { + let arr = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::MalformedData { operation: "decode NodeHeight", - details: format!("Invalid bytes size {} for NumberCodec", bytes.len()), + details: "Invalid bytes size for NumberCodec".to_string(), })?; - Ok(NodeHeight::from(u64::from_be_bytes(buf))) + let height = u64::from_be_bytes(arr); + Ok(NodeHeight::from(height)) } } @@ -128,10 +133,10 @@ impl DbCodec for NumberCodec { Ok(EncodeVec::new_from_array(shard.as_u32().to_be_bytes())) } - fn decode(&self, mut bytes: &[u8]) -> Result { - let arr = read_to_fixed(&mut bytes).ok_or_else(|| RocksDbStorageError::MalformedData { + fn decode_reader(&self, reader: &mut R) -> Result { + let arr = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::MalformedData { operation: "decode Shard", - details: format!("Invalid bytes size {} for ShardCodec", bytes.len()), + details: "Invalid bytes size for NumberCodec".to_string(), })?; let shard = u32::from_be_bytes(arr); Ok(shard.into()) diff --git a/crates/state_store_rocksdb/src/codecs/mod.rs b/crates/state_store_rocksdb/src/codecs/mod.rs index 652d605334..03ab40d14c 100644 --- a/crates/state_store_rocksdb/src/codecs/mod.rs +++ b/crates/state_store_rocksdb/src/codecs/mod.rs @@ -7,6 +7,7 @@ mod bytes; mod column; mod misc; mod public_key; +mod shard_group; mod small_bytes; mod state_tree; mod substate_id; @@ -14,16 +15,18 @@ mod substate_lock; mod tuple; mod versioned; +use std::io; + pub use bincode::*; pub use block_diff::*; pub use bytes::*; pub use column::*; pub use misc::*; pub use public_key::*; +pub use shard_group::ShardGroupCodec; pub use state_tree::*; pub use substate_id::*; pub use substate_lock::*; -pub use tuple::*; pub use versioned::*; use crate::error::RocksDbStorageError; @@ -33,8 +36,12 @@ pub type EncodeVec = small_bytes::SmallBytes<100>; pub trait DbCodec { fn encode(&self, value: &T) -> Result; + fn decode(&self, bytes: &[u8]) -> Result { + let reader = &mut &bytes[..]; + self.decode_reader(reader) + } - fn decode(&self, bytes: &[u8]) -> Result; + fn decode_reader(&self, reader: &mut R) -> Result; } pub type DefaultCodec = Bincode; diff --git a/crates/state_store_rocksdb/src/codecs/public_key.rs b/crates/state_store_rocksdb/src/codecs/public_key.rs index 0b2ac9b159..4a0b57d039 100644 --- a/crates/state_store_rocksdb/src/codecs/public_key.rs +++ b/crates/state_store_rocksdb/src/codecs/public_key.rs @@ -1,25 +1,26 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use anyhow::anyhow; +use std::io::Read; + use tari_template_lib_types::crypto::RistrettoPublicKeyBytes; use crate::{ - codecs::{DbCodec, EncodeVec}, + codecs::{DbCodec, EncodeVec, FixedBytesCodec}, error::RocksDbStorageError, }; #[derive(Debug, Clone, Copy, Default)] -pub struct PublicKeyCodec; +pub struct PublicKeyCodec { + inner: FixedBytesCodec<{ RistrettoPublicKeyBytes::length() }>, +} impl DbCodec for PublicKeyCodec { fn encode(&self, value: &RistrettoPublicKeyBytes) -> Result { - Ok(EncodeVec::from_slice(value.as_bytes())) + self.inner.encode(value) } - fn decode(&self, bytes: &[u8]) -> Result { - RistrettoPublicKeyBytes::from_bytes(bytes).map_err(|e| RocksDbStorageError::DecodeError { - source: anyhow!("RistrettoPublicKeyBytes: {}", e), - }) + fn decode_reader(&self, reader: &mut R) -> Result { + self.inner.decode_reader(reader) } } diff --git a/crates/state_store_rocksdb/src/codecs/shard_group.rs b/crates/state_store_rocksdb/src/codecs/shard_group.rs new file mode 100644 index 0000000000..709d405a07 --- /dev/null +++ b/crates/state_store_rocksdb/src/codecs/shard_group.rs @@ -0,0 +1,30 @@ +// Copyright 2025 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use std::io::Read; + +use tari_ootle_common_types::ShardGroup; + +use crate::{ + codecs::{DbCodec, EncodeVec, ShardCodec}, + error::RocksDbStorageError, +}; + +#[derive(Debug, Clone, Copy, Default)] +pub struct ShardGroupCodec { + inner: ShardCodec, +} + +impl DbCodec for ShardGroupCodec { + fn encode(&self, value: &ShardGroup) -> Result { + let start = self.inner.encode(&value.start())?; + let end = self.inner.encode(&value.end())?; + Ok(EncodeVec::from_slices(&[start.as_slice(), end.as_slice()])) + } + + fn decode_reader(&self, reader: &mut R) -> Result { + let start = self.inner.decode_reader(reader)?; + let end = self.inner.decode_reader(reader)?; + Ok(ShardGroup::new(start, end)) + } +} diff --git a/crates/state_store_rocksdb/src/codecs/state_tree.rs b/crates/state_store_rocksdb/src/codecs/state_tree.rs index 4daafd5b66..48dd7cf22e 100644 --- a/crates/state_store_rocksdb/src/codecs/state_tree.rs +++ b/crates/state_store_rocksdb/src/codecs/state_tree.rs @@ -1,6 +1,8 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use std::io::Read; + use anyhow::anyhow; use tari_state_tree::{NibblePath, NodeKey, Version}; @@ -35,8 +37,7 @@ impl DbCodec for NodeKeyCodec { self.encode_node_key(key) } - fn decode(&self, mut bytes: &[u8]) -> Result { - let reader = &mut bytes; + fn decode_reader(&self, reader: &mut R) -> Result { let buf = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { source: anyhow!("Invalid version bytes"), })?; @@ -73,7 +74,7 @@ impl<'a> DbCodec<&'a NodeKey> for NodeKeyCodec { self.encode_node_key(key) } - fn decode(&self, _bytes: &[u8]) -> Result<&'a NodeKey, RocksDbStorageError> { + fn decode_reader(&self, _reader: &mut R) -> Result<&'a NodeKey, RocksDbStorageError> { unreachable!("decode should not be called on NodeKeyCodec with a reference") } } diff --git a/crates/state_store_rocksdb/src/codecs/substate_id.rs b/crates/state_store_rocksdb/src/codecs/substate_id.rs index 3848b5f9d0..76510071df 100644 --- a/crates/state_store_rocksdb/src/codecs/substate_id.rs +++ b/crates/state_store_rocksdb/src/codecs/substate_id.rs @@ -1,7 +1,7 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use std::io; +use std::io::Read; use borsh::BorshDeserialize; use tari_engine_types::substate::SubstateId; @@ -27,12 +27,6 @@ impl SubstateIdCodec { let buf = borsh::to_vec(value).map_err(|e| RocksDbStorageError::EncodeError { source: e.into() })?; Ok(EncodeVec::new_heap(buf)) } - - pub fn decode_reader(self, reader: &mut R) -> Result { - // We use the deserialize_reader here so that no error is returned if there are extra bytes in the buffer - // in order to use SubstateId as a prefix - SubstateId::deserialize_reader(reader).map_err(|e| RocksDbStorageError::DecodeError { source: e.into() }) - } } impl DbCodec for SubstateIdCodec { @@ -40,8 +34,10 @@ impl DbCodec for SubstateIdCodec { self.encode_substate_id(value) } - fn decode(&self, mut bytes: &[u8]) -> Result { - self.decode_reader(&mut bytes) + fn decode_reader(&self, reader: &mut R) -> Result { + // We use the deserialize_reader here so that no error is returned if there are extra bytes in the buffer + // in order to use SubstateId as a prefix + SubstateId::deserialize_reader(reader).map_err(|e| RocksDbStorageError::DecodeError { source: e.into() }) } } @@ -50,8 +46,8 @@ impl<'a> DbCodec<&'a SubstateId> for SubstateIdCodec { SubstateIdCodec.encode(*value) } - fn decode(&self, _bytes: &[u8]) -> Result<&'a SubstateId, RocksDbStorageError> { - panic!("Attempt to decode a reference to a SubstateId which is not possible.") + fn decode_reader(&self, _reader: &mut R) -> Result<&'a SubstateId, RocksDbStorageError> { + unimplemented!("Decoding a reference to a SubstateId is not supported. Use decode_reader for owned values."); } } @@ -65,8 +61,8 @@ impl<'a> DbCodec> for SubstateIdCodec { ])) } - fn decode(&self, _bytes: &[u8]) -> Result, RocksDbStorageError> { - panic!("Attempt to decode a reference to a VersionedSubstateIdRef which is not possible.") + fn decode_reader(&self, _reader: &mut R) -> Result, RocksDbStorageError> { + unreachable!("Decoding a VersionedSubstateIdRef is not supported. Use decode_reader for owned values."); } } diff --git a/crates/state_store_rocksdb/src/codecs/substate_lock.rs b/crates/state_store_rocksdb/src/codecs/substate_lock.rs index 4e03ae351b..7f5b43cc6d 100644 --- a/crates/state_store_rocksdb/src/codecs/substate_lock.rs +++ b/crates/state_store_rocksdb/src/codecs/substate_lock.rs @@ -1,6 +1,8 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use std::io::Read; + use anyhow::anyhow; use tari_common_types::types::FixedHash; use tari_consensus_types::BlockId; @@ -21,31 +23,31 @@ pub struct SubstateLockKeyCodec { } impl SubstateLockKeyCodec { - fn decode_transaction_id(&self, reader: &mut &[u8]) -> Result { + fn decode_transaction_id(&self, reader: &mut R) -> Result { let buf = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!("SubstateLockKeyCodec: Invalid bytes len={} for FixedHash", reader.len()), + source: anyhow!("SubstateLockKeyCodec: Invalid bytes for FixedHash"), })?; Ok(TransactionId::new(buf)) } - fn decode_block_id(&self, reader: &mut &[u8]) -> Result { + fn decode_block_id(&self, reader: &mut R) -> Result { let buf = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!("SubstateLockKeyCodec: Invalid bytes len={} for FixedHash", reader.len()), + source: anyhow!("SubstateLockKeyCodec: Invalid bytes for FixedHash"), })?; Ok(BlockId::new(FixedHash::new(buf))) } - fn decode_substate_id(&self, reader: &mut &[u8]) -> Result { - let substate_id = self.substate_id_codec.decode_reader(reader)?; - Ok(substate_id) + fn decode_substate_id(&self, reader: &mut R) -> Result { + self.substate_id_codec + .decode_reader(reader) + .map_err(|e| RocksDbStorageError::DecodeError { + source: anyhow!("SubstateLockKeyCodec: Failed to decode SubstateId: {}", e), + }) } - fn decode_block_height(&self, reader: &mut &[u8]) -> Result { + fn decode_block_height(&self, reader: &mut R) -> Result { let height = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!( - "SubstateLockKeyCodec: Invalid bytes len={} for NodeHeight", - reader.len() - ), + source: anyhow!("SubstateLockKeyCodec: Invalid bytes for NodeHeight"), })?; Ok(NodeHeight(u64::from_be_bytes(height))) } @@ -65,8 +67,7 @@ impl DbCodec for SubstateLockKeyCodec<(TransactionId, SubstateI ])) } - fn decode(&self, mut bytes: &[u8]) -> Result { - let reader = &mut bytes; + fn decode_reader(&self, reader: &mut R) -> Result { let transaction_id = self.decode_transaction_id(reader)?; let substate_id = self.decode_substate_id(reader)?; let block_id = self.decode_block_id(reader)?; @@ -94,8 +95,7 @@ impl DbCodec for SubstateLockKeyCodec<(BlockId, SubstateId, Tra ])) } - fn decode(&self, mut bytes: &[u8]) -> Result { - let reader = &mut bytes; + fn decode_reader(&self, reader: &mut R) -> Result { let block_id = self.decode_block_id(reader)?; let substate_id = self.decode_substate_id(reader)?; let transaction_id = self.decode_transaction_id(reader)?; @@ -124,8 +124,7 @@ impl DbCodec for SubstateLockKeyCodec<(SubstateId, TransactionI ])) } - fn decode(&self, mut bytes: &[u8]) -> Result { - let reader = &mut bytes; + fn decode_reader(&self, reader: &mut R) -> Result { let substate_id = self.decode_substate_id(reader)?; let transaction_id = self.decode_transaction_id(reader)?; let block_id = self.decode_block_id(reader)?; diff --git a/crates/state_store_rocksdb/src/codecs/substate_transaction_index.rs b/crates/state_store_rocksdb/src/codecs/substate_transaction_index.rs deleted file mode 100644 index f2e35d8520..0000000000 --- a/crates/state_store_rocksdb/src/codecs/substate_transaction_index.rs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2025 The Tari Project -// SPDX-License-Identifier: BSD-3-Clause - -use anyhow::anyhow; -use tari_engine_types::substate::SubstateId; -use tari_ootle_common_types::VersionedSubstateId; -use tari_transaction::TransactionId; - -use crate::{ - codecs::{DbCodec, EncodeVec, SubstateIdCodec}, - error::RocksDbStorageError, - model::substate::SubstateTransactionIndexKey, - utils::read_to_fixed, -}; - -#[derive(Default)] -pub struct SubstateTransactionKeyCodec { - substate_id_codec: SubstateIdCodec, -} - -impl SubstateTransactionKeyCodec { - fn decode_transaction_id(&self, reader: &mut &[u8]) -> Result { - let buf = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!( - "SubstateTransactionIndexCodec: Invalid bytes len={} for FixedHash", - reader.len() - ), - })?; - Ok(TransactionId::new(buf)) - } - - fn decode_bool(&self, reader: &mut &[u8]) -> Result { - if reader.is_empty() { - return Err(RocksDbStorageError::MalformedData { - operation: "decode bool", - details: "Empty bytes".to_string(), - }); - } - let b = reader[0] != 0; - *reader = &reader[1..]; - Ok(b) - } - - fn decode_u32(&self, reader: &mut &[u8]) -> Result { - let bytes = read_to_fixed(reader).ok_or_else(|| RocksDbStorageError::DecodeError { - source: anyhow!( - "SubstateTransactionIndexCodec: Invalid bytes len={} for u32", - reader.len() - ), - })?; - Ok(u32::from_be_bytes(bytes)) - } - - fn decode_substate_id(&self, reader: &mut &[u8]) -> Result { - let substate_id = self.substate_id_codec.decode_reader(reader)?; - Ok(substate_id) - } -} - -impl DbCodec for SubstateTransactionKeyCodec { - fn encode(&self, value: &SubstateTransactionIndexKey) -> Result { - let tx_id_bytes = value.transaction_id.as_bytes(); - let substate_id_bytes = self - .substate_id_codec - .encode(value.versioned_substate_id.substate_id())?; - let version_bytes = value.versioned_substate_id.version().to_be_bytes(); - let bool_bytes = [u8::from(value.is_up)]; - Ok(EncodeVec::from_slices(&[ - tx_id_bytes, - &substate_id_bytes, - &version_bytes, - &bool_bytes, - ])) - } - - fn decode(&self, mut bytes: &[u8]) -> Result { - let reader = &mut bytes; - let transaction_id = self.decode_transaction_id(reader)?; - let substate_id = self.decode_substate_id(reader)?; - let version = self.decode_u32(reader)?; - let versioned_substate_id = VersionedSubstateId::new(substate_id, version); - let is_up = self.decode_bool(reader)?; - Ok(SubstateTransactionIndexKey { - is_up, - versioned_substate_id, - transaction_id, - }) - } -} - -#[cfg(test)] -mod tests { - use tari_engine_types::template_models::{ComponentAddress, ObjectKey}; - - use super::*; - - fn create_substate_id(seed: u8) -> SubstateId { - SubstateId::Component(ComponentAddress::from_array([seed; ObjectKey::LENGTH])) - } - - #[test] - fn encode_decode() { - let codec = SubstateTransactionKeyCodec::default(); - let key = SubstateTransactionIndexKey { - is_up: true, - versioned_substate_id: VersionedSubstateId::new(create_substate_id(1), 1), - transaction_id: TransactionId::default(), - }; - let encoded = codec.encode(&key).unwrap(); - let decoded = codec.decode(&encoded).unwrap(); - assert_eq!(key.versioned_substate_id, decoded.versioned_substate_id); - assert_eq!(key.transaction_id, decoded.transaction_id); - assert_eq!(key.is_up, decoded.is_up); - } -} diff --git a/crates/state_store_rocksdb/src/codecs/tuple.rs b/crates/state_store_rocksdb/src/codecs/tuple.rs index 98583df4d9..441acd08ec 100644 --- a/crates/state_store_rocksdb/src/codecs/tuple.rs +++ b/crates/state_store_rocksdb/src/codecs/tuple.rs @@ -1,104 +1,18 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use anyhow::anyhow; -use tari_consensus_types::BlockId; -use tari_ootle_common_types::{shard::Shard, Epoch, NodeHeight}; -use tari_ootle_storage::consensus_models::ForeignProposalStatus; -use tari_template_lib_types::crypto::RistrettoPublicKeyBytes; -use tari_transaction::TransactionId; +use std::io::Read; use crate::{ - codecs::{Column, DbCodec, EncodeVec}, + codecs::{DbCodec, EncodeVec}, error::RocksDbStorageError, }; -/// A codec for encoding and decoding a tuple of two types that own a byte slice. These types must implement -/// `AsRef<[u8]>` and `TryFrom<&[u8]>`. -#[derive(Debug, Clone, Copy)] -pub struct TupleBytesCodec { - _phantom: std::marker::PhantomData, -} - -impl DbCodec<(A, B)> for TupleBytesCodec<(A, B)> -where - A: Clone + serde::Serialize + serde::de::DeserializeOwned, - A: AsRef<[u8]> + FixedByteLength, - for<'a> A: TryFrom<&'a [u8]>, - for<'a> >::Error: std::error::Error, - B: AsRef<[u8]>, - for<'b> B: TryFrom<&'b [u8]>, - for<'b> >::Error: std::error::Error, -{ - fn encode(&self, (a, b): &(A, B)) -> Result { - let a_bytes = a.as_ref(); - let b_bytes = b.as_ref(); - Ok(EncodeVec::from_slices(&[a_bytes, b_bytes])) - } - - fn decode(&self, bytes: &[u8]) -> Result<(A, B), RocksDbStorageError> { - let (a_bytes, b_bytes) = bytes.split_at(A::BYTE_LENGTH); - let a = A::try_from(a_bytes).map_err(|e| RocksDbStorageError::DecodeError { - source: anyhow!("{}", e), - })?; - let b = B::try_from(b_bytes).map_err(|e| RocksDbStorageError::DecodeError { - source: anyhow!("{}", e), - })?; - Ok((a, b)) - } -} - -impl DbCodec<(A, B, C)> for TupleBytesCodec<(A, B, C)> -where - A: Clone + serde::Serialize + serde::de::DeserializeOwned, - A: AsRef<[u8]> + FixedByteLength, - for<'a> A: TryFrom<&'a [u8]>, - for<'a> >::Error: std::error::Error, - B: AsRef<[u8]> + FixedByteLength, - for<'b> B: TryFrom<&'b [u8]>, - for<'b> >::Error: std::error::Error, - C: AsRef<[u8]>, - for<'c> C: TryFrom<&'c [u8]>, - for<'c> >::Error: std::error::Error, -{ - fn encode(&self, (a, b, c): &(A, B, C)) -> Result { - let a_bytes = a.as_ref(); - let b_bytes = b.as_ref(); - let c_bytes = c.as_ref(); - Ok(EncodeVec::from_slices(&[a_bytes, b_bytes, c_bytes])) - } - - fn decode(&self, bytes: &[u8]) -> Result<(A, B, C), RocksDbStorageError> { - let (a_bytes, rest) = bytes.split_at(A::BYTE_LENGTH); - let a = A::try_from(a_bytes).map_err(|e| RocksDbStorageError::DecodeError { - source: anyhow!("{}", e), - })?; - let (b_bytes, c_bytes) = rest.split_at(B::BYTE_LENGTH); - let b = B::try_from(b_bytes).map_err(|e| RocksDbStorageError::DecodeError { - source: anyhow!("{}", e), - })?; - let c = C::try_from(c_bytes).map_err(|e| RocksDbStorageError::DecodeError { - source: anyhow!("{}", e), - })?; - Ok((a, b, c)) - } -} - -impl Default for TupleBytesCodec { - fn default() -> Self { - Self { - _phantom: std::marker::PhantomData, - } - } -} - impl DbCodec<(A, B, C)> for (CA, CB, CC) where CA: DbCodec, CB: DbCodec, CC: DbCodec, - A: FixedByteLength, - B: FixedByteLength, { fn encode(&self, (a, b, c): &(A, B, C)) -> Result { let (ca, cb, cc) = &self; @@ -112,13 +26,11 @@ where ])) } - fn decode(&self, bytes: &[u8]) -> Result<(A, B, C), RocksDbStorageError> { + fn decode_reader(&self, reader: &mut R) -> Result<(A, B, C), RocksDbStorageError> { let (ca, cb, cc) = &self; - let (a_bytes, rest) = bytes.split_at(A::BYTE_LENGTH); - let a = ca.decode(a_bytes)?; - let (b_bytes, c_bytes) = rest.split_at(B::BYTE_LENGTH); - let b = cb.decode(b_bytes)?; - let c = cc.decode(c_bytes)?; + let a = ca.decode_reader(reader)?; + let b = cb.decode_reader(reader)?; + let c = cc.decode_reader(reader)?; Ok((a, b, c)) } } @@ -127,58 +39,18 @@ impl DbCodec<(A, B)> for (CA, CB) where CA: DbCodec, CB: DbCodec, - A: FixedByteLength, { fn encode(&self, (a, b): &(A, B)) -> Result { - let a_bytes = self.0.encode(a)?; - let b_bytes = self.1.encode(b)?; + let (ca, cb) = &self; + let a_bytes = ca.encode(a)?; + let b_bytes = cb.encode(b)?; Ok(EncodeVec::from_slices(&[a_bytes.as_ref(), b_bytes.as_ref()])) } - fn decode(&self, bytes: &[u8]) -> Result<(A, B), RocksDbStorageError> { - let (a_bytes, b_bytes) = bytes.split_at(A::BYTE_LENGTH); - let a = self.0.decode(a_bytes)?; - let b = self.1.decode(b_bytes)?; + fn decode_reader(&self, reader: &mut R) -> Result<(A, B), RocksDbStorageError> { + let (ca, cb) = &self; + let a = ca.decode_reader(reader)?; + let b = cb.decode_reader(reader)?; Ok((a, b)) } } - -pub trait FixedByteLength { - const BYTE_LENGTH: usize; -} - -impl FixedByteLength for u64 { - const BYTE_LENGTH: usize = size_of::(); -} - -impl FixedByteLength for BlockId { - const BYTE_LENGTH: usize = BlockId::byte_size(); -} - -impl FixedByteLength for Epoch { - const BYTE_LENGTH: usize = size_of::(); -} - -impl FixedByteLength for ForeignProposalStatus { - const BYTE_LENGTH: usize = 1; -} - -impl FixedByteLength for TransactionId { - const BYTE_LENGTH: usize = TransactionId::byte_size(); -} - -impl FixedByteLength for NodeHeight { - const BYTE_LENGTH: usize = size_of::(); -} - -impl FixedByteLength for RistrettoPublicKeyBytes { - const BYTE_LENGTH: usize = RistrettoPublicKeyBytes::length(); -} - -impl FixedByteLength for Column { - const BYTE_LENGTH: usize = size_of::(); -} - -impl FixedByteLength for Shard { - const BYTE_LENGTH: usize = size_of::(); -} diff --git a/crates/state_store_rocksdb/src/codecs/versioned.rs b/crates/state_store_rocksdb/src/codecs/versioned.rs index 15b851f6cc..3ec7f7824a 100644 --- a/crates/state_store_rocksdb/src/codecs/versioned.rs +++ b/crates/state_store_rocksdb/src/codecs/versioned.rs @@ -1,6 +1,8 @@ // Copyright 2025 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use std::io::Read; + use crate::{ codecs::{DbCodec, EncodeVec}, error::RocksDbStorageError, @@ -18,8 +20,8 @@ impl, T: Versioned, V: Into + Clone> DbCodec for self.codec.encode(&value) } - fn decode(&self, bytes: &[u8]) -> Result { - let versioned = self.codec.decode(bytes)?; + fn decode_reader(&self, reader: &mut R) -> Result { + let versioned = self.codec.decode_reader(reader)?; Ok(versioned.full_upgrade().into_latest()) } } diff --git a/crates/state_store_rocksdb/src/column_families/burnt_utxo.rs b/crates/state_store_rocksdb/src/column_families/burnt_utxo.rs index 3b104de8bb..e1266fc996 100644 --- a/crates/state_store_rocksdb/src/column_families/burnt_utxo.rs +++ b/crates/state_store_rocksdb/src/column_families/burnt_utxo.rs @@ -6,9 +6,10 @@ use tari_engine_types::{ confidential::UnclaimedConfidentialOutput, template_lib_models::UnclaimedConfidentialOutputAddress, }; +use tari_template_lib_types::ObjectKey; use crate::{ - codecs::{BlockIdCodec, BytesCodec, DefaultVersionedCodec, TupleBytesCodec, UnitCodec}, + codecs::{BlockIdCodec, BytesCodec, DefaultVersionedCodec, FixedBytesCodec, UnitCodec}, traits::{Cf, QueryCf, VersionedUnclaimedConfidentialOutput}, }; @@ -29,7 +30,7 @@ pub struct ProposedInBlockIndex; impl Cf for ProposedInBlockIndex { type Key = (BlockId, UnclaimedConfidentialOutputAddress); - type KeyCodec = TupleBytesCodec; + type KeyCodec = (BlockIdCodec, FixedBytesCodec<{ ObjectKey::LENGTH }>); type Value = (); type ValueCodec = UnitCodec; diff --git a/crates/state_store_rocksdb/src/column_families/epoch_checkpoint.rs b/crates/state_store_rocksdb/src/column_families/epoch_checkpoint.rs index 73312e2209..9bbffd5f4f 100644 --- a/crates/state_store_rocksdb/src/column_families/epoch_checkpoint.rs +++ b/crates/state_store_rocksdb/src/column_families/epoch_checkpoint.rs @@ -20,11 +20,11 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use tari_ootle_common_types::Epoch; +use tari_ootle_common_types::{Epoch, ShardGroup}; use tari_ootle_storage::consensus_models::EpochCheckpoint; use crate::{ - codecs::{DefaultVersionedCodec, EpochCodec}, + codecs::{DefaultVersionedCodec, EpochCodec, ShardGroupCodec}, traits::Cf, versioned_types::VersionedEpochCheckpoint, }; @@ -32,8 +32,8 @@ use crate::{ pub struct EpochCheckpointCf; impl Cf for EpochCheckpointCf { - type Key = Epoch; - type KeyCodec = EpochCodec; + type Key = (Epoch, ShardGroup); + type KeyCodec = (EpochCodec, ShardGroupCodec); type Value = EpochCheckpoint; type ValueCodec = DefaultVersionedCodec; @@ -41,3 +41,11 @@ impl Cf for EpochCheckpointCf { "epoch_checkpoints" } } + +pub struct ByEpochQuery; + +impl crate::traits::QueryCf for ByEpochQuery { + type Cf = EpochCheckpointCf; + type Key = Epoch; + type KeyCodec = EpochCodec; +} diff --git a/crates/state_store_rocksdb/src/column_families/foreign_parked_blocks.rs b/crates/state_store_rocksdb/src/column_families/foreign_parked_blocks.rs index aa862b66cb..5cba6a2894 100644 --- a/crates/state_store_rocksdb/src/column_families/foreign_parked_blocks.rs +++ b/crates/state_store_rocksdb/src/column_families/foreign_parked_blocks.rs @@ -25,7 +25,7 @@ use tari_ootle_storage::consensus_models::ForeignParkedProposal; use tari_transaction::TransactionId; use crate::{ - codecs::{BlockIdCodec, DefaultCodec, TransactionIdCodec, TupleBytesCodec, UnitCodec}, + codecs::{BlockIdCodec, DefaultCodec, TransactionIdCodec, UnitCodec}, traits::{Cf, QueryCf}, }; @@ -46,7 +46,7 @@ pub struct MissingTransactionsModel; impl Cf for MissingTransactionsModel { type Key = (TransactionId, BlockId); - type KeyCodec = TupleBytesCodec; + type KeyCodec = (TransactionIdCodec, BlockIdCodec); type Value = (); type ValueCodec = UnitCodec; diff --git a/crates/state_store_rocksdb/src/column_families/foreign_substate_pledge.rs b/crates/state_store_rocksdb/src/column_families/foreign_substate_pledge.rs index 0c84480de9..40914394fe 100644 --- a/crates/state_store_rocksdb/src/column_families/foreign_substate_pledge.rs +++ b/crates/state_store_rocksdb/src/column_families/foreign_substate_pledge.rs @@ -25,7 +25,7 @@ use tari_ootle_storage::consensus_models::SubstatePledge; use tari_transaction::TransactionId; use crate::{ - codecs::{DefaultCodec, TransactionIdCodec, TupleBytesCodec}, + codecs::{DefaultCodec, FixedBytesCodec, TransactionIdCodec}, traits::{Cf, QueryCf}, }; @@ -33,7 +33,7 @@ pub struct ForeignSubstatePledgeCf; impl Cf for ForeignSubstatePledgeCf { type Key = (TransactionId, SubstateAddress); - type KeyCodec = TupleBytesCodec; + type KeyCodec = (TransactionIdCodec, FixedBytesCodec<{ SubstateAddress::LENGTH }>); type Value = SubstatePledge; type ValueCodec = DefaultCodec; diff --git a/crates/state_store_rocksdb/src/column_families/lock_conflict.rs b/crates/state_store_rocksdb/src/column_families/lock_conflict.rs index 421b8e1a46..20ed8e81d1 100644 --- a/crates/state_store_rocksdb/src/column_families/lock_conflict.rs +++ b/crates/state_store_rocksdb/src/column_families/lock_conflict.rs @@ -25,7 +25,7 @@ use tari_ootle_storage::consensus_models::LockConflict; use tari_transaction::TransactionId; use crate::{ - codecs::{BlockIdCodec, DefaultCodec, TransactionIdCodec, TupleBytesCodec, UnitCodec}, + codecs::{BlockIdCodec, DefaultCodec, TransactionIdCodec, UnitCodec}, traits::{Cf, QueryCf}, }; @@ -34,7 +34,7 @@ pub struct LockConflictCf; impl Cf for LockConflictCf { // (transaction id, Block, depends_on_tx_id) type Key = (TransactionId, BlockId, TransactionId); - type KeyCodec = TupleBytesCodec; + type KeyCodec = (TransactionIdCodec, BlockIdCodec, TransactionIdCodec); type Value = LockConflict; type ValueCodec = DefaultCodec; @@ -56,12 +56,12 @@ pub struct LockConflictBlockIdIndex; impl Cf for LockConflictBlockIdIndex { // (block id, transaction id, depends_on_tx_id) type Key = (BlockId, TransactionId, TransactionId); - type KeyCodec = TupleBytesCodec; + type KeyCodec = (BlockIdCodec, TransactionIdCodec, TransactionIdCodec); type Value = (); type ValueCodec = UnitCodec; fn name() -> &'static str { - "lockconflicts" + "lockconflicts_block_id_index" } } diff --git a/crates/state_store_rocksdb/src/column_families/missing_transactions.rs b/crates/state_store_rocksdb/src/column_families/missing_transactions.rs index 87a4741427..d4be8775d6 100644 --- a/crates/state_store_rocksdb/src/column_families/missing_transactions.rs +++ b/crates/state_store_rocksdb/src/column_families/missing_transactions.rs @@ -24,7 +24,7 @@ use tari_consensus_types::BlockId; use tari_transaction::TransactionId; use crate::{ - codecs::{BlockIdCodec, TransactionIdCodec, TupleBytesCodec, UnitCodec}, + codecs::{BlockIdCodec, TransactionIdCodec, UnitCodec}, traits::{Cf, QueryCf}, }; @@ -32,7 +32,7 @@ pub struct MissingTransactionCf; impl Cf for MissingTransactionCf { type Key = (TransactionId, BlockId); - type KeyCodec = TupleBytesCodec; + type KeyCodec = (TransactionIdCodec, BlockIdCodec); type Value = (); type ValueCodec = UnitCodec; @@ -53,7 +53,7 @@ pub struct MissingTransactionBlockIdIndex; impl Cf for MissingTransactionBlockIdIndex { type Key = (BlockId, TransactionId); - type KeyCodec = TupleBytesCodec; + type KeyCodec = (BlockIdCodec, TransactionIdCodec); type Value = (); type ValueCodec = UnitCodec; diff --git a/crates/state_store_rocksdb/src/column_families/transaction_pool_state_update.rs b/crates/state_store_rocksdb/src/column_families/transaction_pool_state_update.rs index 9de36aeba9..5581a81abb 100644 --- a/crates/state_store_rocksdb/src/column_families/transaction_pool_state_update.rs +++ b/crates/state_store_rocksdb/src/column_families/transaction_pool_state_update.rs @@ -27,7 +27,7 @@ use tari_ootle_storage::consensus_models::{Evidence, LeaderFee, TransactionPoolR use tari_transaction::TransactionId; use crate::{ - codecs::{BlockIdCodec, BytesCodec, DefaultCodec, EpochCodec, NumberCodec, TupleBytesCodec}, + codecs::{BlockIdCodec, BytesCodec, DefaultCodec, EpochCodec, NumberCodec, TransactionIdCodec}, traits::{Cf, QueryCf}, }; @@ -65,7 +65,7 @@ pub struct TransactionPoolStateUpdateCf; impl Cf for TransactionPoolStateUpdateCf { type Key = (BlockId, TransactionId); - type KeyCodec = TupleBytesCodec; + type KeyCodec = (BlockIdCodec, TransactionIdCodec); type Value = TransactionPoolStateUpdateData; type ValueCodec = DefaultCodec; diff --git a/crates/state_store_rocksdb/src/reader.rs b/crates/state_store_rocksdb/src/reader.rs index 9d2718e719..f1b0ca8d5a 100644 --- a/crates/state_store_rocksdb/src/reader.rs +++ b/crates/state_store_rocksdb/src/reader.rs @@ -81,6 +81,7 @@ use tari_ootle_storage::{ SubstatePledges, SubstateRecord, SubstateUpdateProof, + SubstateValueFilterFlags, SubstateValueOrHash, TransactionExecution, TransactionPoolRecord, @@ -124,6 +125,7 @@ use crate::{ burnt_utxo::BurntUtxoCf, certificates::{proposal::ProposalCertificateCf, timeout::TimeoutCertificateCf}, chain, + epoch_checkpoint, epoch_checkpoint::EpochCheckpointCf, evicted_node, evicted_node::EvictedNodeCf, @@ -1593,7 +1595,7 @@ impl<'tx, TAddr: NodeAddressable + Serialize + DeserializeOwned + 'tx> StateStor &self, req_shard: Shard, state_version: Version, - include_values: bool, + value_filter: SubstateValueFilterFlags, ) -> Result { const OPERATION: &str = "state_transitions_get_n_after"; @@ -1616,7 +1618,7 @@ impl<'tx, TAddr: NodeAddressable + Serialize + DeserializeOwned + 'tx> StateStor }); } - // TODO(perf): if include_values is false, we still have to load the whole substate for the id and version - not + // TODO(perf): we still have to load all substates for the id and version regardless of the value filters - not // ideal let substates = substate_cf.multi_get(data.transitions.iter().map(|t| t.substate_address), OPERATION)?; @@ -1625,10 +1627,14 @@ impl<'tx, TAddr: NodeAddressable + Serialize + DeserializeOwned + 'tx> StateStor for (data, substate) in data.transitions.iter().zip(substates) { let update = match data.transition { StateTransitionType::Up => { - let value = include_values.then_some(substate.substate_value).flatten().map_or_else( - || SubstateValueOrHash::Hash(substate.state_hash), - |v| SubstateValueOrHash::Value(Box::new(v)), - ); + let value = value_filter + .contains_substate(&substate.substate_id) + .then_some(substate.substate_value) + .flatten() + .map_or_else( + || SubstateValueOrHash::Hash(substate.state_hash), + |v| SubstateValueOrHash::Value(Box::new(v)), + ); SubstateUpdateProof::Create(SubstateCreatedProof { substate: SubstateData { substate_id: substate.substate_id, @@ -1719,10 +1725,29 @@ impl<'tx, TAddr: NodeAddressable + Serialize + DeserializeOwned + 'tx> StateStor Ok(shard_tree_versions) } - fn epoch_checkpoint_get(&self, epoch: Epoch) -> Result { - const OPERATION: &str = "epoch_checkpoint_get"; + fn epoch_checkpoint_get_all_from_epoch( + &self, + from_epoch: Epoch, + limit: usize, + ) -> Result, StorageError> { + // const OPERATION: &str = "epoch_checkpoint_get_all"; + let query = self.db().cf(epoch_checkpoint::ByEpochQuery)?; + let iter = query.query_range_iterator(Ordering::Ascending, from_epoch..); + let epoch_checkpoints = iter + .map(|result| result.map(|(_, checkpoint)| checkpoint)) + .take(limit) + .collect::>()?; + Ok(epoch_checkpoints) + } + + fn epoch_checkpoint_get_by_shard_group( + &self, + epoch: Epoch, + shard_group: ShardGroup, + ) -> Result { + const OPERATION: &str = "epoch_checkpoint_get_by_shard_group"; let cf = self.db().cf(EpochCheckpointCf)?; - let checkpoint = cf.get(&epoch, OPERATION)?; + let checkpoint = cf.get(&(epoch, shard_group), OPERATION)?; Ok(checkpoint) } diff --git a/crates/state_store_rocksdb/src/store.rs b/crates/state_store_rocksdb/src/store.rs index 72ae60d455..b2daa8ddcb 100644 --- a/crates/state_store_rocksdb/src/store.rs +++ b/crates/state_store_rocksdb/src/store.rs @@ -48,6 +48,7 @@ use crate::{ foreign_proposal, foreign_proposal::ForeignProposalCf, foreign_substate_pledge::ForeignSubstatePledgeCf, + lock_conflict, lock_conflict::LockConflictCf, missing_transactions::MissingTransactionCf, parked_block::ParkedBlockCf, @@ -123,6 +124,7 @@ pub fn all_column_families_iter() -> impl Iterator { BurntUtxoCf::name(), burnt_utxo::ProposedInBlockIndex::name(), LockConflictCf::name(), + lock_conflict::LockConflictBlockIdIndex::name(), EvictedNodeCf::name(), ValidatorNodeEpochStatsCf::name(), ] diff --git a/crates/state_store_rocksdb/src/utils.rs b/crates/state_store_rocksdb/src/utils.rs index 56a1c7d44b..8a9c9f6529 100644 --- a/crates/state_store_rocksdb/src/utils.rs +++ b/crates/state_store_rocksdb/src/utils.rs @@ -22,42 +22,8 @@ use std::io; -use anyhow::anyhow; -use serde::{de::DeserializeOwned, Serialize}; use tari_ootle_storage::time::{PrimitiveDateTime, UtcDateTime}; -use crate::error::RocksDbStorageError; - -const BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard(); - -pub fn bincode_encode(value: &T) -> Result, RocksDbStorageError> { - let bytes = bincode::serde::encode_to_vec(value, BINCODE_CONFIG) - .map_err(|e| RocksDbStorageError::EncodeError { source: e.into() })?; - Ok(bytes) -} - -pub fn bincode_decode(bytes: &[u8]) -> Result { - let (value, bytes_read) = - bincode::serde::decode_from_slice(bytes, BINCODE_CONFIG).map_err(|e| RocksDbStorageError::DecodeError { - source: anyhow!( - "Bincode deserialization failed for type:{}: {}", - std::any::type_name::(), - e, - ), - })?; - if bytes_read != bytes.len() { - return Err(RocksDbStorageError::DecodeError { - source: anyhow!( - "Bincode deserialization failed for type {}. Bytes read: {}. Bytes length: {}", - std::any::type_name::(), - bytes_read, - bytes.len() - ), - }); - } - Ok(value) -} - pub(crate) fn read_to_fixed(reader: &mut R) -> Option where [u8; SZ]: Into, diff --git a/crates/state_store_rocksdb/src/writer.rs b/crates/state_store_rocksdb/src/writer.rs index 617396070f..bb3b4d339d 100644 --- a/crates/state_store_rocksdb/src/writer.rs +++ b/crates/state_store_rocksdb/src/writer.rs @@ -1531,9 +1531,16 @@ impl<'tx, TAddr: NodeAddressable + 'tx> StateStoreWriteTransaction for RocksDbSt fn epoch_checkpoint_save(&mut self, checkpoint: &EpochCheckpoint) -> Result<(), StorageError> { const OPERATION: &str = "epoch_checkpoint_save"; + let shard_group = checkpoint.checked_shard_group().map_err(|e| StorageError::QueryError { + reason: format!( + "{OPERATION}: Invalid shard group for epoch {}: {}", + checkpoint.epoch(), + e + ), + })?; self.db() .cf(EpochCheckpointCf)? - .put(&checkpoint.epoch(), checkpoint, OPERATION)?; + .put(&(checkpoint.epoch(), shard_group), checkpoint, OPERATION)?; Ok(()) } diff --git a/crates/state_store_tests/src/misc.rs b/crates/state_store_tests/src/misc.rs index b16fbf2824..0a8a597ec2 100644 --- a/crates/state_store_tests/src/misc.rs +++ b/crates/state_store_tests/src/misc.rs @@ -196,7 +196,11 @@ fn miscellaneous_operations(db: impl StateStore) { let epoch_checkpoint = EpochCheckpoint::new(proof, shard_summary); tx.epoch_checkpoint_save(&epoch_checkpoint).unwrap(); - let res = tx.epoch_checkpoint_get(block.epoch()).unwrap(); + let res = tx + .epoch_checkpoint_get_all_from_epoch(block.epoch(), 1) + .unwrap() + .pop() + .unwrap(); assert_eq_debug(&res, &epoch_checkpoint); // foreign parked blocks diff --git a/crates/state_store_tests/src/state_transitions.rs b/crates/state_store_tests/src/state_transitions.rs index fa72e52fa5..fe77b710b5 100644 --- a/crates/state_store_tests/src/state_transitions.rs +++ b/crates/state_store_tests/src/state_transitions.rs @@ -4,7 +4,12 @@ use std::collections::{HashMap, HashSet}; use tari_ootle_common_types::{Epoch, Network}; -use tari_ootle_storage::{consensus_models::Block, StateStore, StateStoreReadTransaction, StateStoreWriteTransaction}; +use tari_ootle_storage::{ + consensus_models::{Block, SubstateValueFilterFlags}, + StateStore, + StateStoreReadTransaction, + StateStoreWriteTransaction, +}; use tari_state_tree::Version; use crate::{ @@ -64,7 +69,7 @@ fn operations(db: impl StateStore) { for (state_version, (num_substates, shards)) in &shards { for shard in shards { let transitions = tx - .state_transitions_get_starting_at(*shard, *state_version, false) + .state_transitions_get_starting_at(*shard, *state_version, SubstateValueFilterFlags::empty()) .unwrap(); assert_eq!(transitions.epoch, EPOCH); assert_eq!(transitions.state_version, *state_version); diff --git a/crates/storage/Cargo.toml b/crates/storage/Cargo.toml index c200867997..d6a569639a 100644 --- a/crates/storage/Cargo.toml +++ b/crates/storage/Cargo.toml @@ -22,6 +22,7 @@ tari_crypto = { workspace = true } tari_state_tree = { workspace = true } anyhow = { workspace = true } +bitflags = { workspace = true } borsh = { workspace = true } indexmap = { workspace = true, features = ["serde"] } log = { workspace = true } diff --git a/crates/storage/src/consensus_models/block.rs b/crates/storage/src/consensus_models/block.rs index fd99589559..0dab97b72d 100644 --- a/crates/storage/src/consensus_models/block.rs +++ b/crates/storage/src/consensus_models/block.rs @@ -86,11 +86,7 @@ pub enum BlockError { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Block { header: BlockHeader, /// Collection of signatures that justify a previous block and potentially a change to the next higher view. diff --git a/crates/storage/src/consensus_models/block_header.rs b/crates/storage/src/consensus_models/block_header.rs index 1a77313c2a..37d1a09cad 100644 --- a/crates/storage/src/consensus_models/block_header.rs +++ b/crates/storage/src/consensus_models/block_header.rs @@ -31,11 +31,7 @@ use super::BlockError; use crate::consensus_models::Command; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct BlockHeader { /// "Cached" block ID/hash. This is computed from the contents of the block header. #[cfg_attr(feature = "ts", ts(type = "string"))] @@ -70,8 +66,8 @@ pub struct BlockHeader { command_merkle_root: FixedHash, /// Proposer signature that signs the Block ID signature: Option, - /// The time indicating the creation time of the block. Currently, this can be chosen arbitrarily and is only - /// informational/used for metrics. + /// The Unix Epoch timestamp indicating the creation time of the block. Currently, this can be chosen arbitrarily + /// and is only informational/used for metrics. #[cfg_attr(feature = "ts", ts(type = "number"))] timestamp: u64, /// The epoch hash is a hash given by the epoch oracle. E.g. the base layer epoch oracle gives the first block hash diff --git a/crates/storage/src/consensus_models/burnt_utxo.rs b/crates/storage/src/consensus_models/burnt_utxo.rs index c0b2a218d4..ec4f263631 100644 --- a/crates/storage/src/consensus_models/burnt_utxo.rs +++ b/crates/storage/src/consensus_models/burnt_utxo.rs @@ -69,11 +69,7 @@ impl BurntUtxo { } #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct MintConfidentialOutputAtom { pub commitment: UnclaimedConfidentialOutputAddress, } diff --git a/crates/storage/src/consensus_models/command.rs b/crates/storage/src/consensus_models/command.rs index 7d52b44948..f3563646f9 100644 --- a/crates/storage/src/consensus_models/command.rs +++ b/crates/storage/src/consensus_models/command.rs @@ -24,11 +24,7 @@ use crate::{ }; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct TransactionAtom { #[cfg_attr(feature = "ts", ts(type = "string"))] pub id: TransactionId, @@ -65,11 +61,7 @@ impl Display for TransactionAtom { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum Command { // Transaction Commands /// Request validators to prepare a local-only transaction @@ -263,11 +255,7 @@ impl Display for Command { } } -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize)] pub struct EvictNodeAtom { #[cfg_attr(feature = "ts", ts(type = "string"))] diff --git a/crates/storage/src/consensus_models/epoch_checkpoint.rs b/crates/storage/src/consensus_models/epoch_checkpoint.rs index b9b69c9fb8..c0f70129c4 100644 --- a/crates/storage/src/consensus_models/epoch_checkpoint.rs +++ b/crates/storage/src/consensus_models/epoch_checkpoint.rs @@ -127,7 +127,14 @@ impl EpochCheckpoint { Ok(()) } - fn validate_well_formed(&self) -> Result<(), EpochCheckpointValidationError> { + /// Validates that the epoch checkpoint is well-formed. + /// This includes basic sanity checks such as: + /// - The shard group is valid (start < end + 1) + /// - The number of shard state roots does not exceed the number of shards in the group + /// - The state root matches the provided header + /// + /// Use EpochCheckpoint::validate() to validate the entire proof (including well-formedness). + pub fn validate_well_formed(&self) -> Result<(), EpochCheckpointValidationError> { // Basic sanity checks let header_shard_group = convert_sidechain_shard_group_to_shard_group(self.header().shard_group)?; let num_shards = header_shard_group.len(); @@ -163,8 +170,20 @@ impl EpochCheckpoint { } impl EpochCheckpoint { - pub fn get(tx: &TTx, epoch: Epoch) -> Result { - tx.epoch_checkpoint_get(epoch) + pub fn get_all_from_epoch( + tx: &TTx, + from_epoch: Epoch, + limit: usize, + ) -> Result, StorageError> { + tx.epoch_checkpoint_get_all_from_epoch(from_epoch, limit) + } + + pub fn get_by_shard_group( + tx: &TTx, + epoch: Epoch, + shard_group: ShardGroup, + ) -> Result { + tx.epoch_checkpoint_get_by_shard_group(epoch, shard_group) } pub fn save(&self, tx: &mut TTx) -> Result<(), StorageError> { diff --git a/crates/storage/src/consensus_models/evidence.rs b/crates/storage/src/consensus_models/evidence.rs index 510f88125e..b9c36d268b 100644 --- a/crates/storage/src/consensus_models/evidence.rs +++ b/crates/storage/src/consensus_models/evidence.rs @@ -27,11 +27,7 @@ use crate::consensus_models::{RequireLockIntentRef, SubstatePledge}; const LOG_TARGET: &str = "tari::ootle::consensus_models::evidence"; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Evidence { // Serialize JSON as an array of objects since ShardGroup is a non-string key #[serde(with = "serde_with::vec")] @@ -408,11 +404,7 @@ impl Display for Evidence { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ShardGroupEvidence { #[borsh(serialize_with = "indexmap_borsh::serialize")] #[cfg_attr(feature = "ts", ts(type = "Record"))] @@ -604,11 +596,7 @@ impl Display for ShardGroupEvidence { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct EvidenceInputLockData { pub is_write: bool, pub version: u32, diff --git a/crates/storage/src/consensus_models/foreign_proposal.rs b/crates/storage/src/consensus_models/foreign_proposal.rs index 6ce756d3af..70b100eef5 100644 --- a/crates/storage/src/consensus_models/foreign_proposal.rs +++ b/crates/storage/src/consensus_models/foreign_proposal.rs @@ -219,11 +219,7 @@ impl Display for ForeignProposalRecord { } #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ForeignProposalAtom { #[cfg_attr(feature = "ts", ts(type = "string"))] pub block_id: BlockId, diff --git a/crates/storage/src/consensus_models/leader_fee.rs b/crates/storage/src/consensus_models/leader_fee.rs index 598234cdb7..8354294cc3 100644 --- a/crates/storage/src/consensus_models/leader_fee.rs +++ b/crates/storage/src/consensus_models/leader_fee.rs @@ -10,11 +10,7 @@ use borsh::BorshSerialize; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, BorshSerialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct LeaderFee { #[cfg_attr(feature = "ts", ts(type = "number"))] pub fee: u64, diff --git a/crates/storage/src/consensus_models/lock_intent.rs b/crates/storage/src/consensus_models/lock_intent.rs index e2f2ebac58..011e951ea6 100644 --- a/crates/storage/src/consensus_models/lock_intent.rs +++ b/crates/storage/src/consensus_models/lock_intent.rs @@ -14,11 +14,7 @@ use tari_ootle_common_types::{ }; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct VersionedSubstateIdLockIntent { versioned_substate_id: VersionedSubstateId, lock_type: SubstateLockType, diff --git a/crates/storage/src/consensus_models/state_transition.rs b/crates/storage/src/consensus_models/state_transition.rs index d425474548..61f454ab3b 100644 --- a/crates/storage/src/consensus_models/state_transition.rs +++ b/crates/storage/src/consensus_models/state_transition.rs @@ -3,7 +3,9 @@ use std::num::NonZeroUsize; +use bitflags::bitflags; use serde::{Deserialize, Serialize}; +use tari_engine_types::substate::SubstateId; use tari_ootle_common_types::{shard::Shard, Epoch}; use tari_state_tree::Version; @@ -43,8 +45,41 @@ impl StateTransition { tx: &TTx, shard: Shard, state_version: Version, - include_values: bool, + value_filters: SubstateValueFilterFlags, ) -> Result { - tx.state_transitions_get_starting_at(shard, state_version, include_values) + tx.state_transitions_get_starting_at(shard, state_version, value_filters) + } +} + +bitflags! { + /// Represents a set of flags. + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct SubstateValueFilterFlags: u32 { + const NONE = 0; + const COMPONENT = 0x0000_0001; + const RESOURCE = 0x0000_0002; + const VAULT = 0x0000_0004; + const NON_FUNGIBLE = 0x0000_0008; + const TRANSACTION_RECEIPT = 0x0000_0010; + const TEMPLATE = 0x0000_0020; + const VALIDATOR_FEE_POOL = 0x0000_0040; + const UTXO = 0x0000_0080; + } +} + +impl SubstateValueFilterFlags { + pub fn contains_substate(&self, substate_id: &SubstateId) -> bool { + match substate_id { + SubstateId::Component(_) => self.contains(SubstateValueFilterFlags::COMPONENT), + SubstateId::Resource(_) => self.contains(SubstateValueFilterFlags::RESOURCE), + SubstateId::Vault(_) => self.contains(SubstateValueFilterFlags::VAULT), + SubstateId::NonFungible(_) => self.contains(SubstateValueFilterFlags::NON_FUNGIBLE), + SubstateId::TransactionReceipt(_) => self.contains(SubstateValueFilterFlags::TRANSACTION_RECEIPT), + SubstateId::Template(_) => self.contains(SubstateValueFilterFlags::TEMPLATE), + SubstateId::ValidatorFeePool(_) => self.contains(SubstateValueFilterFlags::VALIDATOR_FEE_POOL), + SubstateId::Utxo(_) => self.contains(SubstateValueFilterFlags::UTXO), + // TODO: remove once UnclaimedConfidentialOutput is removed + SubstateId::UnclaimedConfidentialOutput(_) => false, + } } } diff --git a/crates/storage/src/consensus_models/substate.rs b/crates/storage/src/consensus_models/substate.rs index e993d35443..0b8c94ec40 100644 --- a/crates/storage/src/consensus_models/substate.rs +++ b/crates/storage/src/consensus_models/substate.rs @@ -30,11 +30,7 @@ use crate::{ }; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct SubstateRecord { pub substate_id: SubstateId, pub version: u32, @@ -294,11 +290,7 @@ impl SubstateDestroyedProof { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct SubstateCreated { // TODO: consider removing this field, it's not used pub at_epoch: Epoch, @@ -309,11 +301,7 @@ pub struct SubstateCreated { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct SubstateDestroyed { pub at_epoch: Epoch, pub at_state_version: Version, diff --git a/crates/storage/src/consensus_models/transaction_execution.rs b/crates/storage/src/consensus_models/transaction_execution.rs index 8e6ba75af6..80a70353b0 100644 --- a/crates/storage/src/consensus_models/transaction_execution.rs +++ b/crates/storage/src/consensus_models/transaction_execution.rs @@ -18,11 +18,7 @@ use crate::{ }; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct TransactionExecution { pub result: ExecuteResult, pub resolved_inputs: Vec, diff --git a/crates/storage/src/consensus_models/transaction_pool.rs b/crates/storage/src/consensus_models/transaction_pool.rs index 025e2cca81..c507f3a461 100644 --- a/crates/storage/src/consensus_models/transaction_pool.rs +++ b/crates/storage/src/consensus_models/transaction_pool.rs @@ -211,11 +211,7 @@ impl TransactionPool { // Ord: ensure that the enum variants are ordered in the order of their progression #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum TransactionPoolStage { /// Transaction has just come in and has never been proposed New, @@ -322,11 +318,7 @@ impl FromStr for TransactionPoolConfirmedStage { pub struct TransactionPoolConfirmedStageFromStrErr(String); #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct TransactionPoolRecord { #[cfg_attr(feature = "ts", ts(type = "string"))] transaction_id: TransactionId, diff --git a/crates/storage/src/error.rs b/crates/storage/src/error.rs index 5c1ef4e9c6..ab17d8fbe1 100644 --- a/crates/storage/src/error.rs +++ b/crates/storage/src/error.rs @@ -20,6 +20,8 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +use std::fmt::Display; + use tari_common_types::types::FixedHashSizeError; use tari_ootle_common_types::optional::IsNotFoundError; @@ -64,6 +66,14 @@ pub enum StorageError { BlockError(#[from] BlockError), } +impl StorageError { + pub fn general(operation: &'static str, details: T) -> Self { + Self::General { + details: format!("{}: {}", operation, details), + } + } +} + impl IsNotFoundError for StorageError { fn is_not_found_error(&self) -> bool { matches!(self, Self::NotFound { .. }) || matches!(self, Self::NotFoundDbAdapter { .. }) diff --git a/crates/storage/src/state_store/mod.rs b/crates/storage/src/state_store/mod.rs index 4a98d9c15f..62580793e5 100644 --- a/crates/storage/src/state_store/mod.rs +++ b/crates/storage/src/state_store/mod.rs @@ -63,6 +63,7 @@ use crate::{ SubstatePledges, SubstateRecord, SubstateUpdateBatch, + SubstateValueFilterFlags, TransactionExecution, TransactionPoolRecord, TransactionPoolStage, @@ -280,7 +281,7 @@ pub trait StateStoreReadTransaction: Sized { &self, shard: Shard, state_version: Version, - include_values: bool, + value_filters: SubstateValueFilterFlags, ) -> Result; // -------------------------------- State Tree -------------------------------- // @@ -298,7 +299,16 @@ pub trait StateStoreReadTransaction: Sized { ) -> Result; // -------------------------------- Epoch checkpoint -------------------------------- // - fn epoch_checkpoint_get(&self, epoch: Epoch) -> Result; + fn epoch_checkpoint_get_all_from_epoch( + &self, + epoch: Epoch, + limit: usize, + ) -> Result, StorageError>; + fn epoch_checkpoint_get_by_shard_group( + &self, + epoch: Epoch, + shard_group: ShardGroup, + ) -> Result; // -------------------------------- Foreign Substate Pledges -------------------------------- // fn foreign_substate_pledges_exists_for_transaction_and_address( @@ -596,11 +606,7 @@ pub trait StateStoreWriteTransaction { } #[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum Ordering { #[default] Ascending, diff --git a/crates/template_abi/src/types.rs b/crates/template_abi/src/types.rs index 64791dac24..55c5359248 100644 --- a/crates/template_abi/src/types.rs +++ b/crates/template_abi/src/types.rs @@ -25,11 +25,7 @@ use serde::{Deserialize, Serialize}; use crate::rust::{boxed::Box, string::String, vec::Vec}; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum TemplateDef { V1(TemplateDefV1), } @@ -61,11 +57,7 @@ impl TemplateDef { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct TemplateDefV1 { pub template_name: String, pub tari_version: String, @@ -79,11 +71,7 @@ impl TemplateDefV1 { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct FunctionDef { pub name: String, pub arguments: Vec, @@ -92,22 +80,14 @@ pub struct FunctionDef { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ArgDef { pub name: String, pub arg_type: Type, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum Type { #[default] Unit, diff --git a/crates/template_lib/src/args/arg.rs b/crates/template_lib/src/args/arg.rs index 4963241e83..e14186ff21 100644 --- a/crates/template_lib/src/args/arg.rs +++ b/crates/template_lib/src/args/arg.rs @@ -28,11 +28,7 @@ use tari_template_lib_types::serde_helpers; pub type WorkspaceId = u16; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct WorkspaceOffsetId { id: WorkspaceId, offset: Option, @@ -79,11 +75,7 @@ impl fmt::Display for WorkspaceOffsetId { /// Represents an argument that can be passed to a transaction instruction. Either a literal value or a reference to a /// item on the runtime's workspace. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum InstructionArg { /// The argument is in the transaction execution's workspace, which means it is the result of a previous /// instruction diff --git a/crates/template_lib/src/args/freeze_flags.rs b/crates/template_lib/src/args/freeze_flags.rs index 16e223eecf..fb104bb717 100644 --- a/crates/template_lib/src/args/freeze_flags.rs +++ b/crates/template_lib/src/args/freeze_flags.rs @@ -8,11 +8,7 @@ const ALL_FLAGS: u8 = 0b0011; #[derive(Clone, Debug, Copy, Default, Serialize, Deserialize)] #[serde(transparent)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct VaultFreezeFlags(u8); impl VaultFreezeFlags { diff --git a/crates/template_lib/src/args/types.rs b/crates/template_lib/src/args/types.rs index 46f52c6616..6cdd3eff91 100644 --- a/crates/template_lib/src/args/types.rs +++ b/crates/template_lib/src/args/types.rs @@ -65,11 +65,7 @@ pub struct EmitLogArg { /// All the possible log levels #[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum LogLevel { Error, Warn, @@ -570,11 +566,7 @@ pub struct CallerContextInvokeArg { /// Possible allocatable address types #[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum AllocatableAddressType { Component, Resource, diff --git a/crates/template_lib/src/auth/access_rules.rs b/crates/template_lib/src/auth/access_rules.rs index 080656a980..ea5d85fdd5 100644 --- a/crates/template_lib/src/auth/access_rules.rs +++ b/crates/template_lib/src/auth/access_rules.rs @@ -9,11 +9,7 @@ use crate::models::{ComponentAddress, NonFungibleAddress, ResourceAddress}; /// Represents the types of possible access control rules over a component method or resource #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum AccessRule { /// AccessRule always passes AllowAll, @@ -47,11 +43,7 @@ impl AccessRule { /// An enum that represents the possible ways to restrict access to components or resources #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum RestrictedAccessRule { /// Requires a specific condition to be met Require(RequireRule), @@ -73,11 +65,7 @@ impl RestrictedAccessRule { /// Specifies a requirement for a [RequireRule]. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum RuleRequirement { /// Requires ownership of a specific resource Resource(ResourceAddress), @@ -115,11 +103,7 @@ impl From for RuleRequirement { /// A rule requiring specific condition(s) to be met #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum RequireRule { /// Requires a specific condition to be met Require(RuleRequirement), @@ -131,11 +115,7 @@ pub enum RequireRule { /// Information needed to specify access rules to methods of a component #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ComponentAccessRules { #[cfg_attr(feature = "ts", ts(type = "Record"))] method_access: BTreeMap, @@ -216,11 +196,7 @@ impl ResourceAuthAction { /// Information needed to specify access rules to a resource #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ResourceAccessRules { mintable: AccessRule, burnable: AccessRule, diff --git a/crates/template_lib/src/auth/auth_hook.rs b/crates/template_lib/src/auth/auth_hook.rs index 771404fb5e..4e6366d06d 100644 --- a/crates/template_lib/src/auth/auth_hook.rs +++ b/crates/template_lib/src/auth/auth_hook.rs @@ -6,11 +6,7 @@ use tari_template_lib_types::TemplateAddress; use crate::models::ComponentAddress; -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct AuthHook { pub component_address: ComponentAddress, diff --git a/crates/template_lib/src/auth/owner_rule.rs b/crates/template_lib/src/auth/owner_rule.rs index f398749826..b9fcd5049c 100644 --- a/crates/template_lib/src/auth/owner_rule.rs +++ b/crates/template_lib/src/auth/owner_rule.rs @@ -15,11 +15,7 @@ pub struct Ownership<'a> { /// An enum for all possible ways to specify ownership of values #[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, PartialEq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum OwnerRule { /// The owner is the signer of the transaction that created the value #[default] diff --git a/crates/template_lib/src/models/bucket.rs b/crates/template_lib/src/models/bucket.rs index 4bfe28c139..32b65e74e2 100644 --- a/crates/template_lib/src/models/bucket.rs +++ b/crates/template_lib/src/models/bucket.rs @@ -44,11 +44,7 @@ const TAG: u64 = BinaryTag::BucketId.as_u64(); /// A bucket identifier. This identifier is assigned at runtime. #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd, Hash)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct BucketId(BorTag); impl From for BucketId { diff --git a/crates/template_lib/src/models/component.rs b/crates/template_lib/src/models/component.rs index 92718c7d1d..faac21537e 100644 --- a/crates/template_lib/src/models/component.rs +++ b/crates/template_lib/src/models/component.rs @@ -34,11 +34,7 @@ const TAG: u64 = BinaryTag::ComponentAddress.as_u64(); /// A component's unique global identifier. #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ComponentAddress(#[cfg_attr(feature = "ts", ts(type = "string"))] BorTag); impl ComponentAddress { diff --git a/crates/template_lib/src/models/confidential_proof.rs b/crates/template_lib/src/models/confidential_proof.rs index 4ae31f824a..e29e2b0625 100644 --- a/crates/template_lib/src/models/confidential_proof.rs +++ b/crates/template_lib/src/models/confidential_proof.rs @@ -15,11 +15,7 @@ use crate::{ /// A statement for confidential and revealed outputs. A statement must contain either confidential outputs or non-zero /// revealed funds or both. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ConfidentialOutputStatement { /// Output that is transferred to the receiver account pub output: Option, @@ -58,11 +54,7 @@ impl ConfidentialOutputStatement { /// /// Withdrawals can be revealed only, confidential only, or a mix of both. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ConfidentialWithdrawProof { pub inputs: Vec, /// The amount to withdraw from revealed funds i.e. the revealed funds as inputs diff --git a/crates/template_lib/src/models/encrypted_data.rs b/crates/template_lib/src/models/encrypted_data.rs index 8475ab35f5..de7e0366d7 100644 --- a/crates/template_lib/src/models/encrypted_data.rs +++ b/crates/template_lib/src/models/encrypted_data.rs @@ -8,11 +8,7 @@ use tari_template_lib_types::serde_helpers; /// as well as Minotari burns #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize))] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct EncryptedData( #[serde(with = "serde_helpers::dynamic_hex")] #[cfg_attr(feature = "ts", ts(type = "string"))] diff --git a/crates/template_lib/src/models/layer_one_commitment.rs b/crates/template_lib/src/models/layer_one_commitment.rs index f5794490d0..441516a27d 100644 --- a/crates/template_lib/src/models/layer_one_commitment.rs +++ b/crates/template_lib/src/models/layer_one_commitment.rs @@ -18,11 +18,7 @@ const TAG: u64 = BinaryTag::UnclaimedConfidentialOutputAddress.as_u64(); /// This substate is created when a L1 UTXO is detected as burnt, and consumed when a user submits a valid claim burn /// transaction. #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] #[serde(transparent)] pub struct UnclaimedConfidentialOutputAddress(#[cfg_attr(feature = "ts", ts(type = "string"))] BorTag); @@ -66,6 +62,12 @@ impl TryFrom<&[u8]> for UnclaimedConfidentialOutputAddress { } } +impl From<[u8; ObjectKey::LENGTH]> for UnclaimedConfidentialOutputAddress { + fn from(value: [u8; ObjectKey::LENGTH]) -> Self { + Self(BorTag::new(ObjectKey::from_array(value))) + } +} + impl Display for UnclaimedConfidentialOutputAddress { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "commitment_{}", self.0.inner()) diff --git a/crates/template_lib/src/models/metadata.rs b/crates/template_lib/src/models/metadata.rs index 7b7d5469df..b5f52b3643 100644 --- a/crates/template_lib/src/models/metadata.rs +++ b/crates/template_lib/src/models/metadata.rs @@ -30,11 +30,7 @@ const TAG: u64 = BinaryTag::Metadata as u64; /// A collection of user-defined data used to describe other types, for example, non-fungible tokens or events #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Metadata(BorTag, TAG>); impl Metadata { diff --git a/crates/template_lib/src/models/non_fungible.rs b/crates/template_lib/src/models/non_fungible.rs index 7fa9cc4b09..a780ccb3ad 100644 --- a/crates/template_lib/src/models/non_fungible.rs +++ b/crates/template_lib/src/models/non_fungible.rs @@ -21,11 +21,7 @@ use crate::{ /// The unique identification of a non-fungible token inside it's parent resource #[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, Hash)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))] pub enum NonFungibleId { U256( @@ -207,11 +203,7 @@ const TAG: u64 = BinaryTag::NonFungibleAddress.as_u64(); /// The unique identifier of a non-fungible index in the Tari network #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct NonFungibleAddress(BorTag); #[cfg(feature = "borsh")] @@ -235,11 +227,7 @@ mod borsh_impl { /// A NonFungibleId namespaced by a ResourceAddress. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))] pub struct NonFungibleAddressContents { resource_address: ResourceAddress, diff --git a/crates/template_lib/src/models/proof.rs b/crates/template_lib/src/models/proof.rs index 5025ce8474..a675e36a6f 100644 --- a/crates/template_lib/src/models/proof.rs +++ b/crates/template_lib/src/models/proof.rs @@ -37,11 +37,7 @@ const TAG: u64 = BinaryTag::ProofId.as_u64(); /// The unique identification of a proof during a transaction execution #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd, Hash)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ProofId(BorTag); impl From for ProofId { diff --git a/crates/template_lib/src/models/resource.rs b/crates/template_lib/src/models/resource.rs index 2afe3a6686..a8ab6f45f7 100644 --- a/crates/template_lib/src/models/resource.rs +++ b/crates/template_lib/src/models/resource.rs @@ -35,11 +35,7 @@ const TAG: u64 = BinaryTag::ResourceAddress.as_u64(); /// The globally-unique identifier of a resource. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ResourceAddress(#[cfg_attr(feature = "ts", ts(type = "string"))] BorTag); impl ResourceAddress { diff --git a/crates/template_lib/src/models/stealth.rs b/crates/template_lib/src/models/stealth.rs index ddf40bb435..6276d34f28 100644 --- a/crates/template_lib/src/models/stealth.rs +++ b/crates/template_lib/src/models/stealth.rs @@ -11,11 +11,7 @@ use crate::models::StealthUnspentOutput; /// A statement for stealth outputs. A statement must contain confidential outputs #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct StealthOutputsStatement { /// The stealth outputs that are to be created pub outputs: Vec, @@ -31,11 +27,7 @@ pub struct StealthOutputsStatement { /// A statement for stealth outputs. A statement must contain confidential outputs #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct StealthInput { /// The commitment of the unspent output being spent pub commitment: PedersenCommitmentBytes, @@ -45,11 +37,7 @@ pub struct StealthInput { } /// A statement for stealth outputs. A statement must contain confidential outputs #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct StealthInputsStatement { /// The stealth inputs that are to be spent pub inputs: Vec, @@ -58,11 +46,7 @@ pub struct StealthInputsStatement { } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct StealthTransferStatement { pub inputs_statement: StealthInputsStatement, pub outputs_statement: StealthOutputsStatement, diff --git a/crates/template_lib/src/models/unspent_output.rs b/crates/template_lib/src/models/unspent_output.rs index feb013e628..1a034a134a 100644 --- a/crates/template_lib/src/models/unspent_output.rs +++ b/crates/template_lib/src/models/unspent_output.rs @@ -16,11 +16,7 @@ use crate::models::{EncryptedData, ViewableBalanceProof}; /// - **viewable_balance_proof** - an optional verifiable balance proof that must be provided and valid if the view key /// is enabled for a resource. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct UnspentOutput { pub commitment: PedersenCommitmentBytes, /// Public nonce (R) that was used to generate the commitment mask @@ -34,11 +30,7 @@ pub struct UnspentOutput { } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct StealthUnspentOutput { pub output: UnspentOutput, /// The public key that must prove ownership of this UTXO. This is typically a one time "stealth" public key diff --git a/crates/template_lib/src/models/vault.rs b/crates/template_lib/src/models/vault.rs index c459f6bcf4..e279cc3514 100644 --- a/crates/template_lib/src/models/vault.rs +++ b/crates/template_lib/src/models/vault.rs @@ -64,11 +64,7 @@ const TAG: u64 = BinaryTag::VaultId as u64; /// A vault's unique identification in the Tari network #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct VaultId(#[cfg_attr(feature = "ts", ts(type = "string"))] BorTag); impl VaultId { diff --git a/crates/template_lib/src/models/viewable_balance.rs b/crates/template_lib/src/models/viewable_balance.rs index d669f7dc2d..d99a07c79d 100644 --- a/crates/template_lib/src/models/viewable_balance.rs +++ b/crates/template_lib/src/models/viewable_balance.rs @@ -24,11 +24,7 @@ use tari_template_lib_types::crypto::{PedersenCommitmentBytes, RistrettoPublicKe /// /// The proof size is static (256 bytes). #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ViewableBalanceProof { /// The encrypted value that takes the form: E = v.G + r.P /// where v is the value, G is the generator, r is the secret_nonce and P is the view key diff --git a/crates/template_lib/src/resource/mod.rs b/crates/template_lib/src/resource/mod.rs index 6cdf78ae9c..3b3c272ebb 100644 --- a/crates/template_lib/src/resource/mod.rs +++ b/crates/template_lib/src/resource/mod.rs @@ -62,11 +62,7 @@ pub use manager::*; /// TypeScript bindings when the `ts` feature is enabled. #[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum ResourceType { /// Fungible tokens do not have individual identity, making them interchangeable. /// Examples include monetary units, liquidity pool tokens, or tokenized shares. diff --git a/crates/template_lib_types/src/amount/amount.rs b/crates/template_lib_types/src/amount/amount.rs index d42c97262b..b933ad23ab 100644 --- a/crates/template_lib_types/src/amount/amount.rs +++ b/crates/template_lib_types/src/amount/amount.rs @@ -18,11 +18,7 @@ pub type I192 = bnum::BInt<3>; // 3 x 64 bits = 192 bits /// This allows Tari to support a massive number tokens within resources. /// e.g. 2 ETH = 2 x 10^18 Gwei. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Amount(#[cfg_attr(feature = "ts", ts(type = "string | number"))] pub(super) I192); impl Amount { diff --git a/crates/template_lib_types/src/crypto/commitment.rs b/crates/template_lib_types/src/crypto/commitment.rs index 40d4afdf70..0b4370c044 100644 --- a/crates/template_lib_types/src/crypto/commitment.rs +++ b/crates/template_lib_types/src/crypto/commitment.rs @@ -19,11 +19,7 @@ use crate::{ #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default, Serialize, Deserialize)] #[serde(transparent)] #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct PedersenCommitmentBytes( #[serde(with = "serde_helpers::fixed_hex")] #[cfg_attr(feature = "ts", ts(type = "string"))] diff --git a/crates/template_lib_types/src/crypto/commitment_signature.rs b/crates/template_lib_types/src/crypto/commitment_signature.rs index 5453cb2552..8a13300c61 100644 --- a/crates/template_lib_types/src/crypto/commitment_signature.rs +++ b/crates/template_lib_types/src/crypto/commitment_signature.rs @@ -5,11 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::crypto::{scalar::Scalar32Bytes, InvalidByteLengthError, PedersenCommitmentBytes}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct CommitmentSignatureBytes { public_nonce: PedersenCommitmentBytes, u: Scalar32Bytes, diff --git a/crates/template_lib_types/src/crypto/range_proof.rs b/crates/template_lib_types/src/crypto/range_proof.rs index 64813de852..ba5edfe27a 100644 --- a/crates/template_lib_types/src/crypto/range_proof.rs +++ b/crates/template_lib_types/src/crypto/range_proof.rs @@ -11,11 +11,7 @@ use crate::serde_helpers; /// The length of the range proof is limited to a maximum size (1024 bytes) to mitigate potential denial-of-service /// attacks. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct RangeProofBytes( #[serde( serialize_with = "serde_helpers::dynamic_hex::serialize", diff --git a/crates/template_lib_types/src/crypto/ristretto.rs b/crates/template_lib_types/src/crypto/ristretto.rs index a4e241f799..53898acd4f 100644 --- a/crates/template_lib_types/src/crypto/ristretto.rs +++ b/crates/template_lib_types/src/crypto/ristretto.rs @@ -12,11 +12,7 @@ use crate::{crypto::InvalidByteLengthError, hex::fixed_bytes_from_hex, serde_hel /// A Ristretto public key byte contents #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct RistrettoPublicKeyBytes( #[serde(with = "serde_helpers::fixed_hex")] #[cfg_attr(feature = "ts", ts(type = "string"))] diff --git a/crates/template_lib_types/src/crypto/scalar.rs b/crates/template_lib_types/src/crypto/scalar.rs index 48300ce4fc..a301607d64 100644 --- a/crates/template_lib_types/src/crypto/scalar.rs +++ b/crates/template_lib_types/src/crypto/scalar.rs @@ -9,11 +9,7 @@ use crate::{crypto::InvalidByteLengthError, serde_helpers}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(transparent)] #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize))] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Scalar32Bytes( #[serde(with = "serde_helpers::fixed_hex")] #[cfg_attr(feature = "ts", ts(type = "string"))] diff --git a/crates/template_lib_types/src/crypto/schnorr.rs b/crates/template_lib_types/src/crypto/schnorr.rs index 588a188eff..c3da781e71 100644 --- a/crates/template_lib_types/src/crypto/schnorr.rs +++ b/crates/template_lib_types/src/crypto/schnorr.rs @@ -8,11 +8,7 @@ use crate::crypto::{scalar::Scalar32Bytes, InvalidByteLengthError, RistrettoPubl #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize))] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct SchnorrSignatureBytes { public_nonce: RistrettoPublicKeyBytes, signature: Scalar32Bytes, diff --git a/crates/template_lib_types/src/crypto/tag_byte.rs b/crates/template_lib_types/src/crypto/tag_byte.rs index d4d2781304..754e48db8a 100644 --- a/crates/template_lib_types/src/crypto/tag_byte.rs +++ b/crates/template_lib_types/src/crypto/tag_byte.rs @@ -2,13 +2,10 @@ // SPDX-License-Identifier: BSD-3-Clause use serde::{Deserialize, Serialize}; +use tari_template_abi::rust::fmt; -#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct UtxoTagByte(u8); impl UtxoTagByte { @@ -20,3 +17,9 @@ impl UtxoTagByte { self.0 } } + +impl fmt::Display for UtxoTagByte { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "TagByte({})", self.0) + } +} diff --git a/crates/template_lib_types/src/entity_id.rs b/crates/template_lib_types/src/entity_id.rs index 27619ce90b..f05b20d3bf 100644 --- a/crates/template_lib_types/src/entity_id.rs +++ b/crates/template_lib_types/src/entity_id.rs @@ -11,11 +11,7 @@ use tari_template_abi::rust::{ use crate::serde_helpers; #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default, serde::Serialize, serde::Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct EntityId( #[cfg_attr(feature = "ts", ts(type = "string"))] #[serde(with = "serde_helpers::fixed_hex")] @@ -115,11 +111,7 @@ impl Display for EntityId { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default, serde::Serialize, serde::Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct ComponentKey( #[serde(with = "serde_helpers::fixed_hex")] #[cfg_attr(feature = "ts", ts(type = "string"))] diff --git a/crates/template_lib_types/src/hash.rs b/crates/template_lib_types/src/hash.rs index 091db95ac5..609484e06f 100644 --- a/crates/template_lib_types/src/hash.rs +++ b/crates/template_lib_types/src/hash.rs @@ -33,11 +33,7 @@ use crate::{hex::fixed_bytes_from_hex, serde_helpers}; /// Representation of a 32-byte hash value #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash, Default, Serialize, Deserialize)] #[serde(transparent)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Hash( #[serde(with = "serde_helpers::fixed_hex")] #[cfg_attr(feature = "ts", ts(type = "string"))] diff --git a/crates/template_manager/src/implementation/service.rs b/crates/template_manager/src/implementation/service.rs index a8debb0e55..1ad9b467c9 100644 --- a/crates/template_manager/src/implementation/service.rs +++ b/crates/template_manager/src/implementation/service.rs @@ -29,7 +29,7 @@ use tari_ootle_p2p::proto::rpc::TemplateType; use tari_ootle_storage::global::{DbTemplateType, DbTemplateUpdate, TemplateStatus}; use tari_shutdown::ShutdownSignal; use tari_template_lib::types::{crypto::RistrettoPublicKeyBytes, Hash, TemplateAddress}; -use tari_validator_node_client::types::{ArgDef, FunctionDef, TemplateAbi}; +use tari_validator_node_client::types::{FunctionDef, TemplateAbi}; use tari_validator_node_rpc::client::TariValidatorNodeRpcClientFactory; use tokio::{ sync::{mpsc, oneshot}, @@ -265,14 +265,7 @@ where .iter() .map(|f| FunctionDef { name: f.name.clone(), - arguments: f - .arguments - .iter() - .map(|a| ArgDef { - name: a.name.to_string(), - arg_type: a.arg_type.to_string(), - }) - .collect(), + arguments: f.arguments.iter().cloned().collect(), output: f.output.to_string(), is_mut: f.is_mut, }) diff --git a/crates/template_manager/src/implementation/template_sync_task.rs b/crates/template_manager/src/implementation/template_sync_task.rs index eae35989f8..e44d23e737 100644 --- a/crates/template_manager/src/implementation/template_sync_task.rs +++ b/crates/template_manager/src/implementation/template_sync_task.rs @@ -195,7 +195,7 @@ where return Err(TemplateSyncError::NoMoreSyncValidators); }; - let mut client = self.client_factory.create_client(&vn.address); + let client = self.client_factory.create_client(&vn.address); match client.client_connection().await { Ok(conn) => { self.recently_failed_clients.remove(&vn.address); diff --git a/crates/transaction/src/transaction.rs b/crates/transaction/src/transaction.rs index 35dd9d05e0..69efec259d 100644 --- a/crates/transaction/src/transaction.rs +++ b/crates/transaction/src/transaction.rs @@ -26,11 +26,7 @@ use crate::{ }; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum Transaction { V1(TransactionV1), } diff --git a/crates/transaction/src/transaction_id.rs b/crates/transaction/src/transaction_id.rs index e8104fbf94..6658d03b12 100644 --- a/crates/transaction/src/transaction_id.rs +++ b/crates/transaction/src/transaction_id.rs @@ -15,11 +15,7 @@ use tari_template_lib::types::{from_hex, hex::write_hex_fmt, Hash}; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, Default, BorshSerialize)] #[serde(transparent)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct TransactionId( #[serde(with = "serde_with::hex")] #[cfg_attr(feature = "ts", ts(type = "string"))] diff --git a/crates/transaction/src/unsigned_transaction.rs b/crates/transaction/src/unsigned_transaction.rs index 05af9d3a94..25cfcd6f63 100644 --- a/crates/transaction/src/unsigned_transaction.rs +++ b/crates/transaction/src/unsigned_transaction.rs @@ -12,11 +12,7 @@ use tari_template_lib::models::ComponentAddress; use crate::{TransactionSignature, UnsealedTransactionV1, UnsignedTransactionV1}; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum UnsignedTransaction { V1(UnsignedTransactionV1), } diff --git a/crates/transaction/src/v1/signature.rs b/crates/transaction/src/v1/signature.rs index 3e10bd143c..2b725f4c58 100644 --- a/crates/transaction/src/v1/signature.rs +++ b/crates/transaction/src/v1/signature.rs @@ -22,11 +22,7 @@ use tari_template_lib::types::crypto::{RistrettoPublicKeyBytes, SchnorrSignature use crate::{UnsealedTransactionV1, UnsignedTransactionV1}; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct TransactionSealSignature { public_key: RistrettoPublicKeyBytes, signature: SchnorrSignatureBytes, @@ -81,11 +77,7 @@ impl TransactionSealSignature { } #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct TransactionSignature { public_key: RistrettoPublicKeyBytes, signature: SchnorrSignatureBytes, diff --git a/crates/transaction/src/v1/transaction.rs b/crates/transaction/src/v1/transaction.rs index 86b78cba44..9b1d987c73 100644 --- a/crates/transaction/src/v1/transaction.rs +++ b/crates/transaction/src/v1/transaction.rs @@ -33,11 +33,7 @@ use crate::{ const LOG_TARGET: &str = "tari::ootle::transaction::transaction"; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct TransactionV1 { body: UnsealedTransactionV1, seal_signature: TransactionSealSignature, diff --git a/crates/transaction/src/v1/unsealed.rs b/crates/transaction/src/v1/unsealed.rs index 5df788c229..47be2e97de 100644 --- a/crates/transaction/src/v1/unsealed.rs +++ b/crates/transaction/src/v1/unsealed.rs @@ -19,11 +19,7 @@ use crate::{ const LOG_TARGET: &str = "tari::ootle::transaction::transaction"; #[derive(Debug, Clone, Serialize, Deserialize, Default)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct UnsealedTransactionV1 { transaction: UnsignedTransactionV1, signatures: Vec, diff --git a/crates/transaction/src/v1/unsigned.rs b/crates/transaction/src/v1/unsigned.rs index f515932fdc..a048c3e12f 100644 --- a/crates/transaction/src/v1/unsigned.rs +++ b/crates/transaction/src/v1/unsigned.rs @@ -17,11 +17,7 @@ use tari_template_lib::models::ComponentAddress; use crate::builder::TransactionBuilder; #[derive(Debug, Clone, Serialize, Deserialize, Default)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct UnsignedTransactionV1 { pub network: u8, pub fee_instructions: Vec, diff --git a/crates/transaction_manifest/src/generator.rs b/crates/transaction_manifest/src/generator.rs index bf8eb6dddf..cd50a5c255 100644 --- a/crates/transaction_manifest/src/generator.rs +++ b/crates/transaction_manifest/src/generator.rs @@ -232,9 +232,9 @@ fn lit_to_arg(lit: &Lit) -> Result { "u128" => Ok(call_arg!(i.base10_parse::()?)), "i8" => Ok(call_arg!(i.base10_parse::()?)), "i16" => Ok(call_arg!(i.base10_parse::()?)), - "" | "i32" => Ok(call_arg!(i.base10_parse::()?)), + "i32" => Ok(call_arg!(i.base10_parse::()?)), "i64" => Ok(call_arg!(i.base10_parse::()?)), - "i128" => Ok(call_arg!(i.base10_parse::()?)), + "" | "i128" => Ok(call_arg!(i.base10_parse::()?)), _ => Err(ManifestError::UnsupportedExpr(format!( r#"Unsupported integer suffix "{}""#, i.suffix() diff --git a/crates/validator_node_rpc/Cargo.toml b/crates/validator_node_rpc/Cargo.toml index bcbb5d9120..45cbdcfed9 100644 --- a/crates/validator_node_rpc/Cargo.toml +++ b/crates/validator_node_rpc/Cargo.toml @@ -20,7 +20,6 @@ tari_bor = { workspace = true, default-features = true } tari_consensus_types = { workspace = true } anyhow = { workspace = true } -async-trait = { workspace = true } prost = { workspace = true } serde = { workspace = true, default-features = true } thiserror = { workspace = true } diff --git a/crates/validator_node_rpc/src/client.rs b/crates/validator_node_rpc/src/client.rs index dee69015a9..480b0bbfb0 100644 --- a/crates/validator_node_rpc/src/client.rs +++ b/crates/validator_node_rpc/src/client.rs @@ -1,10 +1,9 @@ // Copyright 2023 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use std::{collections::HashMap, convert::TryInto, sync::Arc, time::Duration}; +use std::{collections::HashMap, convert::TryInto, future::Future, sync::Arc, time::Duration}; use anyhow::anyhow; -use async_trait::async_trait; use serde::{Deserialize, Serialize}; use tari_bor::decode; use tari_consensus_types::Decision; @@ -31,17 +30,22 @@ pub trait ValidatorNodeClientFactory: Send + Sync { fn create_client(&self, address: &TAddr) -> Self::Client; } -#[async_trait] pub trait ValidatorNodeRpcClient: Send + Sync { type Error: std::error::Error + Send + Sync + 'static; - async fn submit_transaction(&mut self, transaction: Transaction) -> Result; - async fn get_finalized_transaction_result( + fn submit_transaction( + &mut self, + transaction: Transaction, + ) -> impl Future> + Send; + fn get_finalized_transaction_result( &mut self, transaction_id: TransactionId, - ) -> Result; + ) -> impl Future> + Send; - async fn get_substate(&mut self, substate_req: SubstateRequirementRef<'_>) -> Result; + fn get_substate( + &mut self, + substate_req: SubstateRequirementRef<'_>, + ) -> impl Future> + Send; } #[derive(Debug, Clone, Deserialize, Serialize)] @@ -89,20 +93,23 @@ pub struct TariValidatorNodeRpcClient { pool: RpcMultiPool, } +impl TariValidatorNodeRpcClient { + pub fn new(address: TAddr, pool: RpcMultiPool) -> Self { + Self { address, pool } + } +} + impl TariValidatorNodeRpcClient { pub fn address(&self) -> &TAddr { &self.address } - pub async fn client_connection( - &mut self, - ) -> Result { + pub async fn client_connection(&self) -> Result { let client = self.pool.get_or_connect(&self.address.to_peer_id()).await?; Ok(client) } } -#[async_trait] impl ValidatorNodeRpcClient for TariValidatorNodeRpcClient { @@ -257,8 +264,8 @@ impl RpcMultiPool { } } - async fn get_or_connect( - &mut self, + pub async fn get_or_connect( + &self, addr: &PeerId, ) -> Result { let mut sessions = self.sessions.write().await; diff --git a/crates/validator_node_rpc/src/rpc_service.rs b/crates/validator_node_rpc/src/rpc_service.rs index 8b3d3b14bc..79295a4c08 100644 --- a/crates/validator_node_rpc/src/rpc_service.rs +++ b/crates/validator_node_rpc/src/rpc_service.rs @@ -5,8 +5,7 @@ use tari_ootle_p2p::proto::rpc as proto; use tari_rpc_framework::{Request, Response, RpcStatus, Streaming}; use tari_rpc_macros::tari_rpc; -#[tari_rpc(protocol_name = "/tari/validator/1.0.0", server_struct = ValidatorNodeRpcServer, client_struct = ValidatorNodeRpcClient -)] +#[tari_rpc(protocol_name = "/tari/validator/1.0.0", server_struct = ValidatorNodeRpcServer, client_struct = ValidatorNodeRpcClient)] pub trait ValidatorNodeRpcService: Send + Sync + 'static { #[rpc(method = 1)] async fn submit_transaction( @@ -33,10 +32,10 @@ pub trait ValidatorNodeRpcService: Send + Sync + 'static { ) -> Result, RpcStatus>; #[rpc(method = 5)] - async fn get_checkpoint( + async fn get_checkpoints( &self, - request: Request, - ) -> Result, RpcStatus>; + request: Request, + ) -> Result, RpcStatus>; #[rpc(method = 6)] async fn sync_state( @@ -49,4 +48,10 @@ pub trait ValidatorNodeRpcService: Send + Sync + 'static { &self, request: Request, ) -> Result, RpcStatus>; + + // #[rpc(method = 8)] + // async fn get_chain_summary( + // &self, + // request: Request, + // ) -> Result, RpcStatus>; } diff --git a/crates/wallet/sdk/src/apis/confidential_transfer.rs b/crates/wallet/sdk/src/apis/confidential_transfer.rs index ae961859ec..fda0abf4de 100644 --- a/crates/wallet/sdk/src/apis/confidential_transfer.rs +++ b/crates/wallet/sdk/src/apis/confidential_transfer.rs @@ -545,11 +545,7 @@ impl ConfidentialTransferParams { } #[derive(Debug, Clone, Copy, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum ConfidentialTransferInputSelection { ConfidentialOnly, RevealedOnly, diff --git a/crates/wallet/sdk/src/apis/key_manager.rs b/crates/wallet/sdk/src/apis/key_manager.rs index 022528ce1b..e313ec891d 100644 --- a/crates/wallet/sdk/src/apis/key_manager.rs +++ b/crates/wallet/sdk/src/apis/key_manager.rs @@ -21,11 +21,7 @@ use crate::{ pub type WalletKeyManager = KeyManager>; #[derive(Debug, Clone, Copy, Deserialize, Serialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/wallet-daemon-client/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export, export_to = "wallet-daemon-client/"))] #[serde(rename_all = "snake_case")] pub enum KeyBranch { /// The account key branch, used for deriving account keys. diff --git a/crates/wallet/sdk/src/models/account.rs b/crates/wallet/sdk/src/models/account.rs index 7cda305754..12b27e55ac 100644 --- a/crates/wallet/sdk/src/models/account.rs +++ b/crates/wallet/sdk/src/models/account.rs @@ -7,11 +7,7 @@ use tari_bor::{Deserialize, Serialize}; use tari_template_lib::{models::ComponentAddress, prelude::RistrettoPublicKeyBytes}; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct Account { pub name: Option, pub address: ComponentAddress, @@ -31,11 +27,7 @@ impl Display for Account { } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct AccountWithPublicKey { pub account: Account, pub owner_public_key: RistrettoPublicKeyBytes, @@ -70,11 +62,7 @@ impl Display for AccountWithPublicKey { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct NewAccountData { pub address: ComponentAddress, } diff --git a/crates/wallet/sdk/src/models/non_fungible_tokens.rs b/crates/wallet/sdk/src/models/non_fungible_tokens.rs index 1f3bc67a9b..823f1deadf 100644 --- a/crates/wallet/sdk/src/models/non_fungible_tokens.rs +++ b/crates/wallet/sdk/src/models/non_fungible_tokens.rs @@ -5,11 +5,7 @@ use tari_engine_types::serde_with; use tari_template_lib::models::{NonFungibleId, ResourceAddress, VaultId}; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct NonFungibleToken { pub vault_id: VaultId, pub nft_id: NonFungibleId, diff --git a/crates/wallet/sdk/src/models/wallet_transaction.rs b/crates/wallet/sdk/src/models/wallet_transaction.rs index 0cbe780017..334fe35ad0 100644 --- a/crates/wallet/sdk/src/models/wallet_transaction.rs +++ b/crates/wallet/sdk/src/models/wallet_transaction.rs @@ -13,11 +13,7 @@ use time::PrimitiveDateTime; use crate::models::NewAccountData; #[derive(Debug, Clone, Serialize, Deserialize)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub struct WalletTransaction { #[cfg_attr(feature = "ts", ts(type = "string"))] pub id: TransactionId, @@ -38,11 +34,7 @@ pub struct WalletTransaction { } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Default)] -#[cfg_attr( - feature = "ts", - derive(ts_rs::TS), - ts(export, export_to = "../../bindings/src/types/") -)] +#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))] pub enum TransactionStatus { #[default] New, diff --git a/crates/wallet/sdk/src/network.rs b/crates/wallet/sdk/src/network.rs index 87d0be01eb..4d43ded327 100644 --- a/crates/wallet/sdk/src/network.rs +++ b/crates/wallet/sdk/src/network.rs @@ -95,7 +95,7 @@ pub struct SubstateListItem { pub module_name: Option, pub version: u32, pub template_address: Option, - pub timestamp: u64, + pub timestamp: PrimitiveDateTime, } #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/integration_tests/src/indexer.rs b/integration_tests/src/indexer.rs index 9e997f80c2..adf4d31c79 100644 --- a/integration_tests/src/indexer.rs +++ b/integration_tests/src/indexer.rs @@ -34,7 +34,7 @@ use tari_common::{ use tari_crypto::tari_utilities::{hex::Hex, message_format::MessageFormat}; use tari_engine_types::substate::SubstateId; use tari_indexer::{ - config::{ApplicationConfig, EventFilterConfig, IndexerConfig}, + config::{ApplicationConfig, IndexerConfig}, run_indexer, }; use tari_indexer_client::{ @@ -192,12 +192,7 @@ pub async fn spawn_indexer(world: &mut TariWorld, indexer_name: String, base_nod config.indexer.graphql_address = Some(format!("127.0.0.1:{}", graphql_port).parse().unwrap()); // store all events in the database using an empty filter - config.indexer.event_filters = vec![EventFilterConfig { - topic: None, - entity_id: None, - substate_id: None, - template_address: None, - }]; + config.indexer.event_filters = vec![]; // Add all other VNs as peer seeds config.peer_seeds.peer_seeds = StringList::from(peer_seeds); diff --git a/networking/core/src/handle.rs b/networking/core/src/handle.rs index 68f753eca7..c196ed96fb 100644 --- a/networking/core/src/handle.rs +++ b/networking/core/src/handle.rs @@ -218,7 +218,7 @@ impl NetworkingHandle { } pub async fn open_substream( - &mut self, + &self, peer_id: PeerId, protocol_id: &StreamProtocol, ) -> Result, NetworkingError> { @@ -236,7 +236,7 @@ impl NetworkingHandle { } pub async fn open_framed_substream( - &mut self, + &self, peer_id: PeerId, protocol_id: &StreamProtocol, max_frame_size: usize, @@ -245,12 +245,12 @@ impl NetworkingHandle { Ok(framing::canonical(substream.stream, max_frame_size)) } - pub async fn connect_rpc(&mut self, peer_id: PeerId) -> Result + pub async fn connect_rpc(&self, peer_id: PeerId) -> Result where T: From + NamedProtocolService { self.connect_rpc_using_builder(RpcClientBuilder::new(peer_id)).await } - pub async fn connect_rpc_using_builder(&mut self, builder: RpcClientBuilder) -> Result + pub async fn connect_rpc_using_builder(&self, builder: RpcClientBuilder) -> Result where T: From + NamedProtocolService { let protocol = StreamProtocol::new(T::PROTOCOL_NAME); debug!( diff --git a/utilities/db_inspector/src/webserver/either_cf.rs b/utilities/db_inspector/src/webserver/either_cf.rs deleted file mode 100644 index 2aa235263b..0000000000 --- a/utilities/db_inspector/src/webserver/either_cf.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2025 The Tari Project -// SPDX-License-Identifier: BSD-3-Clause - -use serde::Serialize; -use tari_state_store_rocksdb::{ - codecs::{DbCodec, EncodeVec}, - error::RocksDbStorageError, - traits::Cf, -}; - -pub struct EitherCf { - _phantom: std::marker::PhantomData<(F, G)>, -} - -impl EitherCf { - pub fn new() -> Self { - Self { - _phantom: std::marker::PhantomData, - } - } -} - -impl Cf for EitherCf -where - F: Cf, - G: Cf, -{ - type Key = EitherValue; - type KeyCodec = EitherCodec; - type Value = EitherValue; - type ValueCodec = EitherCodec; - - fn name() -> &'static str { - // F and G must have the same name - F::name() - } -} - -#[derive(Serialize)] -pub enum EitherValue { - First(V1), - Second(V2), -} - -#[derive(Default)] -pub struct EitherCodec { - first: C1, - second: C2, -} - -impl DbCodec> for EitherCodec -where - C1: DbCodec, - C2: DbCodec, -{ - fn encode(&self, value: &EitherValue) -> Result { - match value { - EitherValue::First(v) => self.first.encode(v), - EitherValue::Second(v) => self.second.encode(v), - } - } - - fn decode(&self, bytes: &[u8]) -> Result, RocksDbStorageError> { - if let Ok(v) = self.first.decode(bytes) { - return Ok(EitherValue::First(v)); - } - self.second.decode(bytes).map(EitherValue::Second) - } -} diff --git a/utilities/db_inspector/src/webserver/handlers/tables.rs b/utilities/db_inspector/src/webserver/handlers/tables.rs index abf57bc177..354408829d 100644 --- a/utilities/db_inspector/src/webserver/handlers/tables.rs +++ b/utilities/db_inspector/src/webserver/handlers/tables.rs @@ -197,8 +197,7 @@ fn create_table_for_cf(cf_name: &str) -> TableResponse { Column::new("version", "Version"), Column::new("substate_value", "Substate Value"), Column::new("state_hash", "State Hash"), - Column::new("created_by_shard", "Created By Shard"), - Column::new("created_at_epoch", "Created At Epoch"), + Column::new("created", "Created"), Column::new("destroyed", "Destroyed"), ]); }, diff --git a/utilities/db_inspector/src/webserver/mod.rs b/utilities/db_inspector/src/webserver/mod.rs index 6cf24c378e..2d38e2f463 100644 --- a/utilities/db_inspector/src/webserver/mod.rs +++ b/utilities/db_inspector/src/webserver/mod.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: BSD-3-Clause mod context; -mod either_cf; mod error; mod handlers; mod server; diff --git a/utilities/db_inspector/src/webserver/server.rs b/utilities/db_inspector/src/webserver/server.rs index 292bf27910..dc61538eb0 100644 --- a/utilities/db_inspector/src/webserver/server.rs +++ b/utilities/db_inspector/src/webserver/server.rs @@ -16,7 +16,7 @@ use reqwest::{header, StatusCode}; use tari_state_store_rocksdb::{column_families, traits::Cf}; use tower_http::cors::CorsLayer; -use crate::webserver::{context::HandlerContext, either_cf::EitherCf, handlers}; +use crate::webserver::{context::HandlerContext, handlers}; const LOG_TARGET: &str = "tari::ootle::swarm::webserver"; @@ -106,10 +106,8 @@ pub async fn run(context: HandlerContext) -> anyhow::Result<()> { column_families::epoch_checkpoint::EpochCheckpointCf, column_families::burnt_utxo::BurntUtxoCf, column_families::burnt_utxo::ProposedInBlockIndex, - EitherCf::< - column_families::lock_conflict::LockConflictCf, - column_families::lock_conflict::LockConflictBlockIdIndex, - >::new(), + column_families::lock_conflict::LockConflictCf, + column_families::lock_conflict::LockConflictBlockIdIndex, column_families::evicted_node::EvictedNodeCf, column_families::validator_node_epoch_stats::ValidatorNodeEpochStatsCf );