diff --git a/.gitignore b/.gitignore index 5a66488..098be63 100644 --- a/.gitignore +++ b/.gitignore @@ -376,3 +376,4 @@ sb.debug # Rust /target +.gitnexus diff --git a/Cargo.lock b/Cargo.lock index f0aed88..f1cab47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -401,9 +401,9 @@ dependencies = [ [[package]] name = "chia-sdk-client" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8b56f14dfd5ce188bece4d0c3478d0dc9fee15f3b83e1b34aa910861e61f4b8" +checksum = "e8580b887f1173edf2458388a17088eb7ca1553c992540f4a8067fceb37f9d8e" dependencies = [ "chia-protocol", "chia-sdk-types", @@ -420,9 +420,9 @@ dependencies = [ [[package]] name = "chia-sdk-coinset" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02175bf3670878f6c43fcd4497c9b7b9d8e3cf43d90dff625997db50a3d71778" +checksum = "0f506b96f9fda1038315a3aa6a27ee57fc652aa118e21977ac35b24f6fe8d0a3" dependencies = [ "chia-protocol", "hex", @@ -434,9 +434,9 @@ dependencies = [ [[package]] name = "chia-sdk-daemon" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b44f9008f55d605ab688e239d8303e6240beca329d27838e0ad6340422bef13a" +checksum = "49d2cd66d8cd5447920e978b46c04018c6ed2ebd3d379ccca506cdd7e6fbfa86" dependencies = [ "chia-sdk-client", "chia-sdk-coinset", @@ -452,9 +452,9 @@ dependencies = [ [[package]] name = "chia-sdk-derive" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e9e366cbc576221da519a08544b546cbf0441a4d3e8bbd8e69f3a06480a6af4" +checksum = "6582e68e7a3577a2d68f49ce996381c25b1c3e7ed8987f892640ae1b2f97a512" dependencies = [ "convert_case 0.8.0", "quote", @@ -463,9 +463,9 @@ dependencies = [ [[package]] name = "chia-sdk-driver" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2677cf560410db034c8bb5de1e07dec2021b12fd986981390654e260a2b856" +checksum = "33d22cc417877a290eff196fe851cfc1175a5432166f8d9bedeb9f55e010bc76" dependencies = [ "bigdecimal", "bip39", @@ -490,14 +490,15 @@ dependencies = [ "num-bigint", "rand 0.9.5", "rand_chacha 0.9.0", + "serde", "thiserror 2.0.17", ] [[package]] name = "chia-sdk-signer" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83f8553345d14f9eb89f07df0d3854162d818d21acf27140997ae77256dc7883" +checksum = "512d32dc79e27a7bd1cbd7f9fc899dcd9cbac0fbabe5ad956842097ab440ef33" dependencies = [ "chia-bls 0.36.1", "chia-consensus", @@ -515,9 +516,9 @@ dependencies = [ [[package]] name = "chia-sdk-test" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de32a1cc7124f151401d553413d45b88b607dbfa69cf1721c7daab75b717d1a2" +checksum = "117394d011b2424785f2a3405241302637ef57946e48541ebd03dc81f2360e89" dependencies = [ "anyhow", "bincode", @@ -527,6 +528,7 @@ dependencies = [ "chia-protocol", "chia-puzzle-types", "chia-sdk-client", + "chia-sdk-coinset", "chia-sdk-signer", "chia-sdk-types", "chia-secp", @@ -538,12 +540,14 @@ dependencies = [ "futures-channel", "futures-util", "hex", + "hex-literal", "indexmap", "itertools 0.13.0", "prettytable-rs", "rand 0.9.5", "rand_chacha 0.9.0", "serde", + "serde_json", "signature 2.2.0", "thiserror 2.0.17", "tokio", @@ -553,9 +557,9 @@ dependencies = [ [[package]] name = "chia-sdk-types" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0891df37e7b053682b7bec452321d0b2205c20de8792e96470d571390cfd5b48" +checksum = "3a4c4fb7e3ee75601e583efae625cd65e3bbcacda5be5d341b89c6f05a4b1702" dependencies = [ "chia-bls 0.36.1", "chia-consensus", @@ -573,14 +577,15 @@ dependencies = [ "rue-compiler", "rue-lir", "rue-options", + "serde", "thiserror 2.0.17", ] [[package]] name = "chia-sdk-utils" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7831343041ceb5f170ef4ff8d8c2b91c055ab75f8a8e075e8bef2c423a0c47c" +checksum = "bdf8cc5b71cd030775165aa1a107f3a138b79838f215f1047ca3484fe10f28d9" dependencies = [ "bech32", "chia-protocol", @@ -697,9 +702,9 @@ dependencies = [ [[package]] name = "chia-wallet-sdk" -version = "0.34.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d57cc9efa1f6f4cca48b38ec4ee461e2d06ccdc71abc9f422b6b0f4c4940732" +checksum = "fea288e24663821de8679cc27458f2ebb9e61f54b5cf2f92249657b904b300d9" dependencies = [ "chia-bls 0.36.1", "chia-consensus", @@ -1066,7 +1071,7 @@ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "datalayer-driver" -version = "4.0.0" +version = "5.0.0" dependencies = [ "anyhow", "chia-bls 0.36.1", @@ -1794,6 +1799,25 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "indexmap" version = "2.11.4" @@ -2767,9 +2791,9 @@ dependencies = [ [[package]] name = "rue-ast" -version = "0.6.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8feffcdd1f81db8d83980714cdd15d53608f7cc49e4d4a1c52d0fe1d523c4b" +checksum = "82e99e24bfbaa8fe116b23d3fa1df09e2f59982e654e04430f8fad0d348271fa" dependencies = [ "paste", "rue-parser", @@ -2777,13 +2801,14 @@ dependencies = [ [[package]] name = "rue-compiler" -version = "0.6.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b58c388afe6e7fb78e63f43b455c57b6f788f1e2b65ae895e9ff38039ab2fdc" +checksum = "59f127828ed5bdd04dee995b5028f3ae291394850e66856bb6998198c51c4514" dependencies = [ "clvmr", "hex", "id-arena", + "include_dir", "indexmap", "log", "num-bigint", @@ -2802,19 +2827,18 @@ dependencies = [ [[package]] name = "rue-diagnostic" -version = "0.6.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cccb3041f21c77e80ea8fdb03e7214b91195d939f3146f054e27020ea1a9" +checksum = "d25461b6850121106735e1abe334ecf2bf56e27244284d46ef5dfbc0e4bc2894" dependencies = [ - "derive_more", "thiserror 2.0.17", ] [[package]] name = "rue-hir" -version = "0.6.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d73674bfcd164e453dbeabfa99cb952827abf7bc0540ed5bf6d2ccea97d06a" +checksum = "cd0cc66defc213a291efd185f0ff18f703abec2850c931a459ce187ee667e1fd" dependencies = [ "derive_more", "hex", @@ -2830,15 +2854,15 @@ dependencies = [ [[package]] name = "rue-lexer" -version = "0.6.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68345f23ba80d548d4a671de14e455de74ae58fccfa436db105b35308a1780ed" +checksum = "579df9994fcc6485832d6a19f77309f38d12cf48bb73b7a2b99eb4ae094aaadf" [[package]] name = "rue-lir" -version = "0.6.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099f3c3d6b432bb94cf8876b7f71b650d6887ae9193e8063c529feca37276b6f" +checksum = "c3ba00e6908f8baf1de08b41f11213a1bc0ef4dfd75f47ebca341665b1d1f5b7" dependencies = [ "chialisp", "clvm-traits 0.28.1", @@ -2854,9 +2878,9 @@ dependencies = [ [[package]] name = "rue-options" -version = "0.6.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f94c541b1397b7fbc4aaba36440c0bc11ddb703b024a424dd2fe193ec413b7" +checksum = "a6c9855c49ee3f3f248004bfb2daf166ca0648a46820f95255fedb4e815b269d" dependencies = [ "serde", "thiserror 2.0.17", @@ -2865,9 +2889,9 @@ dependencies = [ [[package]] name = "rue-parser" -version = "0.6.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d23577d98f535c02d2898e0a0e9cdf04b82d1ea91b15cd31e66141bce73c4c5" +checksum = "2eeffa2e32037202a8fb8a4361f06bf01dd0a7d7ace092dfab3ff1aa5f2cd42f" dependencies = [ "derive_more", "indexmap", @@ -2881,9 +2905,9 @@ dependencies = [ [[package]] name = "rue-types" -version = "0.6.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6dc5f584d1ff7cf562737aa990d746def396ca4211c8f56c2d28d6dc00718b" +checksum = "0766e7089d3b5e41cebb17bee53055479adee1925207e4c1a5dea36a2bf29d06" dependencies = [ "clvmr", "derive_more", diff --git a/Cargo.toml b/Cargo.toml index 7ad6a9b..53ada75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = [".", "napi"] [package] edition = "2021" name = "datalayer-driver" -version = "4.0.0" +version = "5.0.0" license = "MIT" authors = ["yakuhito ", "William Wills "] homepage = "https://github.com/DIG-Network/DataLayer-Driver" @@ -26,7 +26,7 @@ chia-puzzle-types = "0.36.1" thiserror = "1.0.61" clvmr = "0.16.2" tokio = "1.39.3" -chia-wallet-sdk = { version = "0.34.0", features = ["chip-0035", "native-tls", "peer-simulator", "action-layer"] } +chia-wallet-sdk = { version = "0.36.0", features = ["chip-0035", "native-tls", "peer-simulator", "action-layer"] } hex-literal = "0.4.1" num-bigint = "0.4.6" hex = "0.4.3" diff --git a/napi/Cargo.toml b/napi/Cargo.toml index 58c18bc..60c11e4 100644 --- a/napi/Cargo.toml +++ b/napi/Cargo.toml @@ -26,7 +26,7 @@ chia-puzzle-types = "0.36.1" chia-traits = "0.36.1" thiserror = "1.0.61" tokio = "1.39.3" -chia-wallet-sdk = { version = "0.34.0", features = ["chip-0035", "native-tls", "peer-simulator", "action-layer"] } +chia-wallet-sdk = { version = "0.36.0", features = ["chip-0035", "native-tls", "peer-simulator", "action-layer"] } hex = "0.4.3" rand = "0.8" futures-util = "0.3" diff --git a/napi/package-lock.json b/napi/package-lock.json index b64b8b7..8930b4d 100644 --- a/napi/package-lock.json +++ b/napi/package-lock.json @@ -1,12 +1,12 @@ { "name": "@dignetwork/datalayer-driver", - "version": "0.1.38", + "version": "3.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@dignetwork/datalayer-driver", - "version": "0.1.38", + "version": "3.0.1", "license": "MIT", "devDependencies": { "@napi-rs/cli": "^2.18.4", diff --git a/napi/package.json b/napi/package.json index 9c57f75..a42e7a8 100644 --- a/napi/package.json +++ b/napi/package.json @@ -1,6 +1,6 @@ { "name": "@dignetwork/datalayer-driver", - "version": "3.0.0", + "version": "3.0.1", "main": "index.js", "types": "index.d.ts", "repository": { diff --git a/napi/src/lib.rs b/napi/src/lib.rs index dd1febf..4992f12 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -16,7 +16,7 @@ pub use datalayer_driver::{ master_secret_key_to_wallet_synthetic_secret_key, master_to_wallet_unhardened, oracle_delegated_puzzle, secret_key_to_public_key, synthetic_key_to_puzzle_hash, types, wallet, writer_delegated_puzzle_from_key, xch_server_coin, BlsPair, Bytes, Bytes32, Coin, CoinSpend, - CoinState, DataStoreInfo, EveProof, LineageProof, Program, Proof, PublicKey, SecretKey, + CoinState, DatastoreInfo, EveProof, LineageProof, Program, Proof, PublicKey, SecretKey, Signature, SimulatorPuzzle, SpendBundle, XchServerCoin, }; diff --git a/napi/src/napi_lib.rs b/napi/src/napi_lib.rs index 2976463..28293d2 100644 --- a/napi/src/napi_lib.rs +++ b/napi/src/napi_lib.rs @@ -7,12 +7,28 @@ use crate::js::{ // Import from the main datalayer-driver crate use datalayer_driver::{ - master_to_wallet_unhardened, types, wallet, xch_server_coin, Bytes as RustBytes, - Bytes32 as RustBytes32, Coin as RustCoin, CoinSpend as RustCoinSpend, - DataStore as RustDataStore, DataStoreInfo as RustDataStoreInfo, - DataStoreMetadata as RustDataStoreMetadata, DelegatedPuzzle as RustDelegatedPuzzle, - Peer as RustPeer, Proof as RustProof, PublicKey as RustPublicKey, SecretKey as RustSecretKey, - Signature as RustSignature, SpendBundle as RustSpendBundle, + master_to_wallet_unhardened, + types, + wallet, + xch_server_coin, + Bytes as RustBytes, + Bytes32 as RustBytes32, + Coin as RustCoin, + CoinSpend as RustCoinSpend, + // The chia-wallet-sdk 0.36 rename (`DataStore` -> `Datastore`) is absorbed HERE, at the + // aliases. The JS-facing `DataStore`/`DataStoreMetadata` structs below deliberately keep + // their original names: they are the published npm/TypeScript surface, and renaming them + // would break every JS consumer for an upstream capitalisation change they cannot observe. + Datastore as RustDataStore, + DatastoreInfo as RustDataStoreInfo, + DatastoreMetadata as RustDataStoreMetadata, + DelegatedPuzzle as RustDelegatedPuzzle, + Peer as RustPeer, + Proof as RustProof, + PublicKey as RustPublicKey, + SecretKey as RustSecretKey, + Signature as RustSignature, + SpendBundle as RustSpendBundle, }; use chia_protocol::{CoinStateUpdate, NewPeakWallet, ProtocolMessageTypes}; diff --git a/src/lib.rs b/src/lib.rs index bbc3cae..0f65eb3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,13 +14,22 @@ //! - Server coin management //! - Fee management utilities +// `WalletError` is this crate's single error type, so nearly every fallible function returns it by +// value. chia-wallet-sdk 0.36 grew `ClientError` to ~136 bytes, which pushes `WalletError` past +// clippy's 128-byte `result_large_err` threshold — an upstream size change, not a defect in these +// signatures. Boxing the variant would shrink it, but that reshapes the crate's PUBLIC error enum +// and every construction and match site with it, which is a deliberate refactor rather than part of +// a dependency move. Tracked as a follow-up; suppressed here so the size of an upstream struct does +// not silently become a reason to stop building. +#![allow(clippy::result_large_err)] + // Re-export core types from dependencies pub use chia_bls::{master_to_wallet_unhardened, PublicKey, SecretKey, Signature}; pub use chia_protocol::{Bytes, Bytes32, Coin, CoinSpend, CoinState, Program, SpendBundle}; pub use chia_puzzle_types::{EveProof, LineageProof, Proof}; pub use chia_wallet_sdk::client::Peer; pub use chia_wallet_sdk::driver::{ - DataStore, DataStoreInfo, DataStoreMetadata, DelegatedPuzzle, P2ParentCoin, + Datastore, DatastoreInfo, DatastoreMetadata, DelegatedPuzzle, P2ParentCoin, }; pub use chia_wallet_sdk::utils::Address; @@ -264,7 +273,7 @@ pub fn mint_store( pub fn oracle_spend( spender_synthetic_key: PublicKey, selected_coins: Vec, - store: DataStore, + store: Datastore, fee: u64, ) -> Result { Ok(wallet::oracle_spend( @@ -278,7 +287,7 @@ pub fn oracle_spend( /// Updates the metadata of a store (Rust API version). #[allow(clippy::too_many_arguments)] pub fn update_store_metadata( - store: DataStore, + store: Datastore, new_root_hash: Bytes32, new_label: Option, new_description: Option, @@ -299,7 +308,7 @@ pub fn update_store_metadata( /// Updates the ownership of a store (Rust API version). pub fn update_store_ownership( - store: DataStore, + store: Datastore, new_owner_puzzle_hash: Bytes32, new_delegated_puzzles: Vec, inner_spend_info: wallet::DataStoreInnerSpend, @@ -313,7 +322,7 @@ pub fn update_store_ownership( } /// Melts a store (Rust API version). -pub fn melt_store(store: DataStore, owner_pk: PublicKey) -> Result> { +pub fn melt_store(store: Datastore, owner_pk: PublicKey) -> Result> { Ok(wallet::melt_store(store, owner_pk)?) } @@ -542,7 +551,7 @@ pub mod async_api { /// Synchronizes a datastore (Rust API version). pub async fn sync_store( peer: &Peer, - store: &DataStore, + store: &Datastore, last_height: Option, last_header_hash: Bytes32, with_history: bool, diff --git a/src/types.rs b/src/types.rs index fd7d3b5..233c6b7 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,5 +1,5 @@ pub use crate::xch_server_coin::XchServerCoin; -use crate::DataStore; +use crate::Datastore; use chia_bls::{PublicKey, SecretKey}; pub use chia_protocol::*; pub use chia_puzzle_types::{EveProof, LineageProof, Proof}; @@ -18,7 +18,7 @@ pub struct BlsPair { #[derive(Clone, Debug)] pub struct SuccessResponse { pub coin_spends: Vec, - pub new_datastore: DataStore, + pub new_datastore: Datastore, } pub struct UnspentCoinsResponse { diff --git a/src/wallet.rs b/src/wallet.rs index bc046c4..8c8ce17 100644 --- a/src/wallet.rs +++ b/src/wallet.rs @@ -28,14 +28,14 @@ use chia_puzzle_types::{ use chia_puzzles::SINGLETON_LAUNCHER_HASH; use chia_wallet_sdk::client::Peer; use chia_wallet_sdk::driver::{ - get_merkle_tree, DataStore, DataStoreMetadata, DelegatedPuzzle, Did, DidInfo, DriverError, + get_merkle_tree, Datastore, DatastoreMetadata, DelegatedPuzzle, Did, DidInfo, DriverError, HashedPtr, IntermediateLauncher, Launcher, Layer, NftMint, OracleLayer, SpendContext, SpendWithConditions, StandardLayer, WriterLayer, }; use chia_wallet_sdk::signer::{AggSigConstants, RequiredSignature, SignerError}; use chia_wallet_sdk::types::{ announcement_id, - conditions::{CreateCoin, MeltSingleton, Memos, UpdateDataStoreMerkleRoot}, + conditions::{CreateCoin, MeltSingleton, Memos, UpdateDatastoreMerkleRoot}, Condition, Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS, }; use chia_wallet_sdk::utils::{self, CoinSelectionError}; @@ -420,7 +420,7 @@ pub fn mint_store( let (launch_singleton, datastore) = Launcher::new(lead_coin_name, 1).mint_datastore( &mut ctx, - DataStoreMetadata { + DatastoreMetadata { root_hash, label, description, @@ -474,14 +474,14 @@ pub fn mint_store( } pub struct SyncStoreResponse { - pub latest_store: DataStore, + pub latest_store: Datastore, pub latest_height: u32, pub root_hash_history: Option>, } pub async fn sync_store( peer: &Peer, - store: &DataStore, + store: &Datastore, last_height: Option, last_header_hash: Bytes32, with_history: bool, @@ -523,7 +523,7 @@ pub async fn sync_store( solution: puzzle_and_solution_req.solution, }; - let new_store = DataStore::::from_spend( + let new_store = Datastore::::from_spend( &mut ctx, &cs, &latest_store.info.delegated_puzzles, @@ -614,7 +614,7 @@ pub async fn sync_store_using_launcher_id( solution: puzzle_and_solution_req.solution, }; - let first_store = DataStore::::from_spend(&mut ctx, &cs, &[])? + let first_store = Datastore::::from_spend(&mut ctx, &cs, &[])? .ok_or(WalletError::Parse("Store from spend is None".to_string()))?; let res = sync_store( @@ -691,7 +691,7 @@ pub enum DataStoreInnerSpend { fn update_store_with_conditions( ctx: &mut SpendContext, conditions: Conditions, - datastore: DataStore, + datastore: Datastore, inner_spend_info: DataStoreInnerSpend, allow_admin: bool, allow_writer: bool, @@ -720,7 +720,7 @@ fn update_store_with_conditions( let new_spend = datastore.spend(ctx, inner_datastore_spend)?; let new_datastore = - DataStore::::from_spend(ctx, &new_spend, &parent_delegated_puzzles)? + Datastore::::from_spend(ctx, &new_spend, &parent_delegated_puzzles)? .ok_or(WalletError::Parse("Store from spend is None".to_string()))?; Ok(SuccessResponse { @@ -730,7 +730,7 @@ fn update_store_with_conditions( } pub fn update_store_ownership( - datastore: DataStore, + datastore: Datastore, new_owner_puzzle_hash: Bytes32, new_delegated_puzzles: Vec, inner_spend_info: DataStoreInnerSpend, @@ -739,7 +739,7 @@ pub fn update_store_ownership( let update_condition: Condition = match inner_spend_info { DataStoreInnerSpend::Owner(_) => { - DataStore::::owner_create_coin_condition( + Datastore::::owner_create_coin_condition( ctx, datastore.info.launcher_id, new_owner_puzzle_hash, @@ -750,9 +750,9 @@ pub fn update_store_ownership( DataStoreInnerSpend::Admin(_) => { let merkle_tree = get_merkle_tree(ctx, new_delegated_puzzles.clone())?; - let new_merkle_root_condition = UpdateDataStoreMerkleRoot { + let new_merkle_root_condition = UpdateDatastoreMerkleRoot { new_merkle_root: merkle_tree.root(), - memos: DataStore::::get_recreation_memos( + memos: Datastore::::get_recreation_memos( datastore.info.launcher_id, new_owner_puzzle_hash.into(), new_delegated_puzzles, @@ -779,7 +779,7 @@ pub fn update_store_ownership( } pub fn update_store_metadata( - datastore: DataStore, + datastore: Datastore, new_root_hash: Bytes32, new_label: Option, new_description: Option, @@ -789,7 +789,7 @@ pub fn update_store_metadata( ) -> Result { let ctx = &mut SpendContext::new(); - let new_metadata = DataStoreMetadata { + let new_metadata = DatastoreMetadata { root_hash: new_root_hash, label: new_label, description: new_description, @@ -797,12 +797,12 @@ pub fn update_store_metadata( size_proof: new_size_proof, }; let mut new_metadata_condition = Conditions::new().with( - DataStore::::new_metadata_condition(ctx, new_metadata)?, + Datastore::::new_metadata_condition(ctx, new_metadata)?, ); if let DataStoreInnerSpend::Owner(_) = inner_spend_info { new_metadata_condition = new_metadata_condition.with( - DataStore::::owner_create_coin_condition( + Datastore::::owner_create_coin_condition( ctx, datastore.info.launcher_id, datastore.info.owner_puzzle_hash, @@ -823,7 +823,7 @@ pub fn update_store_metadata( } pub fn melt_store( - datastore: DataStore, + datastore: Datastore, owner_pk: PublicKey, ) -> Result, WalletError> { let ctx = &mut SpendContext::new(); @@ -847,7 +847,7 @@ pub fn melt_store( pub fn oracle_spend( spender_synthetic_key: PublicKey, selected_coins: Vec, - datastore: DataStore, + datastore: Datastore, fee: u64, ) -> Result { let Some(DelegatedPuzzle::Oracle(oracle_ph, oracle_fee)) = datastore @@ -906,7 +906,7 @@ pub fn oracle_spend( let parent_delegated_puzzles = datastore.info.delegated_puzzles.clone(); let new_spend = datastore.spend(ctx, inner_datastore_spend)?; - let new_datastore = DataStore::from_spend(ctx, &new_spend, &parent_delegated_puzzles)? + let new_datastore = Datastore::from_spend(ctx, &new_spend, &parent_delegated_puzzles)? .ok_or(WalletError::Parse("Store from spend is None".to_string()))?; ctx.insert(new_spend.clone()); @@ -1684,14 +1684,19 @@ pub async fn resolve_did_string_and_generate_proof( #[cfg(test)] mod melt_kat { - //! Custody KAT pinning `DataStore::from_spend`'s melt signal under the - //! chia-wallet-sdk 0.34 family (dig_ecosystem#2133). + //! Custody KAT pinning `Datastore::from_spend`'s melt signal across the + //! chia-wallet-sdk 0.34 -> 0.36 move (dig_ecosystem#2133, #3161). //! //! The just-merged digstore-chain #1981 melt classifier depends on the load- //! bearing fact that a childless datastore singleton spend (an owner melt) //! surfaces as `Err(DriverError::MissingChild)`, while a spend that recreates //! the datastore surfaces as `Ok(Some(_))`. This test drives a real - //! peer-simulator mint -> melt and asserts both signals hold under 0.34. + //! peer-simulator mint -> melt and asserts both signals hold under 0.36. + //! + //! Its expected values are UNCHANGED by the 0.36 adoption: only the type's + //! spelling moved (`DataStore` -> `Datastore`). Had either signal changed, + //! this test would have gone red rather than needing an edit — which is the + //! evidence that the melt classifier downstream is still safe. use super::*; use chia_wallet_sdk::test::{BlsPair, Simulator}; @@ -1733,7 +1738,7 @@ mod melt_kat { .iter() .find(|cs| cs.coin.puzzle_hash == SINGLETON_LAUNCHER_HASH.into()) .expect("mint must contain the singleton launcher spend"); - let launched = DataStore::::from_spend(&mut ctx, launcher_spend, &[])?; + let launched = Datastore::::from_spend(&mut ctx, launcher_spend, &[])?; assert!( launched.is_some(), "from_spend must recognise the datastore-creating launcher spend as Ok(Some)" @@ -1748,10 +1753,10 @@ mod melt_kat { // The pinned property: a valid datastore singleton spend that recreates no // odd-amount child (the owner melt) is reported as `Err(MissingChild)`. let mut ctx = SpendContext::new(); - let result = DataStore::::from_spend(&mut ctx, &melt_spends[0], &[]); + let result = Datastore::::from_spend(&mut ctx, &melt_spends[0], &[]); assert!( matches!(result, Err(DriverError::MissingChild)), - "0.34 must still surface an owner melt as Err(DriverError::MissingChild), got {result:?}" + "0.36 must still surface an owner melt as Err(DriverError::MissingChild), got {result:?}" ); Ok(()) diff --git a/tests/manifest_chia_coherence.rs b/tests/manifest_chia_coherence.rs new file mode 100644 index 0000000..f0fdcbb --- /dev/null +++ b/tests/manifest_chia_coherence.rs @@ -0,0 +1,295 @@ +//! The regression guard for dig_ecosystem#3161: this workspace MUST NEVER again declare two +//! different minor lines of the same `chia-*` family. +//! +//! ## The defect this exists to catch +//! +//! Published `datalayer-driver` 4.0.0 shipped INTERNALLY SPLIT: every chia primitive +//! (`chia-protocol`, `chia-bls`, `chia-consensus`, `chia-traits`, `chia-puzzle-types`, +//! `clvm-traits`, `clvm-utils`) was declared at `0.36.1` beside `chia-wallet-sdk` at `0.34.0`. +//! Two lines of one family in one crate compile only while every consumer happens to be stale in +//! the matching way; the moment one is not, the crate hands out two incompatible copies of the +//! same types. Because the split lived inside the PUBLISHED manifest, no consumer could escape it +//! by bumping — which is how it came to block `digs`/`digstore-chain` and `dig-wallet-backend` +//! simultaneously. +//! +//! Nothing mechanically prevented it, and no *behavioural* test can: both halves run correctly in +//! isolation, so the split is invisible to every test of what the code DOES. The defect was +//! **manifest coherence**, and manifest coherence is mechanically assertable. That is what these +//! tests assert. +//! +//! ## Why BOTH manifests, and not just the root one +//! +//! This workspace declares the same chia set twice — once in `Cargo.toml` for the library and again +//! in `napi/Cargo.toml`, whose bindings need direct access to the chia types for conversions. A +//! guard reading only the root manifest would be blind to half the surface: `napi/` could sit on +//! `0.34` while the root sat on `0.36` and the library would still build, because the two crates +//! are compiled separately and only meet at the NAPI boundary. That boundary is precisely where two +//! copies of one type produce a silent mismatch, so the two manifests are pooled into ONE coherence +//! judgement rather than checked independently. +//! +//! ## Why the manifest, and not `Cargo.lock` +//! +//! The defect is about the versions this workspace DECLARES. The resolved lock legitimately +//! contains older chia lines we neither choose nor control — `clvmr 0.16.4` vendors `chia-sha2 +//! 0.34.0`, `chia-bls 0.28.2` and `chia-traits 0.28.2` internally, and `chialisp 0.4.6` (via +//! `chia-sdk-types` and `rue-lir`) pulls `chia-bls 0.42.1`. A lock-based assertion would have to +//! carve those out by name and would go red every time an upstream evaluator re-vendored something, +//! which is noise rather than signal. `cargo tree -d` cannot be the gate here for the same reason: +//! `chia-wallet-sdk` fails it on its own vendored graph. The manifest is the surface this workspace +//! owns, so it is the surface the guard pins. +//! +//! ## Why per-FAMILY, and not "all chia crates are equal" +//! +//! The ecosystem ceiling is deliberately NOT uniform, so a test asserting one global version would +//! be red on correct code: the primitives publish `0.36.1` while `chia-wallet-sdk` tops out at +//! `0.36.0`, and `chia-puzzles` (0.20.x) and `clvmr` (0.16.x) have never shared a version line with +//! either. What must agree is the `MAJOR.MINOR` **line** within a family — exactly the granularity +//! the 0.34-vs-0.36 defect violated, and exactly the granularity the legitimate 0.36.0-vs-0.36.1 +//! patch spread does not. +//! +//! ## If you revert-proof these tests, restore `Cargo.lock` as well +//! +//! Proving this guard fires means reintroducing a split into a manifest and watching it fail. +//! Running the suite in that state **silently re-resolves `Cargo.lock`**. Restoring only the +//! manifest therefore leaves the lock carrying BOTH the experiment's old line and the correct one: +//! a two-line split, created by the proof, in the very workspace whose job is to have none. +//! +//! Restore both files by copy (never `git checkout `, which is destructive on uncommitted +//! work), and make the restore run pass `--locked`. That flag is what turns the leftover into a +//! loud refusal instead of a silent green — without it cargo re-resolves again and the pollution +//! ships. + +use std::collections::{BTreeMap, BTreeSet}; +use std::fs; + +/// The manifests this workspace owns, and which therefore must agree with each other. +const MANIFESTS: &[&str] = &["Cargo.toml", "napi/Cargo.toml"]; + +/// A dependency declaration: which manifest it came from, the crate name, and its version literal. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +struct Declared { + manifest: String, + name: String, + version: String, +} + +impl Declared { + /// The `MAJOR.MINOR` line this requirement sits on — the granularity a family must agree at. + fn line(&self) -> String { + self.version + .split('.') + .take(2) + .collect::>() + .join(".") + } +} + +/// The families that MUST each be internally coherent, with the line each is pinned to. +/// +/// `chia-wallet-sdk` is listed in the SAME family as the chia/clvm primitives precisely because the +/// shipped 4.0.0 defect split those two apart. Separating them here would classify the defect as +/// legitimate and the guard would never fire on it. `chia-puzzles` and `clvmr` version +/// independently of both and of each other, so each is its own family. +const FAMILIES: &[(&str, &str, &[&str])] = &[ + ( + "the chia 0.36 line (chia-wallet-sdk + the chia/clvm primitives)", + "0.36", + &[ + "chia-bls", + "chia-consensus", + "chia-protocol", + "chia-puzzle-types", + "chia-traits", + "chia-wallet-sdk", + "clvm-traits", + "clvm-utils", + ], + ), + ("the chia-puzzles line", "0.20", &["chia-puzzles"]), + ("the clvmr line", "0.16", &["clvmr"]), +]; + +/// Reads every `chia-*`/`clvm*` requirement declared in `[dependencies]` and `[dev-dependencies]` +/// across every manifest this workspace owns. +/// +/// Read at RUNTIME rather than `include_str!`d so that reverting a version in a manifest and +/// re-running the suite is a genuine end-to-end proof of the guard, with no recompilation subtlety +/// standing between the edit and the verdict. +fn declared_chia_deps() -> Vec { + let root = env!("CARGO_MANIFEST_DIR"); + let mut found = Vec::new(); + + for relative in MANIFESTS { + let path = format!("{root}/{relative}"); + let manifest = fs::read_to_string(&path) + .unwrap_or_else(|e| panic!("the workspace manifest `{relative}` is readable: {e}")); + + let mut section = String::new(); + + for raw in manifest.lines() { + let line = raw.trim(); + // Comments carry prose mentioning chia crates (napi/Cargo.toml explains why it needs + // direct access to "chia types"), so they must never be parsed as declarations. + if line.starts_with('#') || line.is_empty() { + continue; + } + if line.starts_with('[') { + section = line.to_string(); + continue; + } + // Deliberately NOT `[target.*.dependencies]`: those carry platform shims such as + // vendored openssl, never chia crates, and are not part of the coherence surface. + if section != "[dependencies]" && section != "[dev-dependencies]" { + continue; + } + let Some((name, rest)) = line.split_once('=') else { + continue; + }; + let name = name.trim(); + if !(name.starts_with("chia") || name.starts_with("clvm")) { + continue; + } + let version = extract_version(rest.trim()).unwrap_or_else(|| { + panic!( + "dependency `{name}` in `{relative}` declares no literal version this guard \ + can read: {line}" + ) + }); + found.push(Declared { + manifest: (*relative).to_string(), + name: name.to_string(), + version, + }); + } + } + + assert!( + !found.is_empty(), + "the guard parsed ZERO chia dependencies, which means its parser stopped matching the \ + manifests rather than that the workspace stopped declaring chia crates. A guard that \ + silently reads nothing passes every other assertion vacuously.", + ); + + found +} + +/// Pulls the version literal out of either `"0.36.1"` or `{ version = "0.36.0", features = [..] }`. +fn extract_version(rest: &str) -> Option { + let quoted = if rest.starts_with('{') { + let at = rest.find("version")?; + &rest[at..] + } else { + rest + }; + let mut parts = quoted.split('"'); + parts.next()?; + parts.next().map(str::to_string) +} + +#[test] +fn every_chia_family_declares_a_single_minor_line() { + let declared = declared_chia_deps(); + + for (family, expected_line, members) in FAMILIES { + for member in *members { + for dep in declared.iter().filter(|d| d.name == *member) { + assert_eq!( + dep.line(), + *expected_line, + "#3161 REGRESSION: `{}` is declared at {} in `{}` but {family} is pinned to \ + {expected_line}.x. Two minor lines of one chia family in one workspace is the \ + internal split that shipped as 4.0.0 and blocked every consumer. Move the \ + whole family together, or re-state the family's line here.", + dep.name, + dep.version, + dep.manifest, + ); + } + } + } +} + +#[test] +fn the_two_manifests_agree_on_every_shared_chia_dependency() { + // Stricter than the family check above, and catching a different failure: `Cargo.toml` at + // 0.36.1 beside `napi/Cargo.toml` at 0.36.0 sits on ONE minor line, so the family test passes, + // yet the library and its NAPI bindings would compile against different patch releases of the + // same types. They meet at the NAPI boundary, so they must be declared identically. + let mut by_name: BTreeMap> = BTreeMap::new(); + for dep in declared_chia_deps() { + by_name + .entry(dep.name) + .or_default() + .insert((dep.manifest, dep.version)); + } + + for (name, sites) in by_name { + if sites.len() < 2 { + continue; // declared in only one manifest — nothing to disagree with. + } + let versions: BTreeSet<&str> = sites.iter().map(|(_, v)| v.as_str()).collect(); + assert_eq!( + versions.len(), + 1, + "`{name}` is declared at differing versions across this workspace's manifests: {sites:?}. \ + The library and the NAPI bindings exchange these types across the binding boundary, so \ + a disagreement here is two copies of one type meeting at runtime.", + ); + } +} + +#[test] +fn every_declared_chia_dep_belongs_to_a_classified_family() { + let classified: BTreeSet<&str> = FAMILIES + .iter() + .flat_map(|(_, _, members)| members.iter().copied()) + .collect(); + + for dep in declared_chia_deps() { + assert!( + classified.contains(dep.name.as_str()), + "`{}` (declared in `{}`) is a chia/clvm dependency this coherence guard does not \ + classify. A new chia dependency can silently arrive on a foreign version line, which \ + is exactly how the 4.0.0 split went unnoticed. Add it to the family it belongs to in \ + FAMILIES.", + dep.name, + dep.manifest, + ); + } +} + +#[test] +fn the_declared_chia_dependency_set_is_exactly_the_expected_one() { + // Pinned by exact membership per manifest, not by count: a guard that only counts cannot tell a + // dropped dependency from a substituted one, and both are ways for a family to lose a member + // without the coherence test above ever seeing it (it only checks names it can find). + let expected: BTreeSet<(&str, &str)> = BTreeSet::from([ + ("Cargo.toml", "chia-bls"), + ("Cargo.toml", "chia-consensus"), + ("Cargo.toml", "chia-protocol"), + ("Cargo.toml", "chia-puzzle-types"), + ("Cargo.toml", "chia-puzzles"), + ("Cargo.toml", "chia-traits"), + ("Cargo.toml", "chia-wallet-sdk"), + ("Cargo.toml", "clvm-traits"), + ("Cargo.toml", "clvm-utils"), + ("Cargo.toml", "clvmr"), + ("napi/Cargo.toml", "chia-bls"), + ("napi/Cargo.toml", "chia-protocol"), + ("napi/Cargo.toml", "chia-puzzle-types"), + ("napi/Cargo.toml", "chia-traits"), + ("napi/Cargo.toml", "chia-wallet-sdk"), + ]); + + let owned: Vec = declared_chia_deps(); + let actual: BTreeSet<(&str, &str)> = owned + .iter() + .map(|d| (d.manifest.as_str(), d.name.as_str())) + .collect(); + + assert_eq!( + actual, expected, + "the workspace's chia/clvm dependency set changed. Confirm the new set is on ONE line per \ + family in BOTH manifests, then update this expectation in the same commit.", + ); +}