diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index db0669f1..a1864dd6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,12 +5,12 @@ on: branches: - master tags: - - 'v\d+\.*' + - 'v[0-9]+.*' pull_request: branches: - master - develop - - 'v\d+(\.\d+)*' + - 'v[0-9]+.?*' env: CARGO_TERM_COLOR: always @@ -33,7 +33,7 @@ jobs: strategy: fail-fast: false matrix: - feature: [ stl, serde ] + feature: [ bitcoin, liquid, prime, serde ] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable @@ -57,7 +57,7 @@ jobs: strategy: fail-fast: false matrix: - toolchain: [ nightly, beta, stable, 1.77.0 ] + toolchain: [ nightly, beta, stable, 1.81.0 ] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 8624aba9..9ba863f5 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -5,12 +5,12 @@ on: branches: - master tags: - - 'v\d+\.*' + - 'v[0-9]+.*' pull_request: branches: - master - develop - - 'v\d+(\.\d+)*' + - 'v[0-9]+.?*' env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 29e0ebc0..91f36b69 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5,7 +5,7 @@ on: branches: - master - develop - - 'v\d+(\.\d+)*' + - 'v[0-9]+.?*' env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b6bd2c74..7b009567 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,12 +5,12 @@ on: branches: - master tags: - - 'v\d+\.*' + - 'v[0-9]+.*' pull_request: branches: - master - develop - - 'v\d+(\.\d+)*' + - 'v[0-9]+.?*' env: CARGO_TERM_COLOR: always diff --git a/.rustfmt.toml b/.rustfmt.toml index 6d14899a..7adebfc3 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,12 +1,14 @@ edition = "2021" style_edition = "2021" -max_width = 100 -array_width = 100 -attr_fn_like_width = 100 +max_width = 120 +array_width = 120 +attr_fn_like_width = 120 comment_width = 100 -fn_call_width = 100 -single_line_if_else_max_width = 100 +chain_width = 60 +fn_call_width = 120 +single_line_if_else_max_width = 120 +struct_lit_width = 60 fn_single_line = true format_code_in_doc_comments = true diff --git a/CHANGELOG.md b/CHANGELOG.md index 472f6e90..164522d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,57 @@ Change Log ========== +v0.13.0 +------- + +TODO: + +- no_std +- no external dependencies +- fallback seals? +- inter-contract ops? +- more introspection op-codes? +- idempotent contract validation? + +v0.12.0 +------- + +- Unify state types +- Distinguish verifiable and non-verifiable state +- Make RGB STARKy +- Remove bitcoin dependencies +- Remove schema verification +- Fully abstract single-use seal protocol: + - Remove layer1 information + - Remove anchors + - Remove secret seals, make types generic over seals + - Remove transition bundles + - Delegate consensus ordering to single-use seal protocols +- Remove valencies and redeems, extension graphs +- Require state transitions to have at least 1 input +- Make schema part of genesis data + +TODO: + +- Test coverage +- Benchmarking +- Documentation + v0.7.0 ------ + - Taproot-based OP_RETURN commitments -- New LNPBP-4 multi-protocol commitments based on merkle trees (support for +- New LNPBP-4 multi-protocol commitments based on merkle trees (support for using RGB alongside other client-side-validation protocols) - State transition bundling for multi-participant transactions (required for LN, pay/coinjoin) - Data containers (binary data for NFTs etc) -- Support for arbitrary rich data in contract state with a new schema for +- Support for arbitrary rich data in contract state with a new schema for representing hierarchies of such data structures. v0.5.0 ------ + - Separation of specific schemata into independent libraries - Introduction of AluVM virtual machine - Bulletproofs data removed from client-side commitments @@ -21,14 +59,15 @@ v0.5.0 v0.4.x patches -------------- + - 0.4.3: Fixing seal_definition old-way of sorting seals before they were - held in Vec (and BTreeSet was used instead). This allows to validate - multi-output transition history + held in Vec (and BTreeSet was used instead). This allows to validate + multi-output transition history - 0.4.4: Fixing broken upstream dependency breaking change in `zeroize` crate - v0.4.0 ------ + - Disclosures - Improved concealment procedures; fixed node id mutability issue - Reveal-merge procedure @@ -41,12 +80,14 @@ v0.4.0 v0.3.1 ------ + - Lightning encoding for RGB types used in lightning messages - Added missed StrictEncoding derives - Consignment ids & bech32 representation v0.3.0 ------ + - RGB Core Library is extracted and externalized from LNP/BP Core Library - Serde encoding fixes (proper use of `serde_as` for wrapped types) - BIP32 & descriptor enhancements @@ -55,10 +96,12 @@ v0.3.0 v0.2.2 ------ + - Fixed PSBT key serialization issue during commitment procedure v0.2.1 ------ + - Fixing serde to use Bech32 encoding for ContractId and SchemaId types v0.2.0 @@ -66,6 +109,7 @@ v0.2.0 No changes since RC2 ### Changes since v0.1 + - Epic: refactoring of LNP protocols and services crate - Epic: initial implementation of generalized lightning network - Epic: lightning network specific encodings and derives @@ -73,28 +117,33 @@ No changes since RC2 v0.2.0-rc.2 ----------- + - New tagged hash implementation defaulting to Bech32 encoding for ContractId - Using amplify and amplify_derive v2.4 v0.2.0-rc.1 ----------- + - Fix for the broken tokio upstream dependency breaking issue - Fix for zero-balance overflow in case of empty arguments - Eq implementation for Schema object v0.2.0-beta.3 ------------- + - Multiple BIP-32 improvements on top of rust-bitcoin functionality - Better CI - Android/iOS/Windows/MacOs build fixes - AnchorId strict encoding -- Fixed issue with broken `serde_with` macro (pinned older version in Cargo.toml) +- Fixed issue with broken `serde_with` macro (pinned older version in + Cargo.toml) - More collection types supporting `AutoConceal` v0.2.0-beta.2 ------------- ### LNP module + - Noise handshake - Abstract state channels - Payment channels @@ -103,23 +152,27 @@ v0.2.0-beta.2 - Additional LN peer messages supporting RGB ### BP module + - Lexicographic orderings (BIP96) for transactions, PSBTs, inputs and outputs v0.2.0-beta.1 ------------- ### LNP/BP Core Library + - LN messaging & LNPWP: Lightning network peer wire protocol (BOLT-1pt2, BOLT-2) - BOLT-8 noise encryptor and handshake implementation - Improvements to LN-specific data types - LNP socket and node addressing large-scale refactoring -- More serde and strict encoding implementations for data types across the +- More serde and strict encoding implementations for data types across the library ### LNP/BP Derivation Library + - Implementation of strict derive macros for enums ### LNP/BP Services Library + - Debugging and display logging improvements with LNP/BP Services library - ESB functionality improvements in LNP/BP Services libraru @@ -127,7 +180,7 @@ v0.2.0-alpha.3 -------------- - Improvements to the ESB and RPC service architectures -- Improvements to debug logging and displaying of LN messages and service +- Improvements to debug logging and displaying of LN messages and service information v0.2.0-alpha.2 @@ -141,11 +194,11 @@ v0.2.0-alpha.2 v0.2.0-alpha.1 -------------- -This is alpha release with some major refactoring in LNP mod adding support for +This is alpha release with some major refactoring in LNP mod adding support for LN and Internet2 protocols. - Refactoring of LNP protocol stack; introduction of Internet2 architacture -- Services crate implementing common client/server and other node architecture +- Services crate implementing common client/server and other node architecture patterns - Basic implementation of core Lightning network data structures @@ -153,75 +206,80 @@ v0.1.0 ------ ### Library overview + - **Paradigms**: generic APIs for L1/L3 best practices - * **Client-side validation** - * **Single-use-seals** - * **Strict encoding** + * **Client-side validation** + * **Single-use-seals** + * **Strict encoding** - **Bitcoin protocol**: extensions to `bitcoin` crate and L2/L3 APIs - * **Deterministic bitcoin commitments** (DBC) based on LNPBP1-4 standard - * **Tagged hashes**: additional procedures for working with Tapproot-style - tagged hashes - * **Short bitcoin identifiers** based on LNPBP-4 standard - * **Resolver API** for requesting transaction graph using providers (like - Bitcoin Core RPC, Electrum Server API etc) - * **Chains**, chain parameters and universal asset identifiers - * **Script types** for differentiating script cycle through different - transaction parts - * **Transaction-output-based single-use-seals**: bitcoin-specific - implementation of single-use-seals + * **Deterministic bitcoin commitments** (DBC) based on LNPBP1-4 standard + * **Tagged hashes**: additional procedures for working with Tapproot-style + tagged hashes + * **Short bitcoin identifiers** based on LNPBP-4 standard + * **Resolver API** for requesting transaction graph using providers (like + Bitcoin Core RPC, Electrum Server API etc) + * **Chains**, chain parameters and universal asset identifiers + * **Script types** for differentiating script cycle through different + transaction parts + * **Transaction-output-based single-use-seals**: bitcoin-specific + implementation of single-use-seals - **RGB**: confidential smart-contract system for Bitcoin & Lightning Network based on client-side validation paradigm (LNPBP11-13 standards) - * **Schema**: structure defining contract creation and evolution rules and - restrictions - * **Contracts**: data types for contract lifecycle - * **Scripting** with embedded procedures for fungible assets - *The library implements RGB Core v1 release candidate set of standards* + * **Schema**: structure defining contract creation and evolution rules and + restrictions + * **Contracts**: data types for contract lifecycle + * **Scripting** with embedded procedures for fungible assets + *The library implements RGB Core v1 release candidate set of standards* - **Lightning networking protocol**: generalized P2P and RPC networking APIs based on the original Lightning standard; early preview - * Universal P2P node ids supporting IPv4, IPv6, Onion v2 and v3 addresses and - public keys - * Feature vectors for defining and workinf with set of feature bits - * LNP networking with ZMQ sockets for RPC interfaces + * Universal P2P node ids supporting IPv4, IPv6, Onion v2 and v3 addresses + and + public keys + * Feature vectors for defining and workinf with set of feature bits + * LNP networking with ZMQ sockets for RPC interfaces ### Major changes since RC2 + - Support for Rust stable and MSRV reduction to 1.41.1 - Custom forks for upstream bitcoin-related dependencies are changed onto the latest publicly-released versions ### Breaking changes since RC2 + - Updated taproot-based hashed tag system (BIP-340) according to the most recent specs. - RGB `Amount` renamed into `AtomicValue` - RGB `amount` mod renamed into `value` -- RGB seal definitions and related structures are now `Copy` and returned by +- RGB seal definitions and related structures are now `Copy` and returned by value - v0.1.0-rc.2 ----------- ### Breaking changes: + - Changed embedded procedure names for RGB VM -- Removed requirement for PSBT to contain fee key in RGB anchor creation (it - needs to be a properly constructed PSBT with `witness_utxo`/`non_witness_utxo` +- Removed requirement for PSBT to contain fee key in RGB anchor creation (it + needs to be a properly constructed PSBT with `witness_utxo`/`non_witness_utxo` data) ### Other changes: + - More embedded procedures for RGB VM - Schema serde serialization (YAML, JSON etc) - Serde serialization for all RGB contract structures - Strict encoding and decoding of Curve25519 public keys and Ed25519 signatures -- Implementation of Curve25519 public keys and Ed25519 signatures as RGB state +- Implementation of Curve25519 public keys and Ed25519 signatures as RGB state and metadata - Bech types for Pedersen commitments, Bulletproofs, Curve25519 data - Tweaking factor is added into PSBT information during anchor creation - Added bitcoin protocol resolvers API - v0.1.0-rc.1 ----------- ### Breaking changes: + - RGB protocol & schema versioning with feature bits - Consignment versioning - Changed Bech32 encodings of RGB data structures; added deflation encoding @@ -233,63 +291,67 @@ v0.1.0-rc.1 - Introduced Chain and ChainParam types instead of old network versioning ### Other changes: + - Test coverage >70% - Code docs >50% - v0.1.0-beta.4 ------------- ### Breaking changes: -- Updated upstream crates (bitcoin, bitcoin_hashes, secp256k1, + +- Updated upstream crates (bitcoin, bitcoin_hashes, secp256k1, grin_secp256k1zpk, miniscript, lightning) with many PRs merged -- EmbedCommitVerify now can mutate container data (used for returning tweaking +- EmbedCommitVerify now can mutate container data (used for returning tweaking factors) -- Upgrading `rand` version to the most recent one (blocked previously by +- Upgrading `rand` version to the most recent one (blocked previously by grin_secp256k1zpk dependency) - Changied txout seals to use u32 vouts instead of u16 - Changed txout blinding factor to be u64 instead of u32 ### Other changes: + - Test coverage >50% (zero-knowledge functionality & RGB contracts structures) - Returning tweaking factors - Minimal support for Tor V2 addresses; improved internet address parsing - v0.1.0-beta.3 ------------- ### Breaking changes + - Single-use-seals blinding factor changed from 32-bit to 64-bit of entropy -- Transaction output indexes in single-use-seal definitions are now 32-bit, as +- Transaction output indexes in single-use-seal definitions are now 32-bit, as in Bitcoin Core / rust-bitcoin (previously were 16-bit) ### New features + - Initial Tor V2 address support - Test cases for BP mod strict encoding - v0.1.0-beta.2 ------------- ### Features overview + - Complete validation workflow with new Validator object - Virtual machines for RGB contracts (interface + embedded VM) -- `Consignment` now has a version field, so in the future more space-saving - variants can be created (like removing txid from anchors and using short +- `Consignment` now has a version field, so in the future more space-saving + variants can be created (like removing txid from anchors and using short universal bitcoin IDs when BP node adoption will increase) -- Anchor contains txid field; so validation can be performed with just Bitcoin - Core (no Electrum or BP node is required). This also speeded up validation +- Anchor contains txid field; so validation can be performed with just Bitcoin + Core (no Electrum or BP node is required). This also speeded up validation performance significantly. ### Breaking changes -- Change of `TransitionId` hash tag value (previously-generated transition ids + +- Change of `TransitionId` hash tag value (previously-generated transition ids will be invalid) -- Change of `GenesisId` hash tag value (previously-generated contract/assets +- Change of `GenesisId` hash tag value (previously-generated contract/assets ids will be invalid) - `TransitionId` type is replaced with `NodeId` -- `NodeId` and `ContractId` are now equal by value; `ContractId` is `NodeId` +- `NodeId` and `ContractId` are now equal by value; `ContractId` is `NodeId` wrapper -- `ancestors()` method moved from `Transition` to `Node` trait; genesis returns +- `ancestors()` method moved from `Transition` to `Node` trait; genesis returns an empty array - Consignment endpoints contain `NodeId` information diff --git a/Cargo.lock b/Cargo.lock index c201786d..a9df635e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,52 +4,35 @@ version = 3 [[package]] name = "aluvm" -version = "0.11.0-beta.9" -source = "git+https://github.com/AluVM/rust-aluvm?branch=develop#24bff9f61570ea26d14e86aa5e127937aa122440" +version = "0.12.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e5c29f34577f43613078668c1fca4390d111958956ccff32397a3723c893b0f" dependencies = [ "amplify", - "ascii-armor", "baid64", - "blake3", + "commit_verify", "getrandom", - "half", "paste", - "ripemd", "serde", - "sha2", "strict_encoding", - "strict_types", "wasm-bindgen", ] [[package]] name = "amplify" -version = "4.7.0" +version = "4.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7147b742325842988dd6c793d55f58df3ae36bccf7d9b6e07db10ab035be343d" +checksum = "448cf0c3afc71439b5f837aac5399a1ef2b223f5f38324dbfb4343deec3b80cc" dependencies = [ - "amplify_apfloat", "amplify_derive", "amplify_num", "amplify_syn", "ascii", - "rand", "serde", "stringly_conversions", "wasm-bindgen", ] -[[package]] -name = "amplify_apfloat" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "695e433882668b55b3d7fb0ba22bf9be66a91abe30d7ca1f1a774f8b90b4db4c" -dependencies = [ - "amplify_num", - "bitflags", - "wasm-bindgen", -] - [[package]] name = "amplify_derive" version = "4.0.1" @@ -98,12 +81,6 @@ dependencies = [ "libc", ] -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - [[package]] name = "arrayvec" version = "0.7.6" @@ -119,19 +96,6 @@ dependencies = [ "serde", ] -[[package]] -name = "ascii-armor" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4966ac403dc4a666d8131dfe4df684f45acc68d4c7e768db89c463aa5617910" -dependencies = [ - "amplify", - "baid64", - "base85", - "sha2", - "strict_encoding", -] - [[package]] name = "autocfg" version = "1.4.0" @@ -140,9 +104,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "baid64" -version = "0.2.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95dabc2759e01e2c382968639868a701f384a18890934f9e75d4feb4d6623794" +checksum = "6cb4a8b2f1afee4ef00a190b260ad871842b93206177b59631fecd325d48d538" dependencies = [ "amplify", "base64", @@ -167,15 +131,9 @@ dependencies = [ [[package]] name = "bitcoin-io" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" - -[[package]] -name = "bitcoin-private" -version = "0.1.0" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" [[package]] name = "bitcoin_hashes" @@ -187,25 +145,6 @@ dependencies = [ "hex-conservative", ] -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "blake3" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -217,22 +156,22 @@ dependencies = [ [[package]] name = "bp-consensus" -version = "0.11.0-beta.9" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#59e41d4dd80fcbb27583d5f32b342873dc917602" +version = "0.12.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "888c412d603ec1c4df0785d9767ff94ee28b65f5e8c800900b328223133415dc" dependencies = [ "amplify", "chrono", "commit_verify", - "secp256k1 0.30.0", - "serde", + "secp256k1", "strict_encoding", - "strict_types", ] [[package]] name = "bp-core" -version = "0.11.0-beta.9" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#59e41d4dd80fcbb27583d5f32b342873dc917602" +version = "0.12.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d5da3b6f01c30d70426892fa7cc116399beb96c3dd4c3492e4cf084456eafab" dependencies = [ "amplify", "bp-consensus", @@ -240,31 +179,30 @@ dependencies = [ "bp-seals", "commit_verify", "getrandom", - "serde", "single_use_seals", "strict_encoding", - "strict_types", "wasm-bindgen", ] [[package]] name = "bp-dbc" -version = "0.11.0-beta.9" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#59e41d4dd80fcbb27583d5f32b342873dc917602" +version = "0.12.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3206ef558ad665cdc75cbbe8415aaa207d5aa75a8129a3dfe6556cdc9272d7" dependencies = [ "amplify", "base85", "bp-consensus", "commit_verify", - "secp256k1 0.30.0", - "serde", + "secp256k1", "strict_encoding", ] [[package]] name = "bp-seals" -version = "0.11.0-beta.9" -source = "git+https://github.com/BP-WG/bp-core?branch=develop#59e41d4dd80fcbb27583d5f32b342873dc917602" +version = "0.12.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f7762a1a99f0b61f81e795e273f22c221609749279cf66c9a2cfcc5f58f8ee" dependencies = [ "amplify", "baid64", @@ -272,16 +210,15 @@ dependencies = [ "bp-dbc", "commit_verify", "rand", - "serde", "single_use_seals", "strict_encoding", ] [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byteorder" @@ -291,9 +228,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.30" +version = "1.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" dependencies = [ "shlex", ] @@ -306,9 +243,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "android-tzdata", "iana-time-zone", @@ -320,8 +257,9 @@ dependencies = [ [[package]] name = "commit_encoding_derive" -version = "0.11.0-beta.9" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=develop#4015f1fb9e99fdc536c69b957fa5727da9cfa6a9" +version = "0.12.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9613582af45e1564c09d813dae82e7c7bca95678b9c42dae955a8499ecc6ae95" dependencies = [ "amplify", "amplify_syn", @@ -332,8 +270,9 @@ dependencies = [ [[package]] name = "commit_verify" -version = "0.11.0-beta.9" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=develop#4015f1fb9e99fdc536c69b957fa5727da9cfa6a9" +version = "0.12.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4de6c513328b7228446f116caf74d658a2d39b305683f5ed24b73edccc3f9cf3" dependencies = [ "amplify", "commit_encoding_derive", @@ -346,22 +285,6 @@ dependencies = [ "vesper-lang", ] -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "constant_time_eq" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -370,19 +293,13 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - [[package]] name = "crypto-common" version = "0.1.6" @@ -405,9 +322,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "generic-array" @@ -432,21 +349,11 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] - [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -488,58 +395,41 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown", ] -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.159" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "memchr" -version = "2.7.4" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "minicov" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" dependencies = [ "cc", "walkdir", @@ -562,9 +452,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "paste" @@ -583,18 +473,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -631,22 +521,17 @@ dependencies = [ [[package]] name = "rgb-core" -version = "0.11.0-beta.9" +version = "0.12.0-beta.5" dependencies = [ - "aluvm", "amplify", - "baid64", "bp-core", - "chrono", "commit_verify", "getrandom", - "mime", "rand", - "secp256k1-zkp", "serde", "single_use_seals", "strict_encoding", - "strict_types", + "ultrasonic", "wasm-bindgen", "wasm-bindgen-test", ] @@ -661,10 +546,10 @@ dependencies = [ ] [[package]] -name = "ryu" -version = "1.0.18" +name = "rustversion" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "same-file" @@ -675,23 +560,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "secp256k1" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" -dependencies = [ - "rand", - "secp256k1-sys", - "serde", -] - [[package]] name = "secp256k1" version = "0.30.0" @@ -701,7 +569,6 @@ dependencies = [ "bitcoin_hashes", "rand", "secp256k1-sys", - "serde", ] [[package]] @@ -713,68 +580,24 @@ dependencies = [ "cc", ] -[[package]] -name = "secp256k1-zkp" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a44aed3002b5ae975f8624c5df3a949cfbf00479e18778b6058fcd213b76e3" -dependencies = [ - "bitcoin-private", - "rand", - "secp256k1 0.29.1", - "secp256k1-zkp-sys", - "serde", -] - -[[package]] -name = "secp256k1-zkp-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6eea7919e0cab992510edfbf40bd9342c0a3c2bb910f2c51355c2cb2d69839" -dependencies = [ - "cc", - "secp256k1-sys", -] - [[package]] name = "serde" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", -] - -[[package]] -name = "serde_json" -version = "1.0.128" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_spanned" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" -dependencies = [ - "serde", + "syn 2.0.98", ] [[package]] @@ -787,19 +610,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - [[package]] name = "sha2" version = "0.10.8" @@ -819,20 +629,21 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "single_use_seals" -version = "0.11.0-beta.9" -source = "git+https://github.com/LNP-BP/client_side_validation?branch=develop#4015f1fb9e99fdc536c69b957fa5727da9cfa6a9" +version = "0.12.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aca5a44fa5e544b62816ecb7309355e53a3bb36d55219606be0028227c13b64" dependencies = [ - "amplify_derive", + "serde", + "strict_encoding", ] [[package]] name = "strict_encoding" -version = "2.7.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d69b4893cf054e129d5288a565102124520d7b94eb9589d1e78202abc7e2092d" +checksum = "8fd36b71bb44ca146be0b2185ed6c6deb3684cc0d5c3a94284e97fe7fa6a642f" dependencies = [ "amplify", - "half", "serde", "strict_encoding_derive", "wasm-bindgen", @@ -840,9 +651,9 @@ dependencies = [ [[package]] name = "strict_encoding_derive" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4f9b678862372f8e439bcaafc27df7610ea93b06d2deb6244dec0af4259ce6" +checksum = "34e3bc6e4a2450420b4dbfb6929d9ce005e8c36cf73bf215db99f0d09c9fa79f" dependencies = [ "amplify_syn", "heck", @@ -853,21 +664,15 @@ dependencies = [ [[package]] name = "strict_types" -version = "2.7.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f16e8855a575633815f01482ac927ebaca3d2485aec8e17226c6826de29154e" +checksum = "0930ae36d58638b14dc7d5491c1a269b13f6cebb16a55ef6d753d3325c395ca8" dependencies = [ "amplify", - "ascii-armor", "baid64", - "half", "indexmap", - "serde", - "serde_json", - "serde_yaml", "sha2", "strict_encoding", - "toml", "vesper-lang", "wasm-bindgen", ] @@ -895,9 +700,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", @@ -906,75 +711,51 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] -name = "toml" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" +name = "typenum" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] -name = "toml_edit" -version = "0.22.22" +name = "ultrasonic" +version = "0.12.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "f9ed6d4109ce630333ee186c42370711cd24ec2b1567b4a750b8266595d92540" dependencies = [ - "indexmap", + "amplify", + "baid64", + "commit_verify", + "getrandom", "serde", - "serde_spanned", - "toml_datetime", - "winnow", + "strict_encoding", + "wasm-bindgen", + "zk-aluvm", ] -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" [[package]] name = "version_check" @@ -984,9 +765,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vesper-lang" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f72ebd3b32f16ee8ace2bd3058c2bfa0f4820992bd4ea86e73ba228bb13dd2b0" +checksum = "cd2b7e3e27aeb0524204e58042f6e4531a720745d1b1a3978d3a084f1885f63d" dependencies = [ "amplify", "strict_encoding", @@ -1010,47 +791,48 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1058,33 +840,34 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-bindgen-test" -version = "0.3.45" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d381749acb0943d357dcbd8f0b100640679883fcdeeef04def49daf8d33a5426" +checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" dependencies = [ - "console_error_panic_hook", "js-sys", "minicov", - "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test-macro", @@ -1092,20 +875,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.45" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c97b2ef2c8d627381e51c071c2ab328eac606d3f69dd82bcbca20a9e389d95f0" +checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -1202,15 +985,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "winnow" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" -dependencies = [ - "memchr", -] - [[package]] name = "zerocopy" version = "0.7.35" @@ -1229,5 +1003,19 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", +] + +[[package]] +name = "zk-aluvm" +version = "0.12.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b17bd7c20d85fd2ce336eb4b2975f5aab2bd5cd8d493eff04a881bd7a9e45b" +dependencies = [ + "aluvm", + "amplify", + "getrandom", + "serde", + "strict_encoding", + "wasm-bindgen", ] diff --git a/Cargo.toml b/Cargo.toml index ce5303e5..63f52d08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rgb-core" -version = "0.11.0-beta.9" +version = "0.12.0-beta.5" authors = ["Dr Maxim Orlovsky "] description = "RGB Core Library: confidential & scalable smart contracts on Bitcoin & Lightning (consensus layer)" repository = "https://github.com/RGB-WG/rgb-core" @@ -10,44 +10,36 @@ categories = ["cryptography::cryptocurrencies"] readme = "README.md" license = "Apache-2.0" edition = "2021" -rust-version = "1.77.0" # Due to `rustfix` +rust-version = "1.81.0" # Due to need for `Error` trait in `core` exclude = [".github"] [lib] name = "rgbcore" -crate-type = ["cdylib", "rlib"] # We need this for WASM - -[[bin]] -name = "rgbcore-stl" -required-features = ["stl"] +crate-type = ["cdylib", "rlib", "staticlib"] # We need this for WASM [dependencies] -amplify = { version = "~4.7.0", features = ["rand"] } -baid64 = "~0.2.2" -strict_encoding = "~2.7.0" -strict_types = { version = "~2.7.0", features = ["armor"] } -aluvm = { version = "~0.11.0-beta.9", features = ["std", "ascii-armor"] } -commit_verify = { version = "~0.11.0-beta.9", features = ["rand", "derive"] } -single_use_seals = "~0.11.0-beta.9" -bp-core = { version = "~0.11.0-beta.9" } -secp256k1-zkp = { version = "0.11.0", features = ["rand", "rand-std", "global-context"] } # TODO: Update version before the release -mime = "~0.3.17" -serde_crate = { package = "serde", version = "1", features = ["derive"], optional = true } -chrono = "0.4.38" +amplify = { version = "~4.8.0", default-features = false, features = ["alloc"] } +ultrasonic = "0.12.0-beta.5" +strict_encoding = "2.8.1" +commit_verify = "~0.12.0-beta.5" +single_use_seals = { version = "~0.12.0-beta.5", features = ["strict_encoding"] } +bp-core = { version = "0.12.0-beta.5", optional = true } +serde = { version = "1", optional = true } [features] -default = [] -all = ["stl", "serde"] -stl = ["commit_verify/stl", "bp-core/stl", "aluvm/stl"] +default = ["bitcoin"] +all = ["bitcoin", "liquid", "prime", "serde"] + +bitcoin = ["bp-core"] +liquid = ["bp-core"] +prime = [] + serde = [ - "serde_crate", + "dep:serde", "amplify/serde", - "strict_encoding/serde", - "strict_types/serde", + "ultrasonic/serde", "commit_verify/serde", - "bp-core/serde", - "aluvm/serde", - "secp256k1-zkp/serde" + "single_use_seals/serde" ] [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -60,12 +52,3 @@ wasm-bindgen-test = "0.3" [package.metadata.docs.rs] features = ["all"] - -[patch.crates-io] -commit_verify = { git = "https://github.com/LNP-BP/client_side_validation", branch = "develop" } -single_use_seals = { git = "https://github.com/LNP-BP/client_side_validation", branch = "develop" } -aluvm = { git = "https://github.com/AluVM/rust-aluvm", branch = "develop" } -bp-consensus = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } -bp-dbc = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } -bp-seals = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } -bp-core = { git = "https://github.com/BP-WG/bp-core", branch = "develop" } diff --git a/LICENSE b/LICENSE index 2385ae39..d9a10c0d 100644 --- a/LICENSE +++ b/LICENSE @@ -174,29 +174,3 @@ of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2019-2024 LNP/BP Standards Association, Switzerland - Copyright 2019-2024 Dr Maxim Orlovsky - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/MANIFEST.yml b/MANIFEST.yml deleted file mode 100644 index 5d9baa92..00000000 --- a/MANIFEST.yml +++ /dev/null @@ -1,14 +0,0 @@ -Name: rgb-core -Type: Library -Kind: Free software -License: Apache-2.0 -Language: Rust -Compiler: 1.77 -Author: Maxim Orlovsky -Maintained: LNP/BP Standards Association, Switzerland -Maintainers: - Maxim Orlovsky: - GitHub: @dr-orlovsky - GPG: EAE730CEC0C663763F028A5860094BAF18A26EC9 - SSH: BoSGFzbyOKC7Jm28MJElFboGepihCpHop60nS8OoG/A - EMail: dr@orlovsky.ch diff --git a/doc/Commitments.md b/doc/Commitments.md index 9eb90d18..130ec1b0 100644 --- a/doc/Commitments.md +++ b/doc/Commitments.md @@ -1,62 +1,62 @@ # RGB consensus commitments -RGB commits to client-side validated data using dedicated serialization +RGB commits to client-side validated data using dedicated serialization mechanism, implemented via `CommitEncode` trait. Depending on the specific data, -the mechanism can be is partially or completely different from strict -serialization, used for data storage. For instance, all data which may be -confidential must be concealed, such that parties having no access to the -original non-confidential values still be able to generate the same +the mechanism can be is partially or completely different from strict +serialization, used for data storage. For instance, all data which may be +confidential must be concealed, such that parties having no access to the +original non-confidential values still be able to generate the same deterministic commitment value and verify single-use seals. Any final consensus commitment is a SHA256 tagged hash. The tagging is performed -according to BIP-340, when a commitment-specific fixed ASCII string value is +according to BIP-340, when a commitment-specific fixed ASCII string value is first hashed with a single SHA256 hash, and the resulting 32 bytes are feed into a new SHA256 hasher twice before any actual data. - ## Generating commitment id -The commitment mechanism uses traits from [`commit_verify`] crate, specifically +The commitment mechanism uses traits from [`commit_verify`] crate, specifically its `id.rs`and `merkle.rs` modules. ### `CommitEncode` trait -It is the main trait which must be implemented for each type requiring a -dedicated commitment id. +It is the main trait which must be implemented for each type requiring a +dedicated commitment id. -The trait implementation can be done either with derive macro +The trait implementation can be done either with derive macro `#[derive(CommitEncode)]` or by providing a manual implementation. The derive macro takes two arguments: `strategy` and `id`: -- `id` must specify a resulting commitment id type, i.e. type wrapping 32-byte - tagged SHA256 hash, implementing `CommitmentId` trait (the implementation - provides a tag for the hasher - see trait details below). The type must also + +- `id` must specify a resulting commitment id type, i.e. type wrapping 32-byte + tagged SHA256 hash, implementing `CommitmentId` trait (the implementation + provides a tag for the hasher - see trait details below). The type must also provide a converting constructor from `coommit_verify::Sha256` hasher. -- `strategy` specifies a workflow used to feed the type data to the SHA256 +- `strategy` specifies a workflow used to feed the type data to the SHA256 tagged hasher: - * `strategy = strict`: the hasher receive strict-serialized type; - * `strategy = conceal`: the type data are first concealed, and only then are - strict-serialized into the hasher. + * `strategy = strict`: the hasher receive strict-serialized type; + * `strategy = conceal`: the type data are first concealed, and only then are + strict-serialized into the hasher. Manual `CommitEncode` implementation must be provided only when the commitment procedure is custom and can't be implemented using any of the strategies, for instance when a collection must be merklized (see on merklization below). NB: you should never call methods of `CommitEncode` trait directly, and instead -use `CommitId` trait, which is automatically implemented for +use `CommitId` trait, which is automatically implemented for ### `CommitmentId` trait Each consensus commitment must have a dedicated Rust newtype, which wraps over inner `Bytes32` - a 32-byte resulting tagged hash value. The type is marked as -a consensus commitment by implementing `CommitmentId` trait for it, which +a consensus commitment by implementing `CommitmentId` trait for it, which requires to provide a tag string values for the tagged hash. -The hash tags are defined using URN strings in form of +The hash tags are defined using URN strings in form of `urn:::#`, where `` stands for the organization, -`` is the name of the protocol, `` is the data type name +`` is the name of the protocol, `` is the data type name producing the commitment, and `` is a `YYYY-MM-DD` string for the latest -revision of the commitment layout. +revision of the commitment layout. ### `CommitId` trait @@ -65,42 +65,45 @@ implementation. You can't implement this trait manually and just need to call its `CommitId::commit_id()` method to produce the final commitment (i.e. bytes of the tagged hash in form of `CommitmentId`-implementing type). -The trait also provides `CommitId::commitment_layout()` method, which can be +The trait also provides `CommitId::commitment_layout()` method, which can be used for automatically generating the documentation on the commitment workflow. ## Merklization procedure Merlization procedure uses traits and data types from `merkle.rs` module of -`commit_verify` crate. It commits to the tree parameters, such as number of -elements, depth of the tree, as well as depth of each node; and uses tagged +`commit_verify` crate. It commits to the tree parameters, such as number of +elements, depth of the tree, as well as depth of each node; and uses tagged SHA256, like the rest of the commitment procedures used here. The main data type, related to the merklization, is `MerkleHash`: it is a tagged -hash (using `urn:ubideco:merkle:node#2024-01-31` tag) representing node at any -position of the tree: leaves, branch nodes and merkle tree root. `MerkleHash` +hash (using `urn:ubideco:merkle:node#2024-01-31` tag) representing node at any +position of the tree: leaves, branch nodes and merkle tree root. `MerkleHash` can be produced in the following ways: + - as a result of merklziation procedure, when it represents Merkle tree root; - as a root of empty Merkle tree (i.e. collection having 0 elements), by calling `MerkleHash::void(0u8, 0u32)`, - as a Merkle leaf, by implementing `CommitEncode` on some type and setting commitment id to be `MerkleHash`. - + In all of the above cases the hash commits to the tree parameters, which makes it safe to use the same type for leaves, branches and root nodes. Specifically, it uses an intermediate structure `MerkleNode`, which is filled with information on (see [`MerkleNode.vesper`](../stl/MerkleNode.vesper) for details): + - type of node branching (no branches, one branch or two branches), - depth of the node, as 8-bit unsigned integer, - width of the tree at its base, as a 256-bit LE unsigned integer, - node hashes of the branches; if one or both branches are absent, they are - replaced with 32 bytes of repeated 0xFF value. + replaced with 32 bytes of repeated 0xFF value. -A collection in form of a list (Rust `Vec`) or an ordered set of unique +A collection in form of a list (Rust `Vec`) or an ordered set of unique non-repeating items (Rust `BTreeSet`), if wrapped into a confinement (i.e. has -type-defined bounds on the minimum or maximum number of items) can be +type-defined bounds on the minimum or maximum number of items) can be automatically merklized when passed as an argument to `MerkleHash::merklize()` call. The API puts the following requirements on the collection: either -- maximum number of elements must be either 0xFF or 0xFFFF **and** each + +- maximum number of elements must be either 0xFF or 0xFFFF **and** each collection element must implement `CommitEncode` trait with target id set to `MerkleHash`, - or there is a manual implementation of `MerkleLeaves` trait. @@ -123,7 +126,6 @@ flowchart BT Leaf -- commit_id ----> MerkleHash ``` - ## Specific RGB consensus commitments Currently, RGB has three consensus commitments: schema, operation and bundle. @@ -149,9 +151,11 @@ Here are more details on each type of the commitments: (1): "URN suffix" is a part which follows "urn:lnp-bp:" prefix. -The last three commitments coincide to be a concealed form of BP seals and RGB state. +The last three commitments coincide to be a concealed form of BP seals and RGB +state. These commitments produced by either calling `commit_id` or `conceal` methods of -revealed seal (`BlindSeal`) and state types (`RevealedData` and `RevealedAttach`). +revealed seal (`BlindSeal`) and state types (`RevealedData` +and `RevealedAttach`). Additionally to these types there are two other commitment ids used internally by merklization and strict encoding procedures: `MerkleHash` (discussed in the @@ -163,82 +167,80 @@ Merklization section above) and `StrictHash` from `commit_verify` crate: | `StrictHash` | `urn:ubideco:strict-types:value-hash#2024-02-10` | | `mpc::Commitment` | `urn:ubideco:mpc:commitment#2024-01-31` | -`StrictHash` can be produced as a result of serialization of any -strict-encodable data; for instance, it is used in compactifying collections +`StrictHash` can be produced as a result of serialization of any +strict-encodable data; for instance, it is used in compactifying collections into a single hash field in the process of computing operation ids (described below). -Finally, in `commit_verify::mpc`, multi-protocol commitment protocol -implementation, we have a type named `mpc::Commitment`, which is a commitment +Finally, in `commit_verify::mpc`, multi-protocol commitment protocol +implementation, we have a type named `mpc::Commitment`, which is a commitment to a root of the MPC tree (i.e. the tree's root `MerkleHash` is tag-hashed once again to produce the final commitment value). - ### Schema ID Schema id, represented by `SchemaId` data type, is produced from `Schema` type -via strict serialization of all the schema data using -`urn:lnp-bp:rgb:schema#2024-02-03` hash tag. No conceal or merklization +via strict serialization of all the schema data using +`urn:lnp-bp:rgb:schema#2024-02-03` hash tag. No conceal or merklization procedures are applied; i.e. the commitment id is the same as hashing serialized -schema with the given tag. The full description of how schema data are +schema with the given tag. The full description of how schema data are serialized into the hasher can be found in [`Schema.vesper`]( -../stl/Schema.vesper) file, which is automatically generated from the RGB rust +../stl/Genesis.vesper) file, which is automatically generated from the RGB rust code. - + ### Operation ID and Contract ID -Operation id is represented by a `OpId` type and produced for `Genesis`, +Operation id is represented by a `OpId` type and produced for `Genesis`, `Transition` and `Extension` types via custom algorithm, which first creates a -dedicated `OpCommitment` structure, and strict-serializes it to hasher, -initialized with `urn:lnp-bp:rgb:operation#2024-02-03` hash tag. - +dedicated `OpCommitment` structure, and strict-serializes it to hasher, +initialized with `urn:lnp-bp:rgb:operation#2024-02-03` hash tag. + The `OpCommitment` by itself consists of a sub-commitments to blocks of the operation data, where each sub-commitment is created with a custom procedure. For instance, operation global state, inputs and assignments are merklized, such that a succinct proofs of some specific state or input inclusion in RGB operation can be produced and used in smart contracts. Additionally to that, -assignments are concealed before the merklization, and range proofs are +assignments are concealed before the merklization, and range proofs are removed from the commitment, such that an aggregation of the historical proofs -can be applied without changing the operation ids. - -To ensure succinctness, other types of collections, such as redeemed and -defined valencies and list of alternate layer 1 in genesis are not merklized -and strict-serialized producing `StrictHash`, which participates in the final +can be applied without changing the operation ids. + +To ensure succinctness, other types of collections, such as redeemed and +defined valencies and list of alternate layer 1 in genesis are not merklized +and strict-serialized producing `StrictHash`, which participates in the final `OpCommitment` structure. ```mermaid flowchart LR - subgraph "Common data" - Ffv --> OpCommitment - TypeCommitment --> OpCommitment - Metadata -- StrictHash --> OpCommitment - Globals -- Merklize --> OpCommitment - Inputs -- Merklize --> OpCommitment - Assignments -- "Conceal\n + Merklize" --> OpCommitment - Redeemed -- StrictHash --> OpCommitment - Valencies -- StrictHash --> OpCommitment - end - - subgraph "Genesis" - schemaId --> BaseCommitment - testnet --> BaseCommitment - altLayers1 -- StrictHash --> BaseCommitment - end - - subgraph "Transition" - tcid[contractId] --> TypeCommitment - transitionType --> TypeCommitment - end - - subgraph "Extension" - ecid[contractId] --> TypeCommitment - extensionType --> TypeCommitment - end - - BaseCommitment --> TypeCommitment - - OpCommitment -- hash --> OpId - OpId -- "reverse bytes\n(genesis only)" --> ContractId + subgraph "Common data" + Ffv --> OpCommitment + TypeCommitment --> OpCommitment + Metadata -- StrictHash --> OpCommitment + Globals -- Merklize --> OpCommitment + Inputs -- Merklize --> OpCommitment + Assignments -- " Conceal\n + Merklize " --> OpCommitment + Redeemed -- StrictHash --> OpCommitment + Valencies -- StrictHash --> OpCommitment + end + + subgraph "Genesis" + schemaId --> BaseCommitment + testnet --> BaseCommitment + altLayers1 -- StrictHash --> BaseCommitment + end + + subgraph "Transition" + tcid[contractId] --> TypeCommitment + transitionType --> TypeCommitment + end + + subgraph "Extension" + ecid[contractId] --> TypeCommitment + extensionType --> TypeCommitment + end + + BaseCommitment --> TypeCommitment + OpCommitment -- hash --> OpId + OpId -- " reverse bytes\n(genesis only) " --> ContractId ``` Additionally to `OpId`, genesis produces `ContractId`, which is made out of the @@ -248,28 +250,27 @@ genesis `OpId` by reversing byte order and using Base58 encoding. Bundle id is a unique identifier of state transition bundle, directly used in constructing multi-protocol commitment tree. Bundle id commits to operation ids -for the participating state transitions and maps of the witness transaction -input to the operation ids. For this purpose, the commitment is created by -strict-encoding `input_map` field of `TransitionBundle` into the hasher, +for the participating state transitions and maps of the witness transaction +input to the operation ids. For this purpose, the commitment is created by +strict-encoding `input_map` field of `TransitionBundle` into the hasher, initialized with tag `urn:lnp-bp:rgb:bundle#2024-02-03`. Input map is serialized first as a 16-bit little-endian integer specifying the number of the items in -the map, followed by the sequence of pairs of input number (32-bit LE value) +the map, followed by the sequence of pairs of input number (32-bit LE value) and `OpId` (32-bytes). ```mermaid flowchart TD - subgraph Discarded - id((" ")) - end - - subgraph TransitionBundle - inputMap - knownTransitions - end - - inputMap -- encode \n hash --> BundleId - knownTransitions --x Discarded -``` +subgraph Discarded +id((" ")) +end +subgraph TransitionBundle +inputMap +knownTransitions +end + +inputMap -- encode \n hash --> BundleId +knownTransitions --x Discarded +``` [`commit_verify`]: https://docs.rs/commit_verify diff --git a/scripts/typelib.sh b/scripts/typelib.sh deleted file mode 100755 index cb53b98e..00000000 --- a/scripts/typelib.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -cargo run --features stl --bin rgbcore-stl -- --sty -cargo run --features stl --bin rgbcore-stl -- --stl -cargo run --features stl --bin rgbcore-stl -- --sta diff --git a/src/bin/rgbcore-stl.rs b/src/bin/rgbcore-stl.rs deleted file mode 100644 index 45908e92..00000000 --- a/src/bin/rgbcore-stl.rs +++ /dev/null @@ -1,161 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::fs; -use std::io::Write; - -use aluvm::stl::aluvm_stl; -use bp::stl::bp_core_stl; -use commit_verify::stl::commit_verify_stl; -use commit_verify::CommitmentLayout; -use rgbcore::stl::bp_tx_stl; -use rgbcore::{Schema, Transition, TransitionBundle}; -use strict_types::stl::{std_stl, strict_types_stl}; -use strict_types::typelib::parse_args; -use strict_types::SystemBuilder; - -fn main() { - let (format, dir) = parse_args(); - - let rgb_commit = rgbcore::stl::rgb_commit_stl(); - let rgb_logic = rgbcore::stl::rgb_logic_stl(); - - rgb_commit - .serialize( - format, - dir.as_ref(), - "0.1.0", - Some( - " - Description: Consensus commitment layer for RGB smart contracts - Author: Dr Maxim Orlovsky - Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0", - ), - ) - .expect("unable to write to the file"); - - rgb_logic - .serialize( - format, - dir.as_ref(), - "0.1.0", - Some( - " - Description: Consensus logic layer for RGB smart contracts - Author: Dr Maxim Orlovsky - Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0", - ), - ) - .expect("unable to write to the file"); - - let std = std_stl(); - let tx = bp_tx_stl(); - let bp = bp_core_stl(); - let cv = commit_verify_stl(); - let st = strict_types_stl(); - let vm = aluvm_stl(); - - let sys = SystemBuilder::new() - .import(rgb_logic) - .unwrap() - .import(rgb_commit) - .unwrap() - .import(vm) - .unwrap() - .import(bp) - .unwrap() - .import(tx) - .unwrap() - .import(cv) - .unwrap() - .import(st) - .unwrap() - .import(std) - .unwrap() - .finalize() - .expect("not all libraries present"); - - let dir = dir.unwrap_or_else(|| ".".to_owned()); - - let mut file = fs::File::create(format!("{dir}/Schema.vesper")).unwrap(); - writeln!( - file, - "{{- - Description: RGB Schema - Author: Dr Maxim Orlovsky - Copyright (C) 2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --}} - -Schema vesper lexicon=types+commitments -" - ) - .unwrap(); - let layout = Schema::commitment_layout(); - writeln!(file, "{layout}").unwrap(); - let tt = sys.type_tree("RGBCommit.Schema").unwrap(); - writeln!(file, "{tt}").unwrap(); - - let mut file = fs::File::create(format!("{dir}/Transition.vesper")).unwrap(); - writeln!( - file, - "{{- - Description: RGB Transition - Author: Dr Maxim Orlovsky - Copyright (C) 2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --}} - -Transition vesper lexicon=types+commitments -" - ) - .unwrap(); - let layout = Transition::commitment_layout(); - writeln!(file, "{layout}").unwrap(); - let tt = sys.type_tree("RGBCommit.OpCommitment").unwrap(); - writeln!(file, "{tt}").unwrap(); - let tt = sys.type_tree("RGBCommit.Transition").unwrap(); - writeln!(file, "{tt}").unwrap(); - - let mut file = fs::File::create(format!("{dir}/AnchoredBundle.vesper")).unwrap(); - writeln!( - file, - "{{- - Description: RGB Anchored Bundles - Author: Dr Maxim Orlovsky - Copyright (C) 2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --}} - -Bundles vesper lexicon=types+commitments -" - ) - .unwrap(); - let layout = TransitionBundle::commitment_layout(); - writeln!(file, "{layout}").unwrap(); - let tt = sys.type_tree("RGBLogic.DbcProof").unwrap(); - writeln!(file, "{tt}").unwrap(); - let tt = sys.type_tree("RGBCommit.TransitionBundle").unwrap(); - writeln!(file, "{tt}").unwrap(); -} diff --git a/src/lib.rs b/src/lib.rs index 22194544..ab818266 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,134 +2,44 @@ // // SPDX-License-Identifier: Apache-2.0 // -// Written in 2019-2024 by -// Dr Maxim Orlovsky +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky // -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are reserved. // -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Unless required by applicable law or agreed to in writing, software distributed under the License +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +// or implied. See the License for the specific language governing permissions and limitations under +// the License. -#![allow(unused_braces)] // Rust compiler can't properly parse derivation macros #![cfg_attr(docsrs, feature(doc_auto_cfg))] +// TODO: Enable when strict encoding supports +// #![no_std] +extern crate alloc; #[macro_use] extern crate amplify; #[macro_use] extern crate strict_encoding; -#[macro_use] -extern crate commit_verify; - #[cfg(feature = "serde")] #[macro_use] -extern crate serde_crate as serde; -extern crate core; - -mod operation; -pub mod schema; -pub mod validation; -#[macro_use] -pub mod vm; -#[cfg(feature = "stl")] -pub mod stl; - -pub mod prelude { - pub use commit_verify::ReservedBytes; - pub use operation::*; - pub use schema::*; - pub use vm::XWitnessId; - - #[cfg(feature = "stl")] - pub use super::stl; - use super::*; - pub use super::{schema, validation, vm}; -} - -pub use prelude::*; - -pub const LIB_NAME_RGB_COMMIT: &str = "RGBCommit"; -pub const LIB_NAME_RGB_LOGIC: &str = "RGBLogic"; - -/// Fast-forward version code -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Default, Debug, Display)] -#[display("RGB/1.{0}")] -#[derive(StrictType, StrictEncode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Ffv(u16); - -mod _ffv { - use strict_encoding::{DecodeError, ReadTuple, StrictDecode, TypedRead}; - - use crate::Ffv; - - impl StrictDecode for Ffv { - fn strict_decode(reader: &mut impl TypedRead) -> Result { - let ffv = reader.read_tuple(|r| r.read_field().map(Self))?; - if ffv != Ffv::default() { - Err(DecodeError::DataIntegrityError(format!( - "unsupported fast-forward version code belonging to a future RGB version. \ - Please update your software, or, if the problem persists, contact your \ - vendor providing the following version information: {ffv}" - ))) - } else { - Ok(ffv) - } - } - } -} - -#[macro_export] -macro_rules! impl_serde_baid64 { - ($ty:ty) => { - #[cfg(feature = "serde")] - mod _serde { - use amplify::ByteArray; - use serde_crate::de::Error; - use serde_crate::{Deserialize, Deserializer, Serialize, Serializer}; - - use super::*; +extern crate serde; - impl Serialize for $ty { - fn serialize(&self, serializer: S) -> Result - where S: Serializer { - if serializer.is_human_readable() { - self.to_string().serialize(serializer) - } else { - self.to_byte_array().serialize(serializer) - } - } - } +mod verify; +mod seals; - impl<'de> Deserialize<'de> for $ty { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> { - if deserializer.is_human_readable() { - let s = String::deserialize(deserializer)?; - Self::from_str(&s).map_err(D::Error::custom) - } else { - let bytes = <[u8; 32]>::deserialize(deserializer)?; - Ok(Self::from_byte_array(bytes)) - } - } - } - } - }; -} +pub use seals::{RgbSealDef, RgbSealSrc}; +pub use single_use_seals::*; +pub use verify::{ContractApi, ContractVerify, OperationSeals, ReadOperation, ReadWitness, Step, VerificationError}; -// TODO: Validate strict type data -// TODO: Add parsed global and structured state to the ContractState +pub const LIB_NAME_RGB_CORE: &str = "RGBCore"; diff --git a/src/operation/assignments.rs b/src/operation/assignments.rs deleted file mode 100644 index 7e719423..00000000 --- a/src/operation/assignments.rs +++ /dev/null @@ -1,653 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use core::cmp::Ordering; -use core::fmt::Debug; -use std::collections::{btree_map, BTreeSet}; -use std::hash::Hash; - -use amplify::confinement::{Confined, SmallVec, TinyOrdMap}; -use commit_verify::{Conceal, ReservedBytes}; -use strict_encoding::{StrictDumb, StrictEncode}; - -use super::ExposedState; -use crate::operation::seal::GenesisSeal; -use crate::{ - AssignmentType, ExposedSeal, GraphSeal, RevealedAttach, RevealedData, RevealedValue, - SecretSeal, StateType, VoidState, XChain, LIB_NAME_RGB_COMMIT, -}; - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Display, Error)] -#[display(doc_comments)] -/// the requested data are not present. -pub struct UnknownDataError; - -pub type AssignRights = Assign; -pub type AssignFungible = Assign; -pub type AssignData = Assign; -pub type AssignAttach = Assign; - -/// State data are assigned to a seal definition, which means that they are -/// owned by a person controlling spending of the seal UTXO, unless the seal -/// is closed, indicating that a transfer of ownership had taken place -#[derive(Clone, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type( - lib = LIB_NAME_RGB_COMMIT, - tags = custom, - dumb = { Self::Confidential { seal: strict_dumb!(), state: strict_dumb!(), lock: default!() } } -)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde( - crate = "serde_crate", - rename_all = "camelCase", - untagged, - bound = "State::Confidential: serde::Serialize + serde::de::DeserializeOwned, State: \ - serde::Serialize + serde::de::DeserializeOwned, Seal: serde::Serialize + \ - serde::de::DeserializeOwned" - ) -)] -pub enum Assign { - #[strict_type(tag = 0x00)] - Confidential { - seal: XChain, - state: State::Confidential, - lock: ReservedBytes<2, 0>, - }, - #[strict_type(tag = 0x03)] - Revealed { - seal: XChain, - state: State, - lock: ReservedBytes<2, 0>, - }, - #[strict_type(tag = 0x02)] - ConfidentialSeal { - seal: XChain, - state: State, - lock: ReservedBytes<2, 0>, - }, - #[strict_type(tag = 0x01)] - ConfidentialState { - seal: XChain, - state: State::Confidential, - lock: ReservedBytes<2, 0>, - }, -} - -// Consensus-critical! -// Assignment indexes are part of the transition ancestor's commitment, so -// here we use deterministic ordering based on hash values of the concealed -// seal data contained within the assignment -impl PartialOrd for Assign { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl Ord for Assign { - fn cmp(&self, other: &Self) -> Ordering { - self.to_confidential_seal() - .cmp(&other.to_confidential_seal()) - } -} - -impl PartialEq for Assign { - fn eq(&self, other: &Self) -> bool { - self.to_confidential_seal() == other.to_confidential_seal() - && self.to_confidential_state() == other.to_confidential_state() - } -} - -impl Eq for Assign {} - -impl Assign { - pub fn revealed(seal: XChain, state: State) -> Self { - Assign::Revealed { - seal, - state, - lock: default!(), - } - } - - pub fn with_seal_replaced(assignment: &Self, seal: XChain) -> Self { - match assignment { - Assign::Confidential { - seal: _, - state, - lock, - } - | Assign::ConfidentialState { - seal: _, - state, - lock, - } => Assign::ConfidentialState { - seal, - state: *state, - lock: *lock, - }, - Assign::ConfidentialSeal { - seal: _, - state, - lock, - } - | Assign::Revealed { - seal: _, - state, - lock, - } => Assign::Revealed { - seal, - state: state.clone(), - lock: *lock, - }, - } - } - - pub fn to_confidential_seal(&self) -> XChain { - match self { - Assign::Revealed { seal, .. } | Assign::ConfidentialState { seal, .. } => { - seal.conceal() - } - Assign::Confidential { seal, .. } | Assign::ConfidentialSeal { seal, .. } => *seal, - } - } - - pub fn revealed_seal(&self) -> Option> { - match self { - Assign::Revealed { seal, .. } | Assign::ConfidentialState { seal, .. } => Some(*seal), - Assign::Confidential { .. } | Assign::ConfidentialSeal { .. } => None, - } - } - - pub fn to_confidential_state(&self) -> State::Confidential { - match self { - Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => { - state.conceal() - } - Assign::Confidential { state, .. } | Assign::ConfidentialState { state, .. } => *state, - } - } - - pub fn as_revealed_state(&self) -> Option<&State> { - match self { - Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => Some(state), - Assign::Confidential { .. } | Assign::ConfidentialState { .. } => None, - } - } - - pub fn as_revealed_state_mut(&mut self) -> Option<&mut State> { - match self { - Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => Some(state), - Assign::Confidential { .. } | Assign::ConfidentialState { .. } => None, - } - } - - pub fn into_revealed_state(self) -> Option { - match self { - Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => Some(state), - Assign::Confidential { .. } | Assign::ConfidentialState { .. } => None, - } - } - - pub fn as_revealed(&self) -> Option<(&XChain, &State)> { - match self { - Assign::Revealed { seal, state, .. } => Some((seal, state)), - _ => None, - } - } - - pub fn to_revealed(&self) -> Option<(XChain, State)> { - match self { - Assign::Revealed { seal, state, .. } => Some((*seal, state.clone())), - _ => None, - } - } - - pub fn into_revealed(self) -> Option<(XChain, State)> { - match self { - Assign::Revealed { seal, state, .. } => Some((seal, state)), - _ => None, - } - } -} - -impl Conceal for Assign -where Self: Clone -{ - type Concealed = Self; - - fn conceal(&self) -> Self::Concealed { - match self { - Assign::Confidential { .. } => self.clone(), - Assign::ConfidentialState { seal, state, lock } => Self::Confidential { - seal: seal.conceal(), - state: *state, - lock: *lock, - }, - Assign::Revealed { seal, state, lock } => Self::Confidential { - seal: seal.conceal(), - state: state.conceal(), - lock: *lock, - }, - Assign::ConfidentialSeal { seal, state, lock } => Self::Confidential { - seal: *seal, - state: state.conceal(), - lock: *lock, - }, - } - } -} - -impl Assign { - pub fn transmutate_seals(&self) -> Assign { - match self { - Assign::Confidential { seal, state, lock } => Assign::Confidential { - seal: *seal, - state: *state, - lock: *lock, - }, - Assign::ConfidentialSeal { seal, state, lock } => Assign::ConfidentialSeal { - seal: *seal, - state: state.clone(), - lock: *lock, - }, - Assign::Revealed { seal, state, lock } => Assign::Revealed { - seal: seal.transmutate(), - state: state.clone(), - lock: *lock, - }, - Assign::ConfidentialState { seal, state, lock } => Assign::ConfidentialState { - seal: seal.transmutate(), - state: *state, - lock: *lock, - }, - } - } -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = custom, dumb = Self::Declarative(strict_dumb!()))] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde( - crate = "serde_crate", - rename_all = "camelCase", - tag = "type", - content = "items", - bound = "Seal: serde::Serialize + serde::de::DeserializeOwned" - ) -)] -pub enum TypedAssigns { - // TODO: Consider using non-empty variants - #[strict_type(tag = 0x00)] - Declarative(SmallVec>), - #[strict_type(tag = 0x01)] - Fungible(SmallVec>), - #[strict_type(tag = 0x02)] - Structured(SmallVec>), - #[strict_type(tag = 0xFF)] - Attachment(SmallVec>), -} - -impl Conceal for TypedAssigns { - type Concealed = Self; - fn conceal(&self) -> Self::Concealed { - match self { - TypedAssigns::Declarative(s) => { - let concealed_iter = s.iter().map(AssignRights::::conceal); - let inner = SmallVec::try_from_iter(concealed_iter).expect("same size"); - TypedAssigns::Declarative(inner) - } - TypedAssigns::Fungible(s) => { - let concealed_iter = s.iter().map(AssignFungible::::conceal); - let inner = SmallVec::try_from_iter(concealed_iter).expect("same size"); - TypedAssigns::Fungible(inner) - } - TypedAssigns::Structured(s) => { - let concealed_iter = s.iter().map(AssignData::::conceal); - let inner = SmallVec::try_from_iter(concealed_iter).expect("same size"); - TypedAssigns::Structured(inner) - } - TypedAssigns::Attachment(s) => { - let concealed_iter = s.iter().map(AssignAttach::::conceal); - let inner = SmallVec::try_from_iter(concealed_iter).expect("same size"); - TypedAssigns::Attachment(inner) - } - } - } -} - -impl TypedAssigns { - pub fn is_empty(&self) -> bool { - match self { - TypedAssigns::Declarative(set) => set.is_empty(), - TypedAssigns::Fungible(set) => set.is_empty(), - TypedAssigns::Structured(set) => set.is_empty(), - TypedAssigns::Attachment(set) => set.is_empty(), - } - } - - pub fn len_u16(&self) -> u16 { - match self { - TypedAssigns::Declarative(set) => set.len_u16(), - TypedAssigns::Fungible(set) => set.len_u16(), - TypedAssigns::Structured(set) => set.len_u16(), - TypedAssigns::Attachment(set) => set.len_u16(), - } - } - - #[inline] - pub fn state_type(&self) -> StateType { - match self { - TypedAssigns::Declarative(_) => StateType::Void, - TypedAssigns::Fungible(_) => StateType::Fungible, - TypedAssigns::Structured(_) => StateType::Structured, - TypedAssigns::Attachment(_) => StateType::Attachment, - } - } - - #[inline] - pub fn is_declarative(&self) -> bool { matches!(self, TypedAssigns::Declarative(_)) } - - #[inline] - pub fn is_fungible(&self) -> bool { matches!(self, TypedAssigns::Fungible(_)) } - - #[inline] - pub fn is_structured(&self) -> bool { matches!(self, TypedAssigns::Structured(_)) } - - #[inline] - pub fn is_attachment(&self) -> bool { matches!(self, TypedAssigns::Attachment(_)) } - - #[inline] - pub fn as_declarative(&self) -> &[AssignRights] { - match self { - TypedAssigns::Declarative(set) => set, - _ => Default::default(), - } - } - - #[inline] - pub fn as_fungible(&self) -> &[AssignFungible] { - match self { - TypedAssigns::Fungible(set) => set, - _ => Default::default(), - } - } - - #[inline] - pub fn as_structured(&self) -> &[AssignData] { - match self { - TypedAssigns::Structured(set) => set, - _ => Default::default(), - } - } - - #[inline] - pub fn as_attachment(&self) -> &[AssignAttach] { - match self { - TypedAssigns::Attachment(set) => set, - _ => Default::default(), - } - } - - #[inline] - pub fn as_declarative_mut(&mut self) -> Option<&mut SmallVec>> { - match self { - TypedAssigns::Declarative(set) => Some(set), - _ => None, - } - } - - #[inline] - pub fn as_fungible_mut(&mut self) -> Option<&mut SmallVec>> { - match self { - TypedAssigns::Fungible(set) => Some(set), - _ => None, - } - } - - #[inline] - pub fn as_structured_mut(&mut self) -> Option<&mut SmallVec>> { - match self { - TypedAssigns::Structured(set) => Some(set), - _ => None, - } - } - - #[inline] - pub fn as_attachment_mut(&mut self) -> Option<&mut SmallVec>> { - match self { - TypedAssigns::Attachment(set) => Some(set), - _ => None, - } - } - - /// If seal definition does not exist, returns [`UnknownDataError`]. If the - /// seal is confidential, returns `Ok(None)`; otherwise returns revealed - /// seal data packed as `Ok(Some(`[`Seal`]`))` - pub fn revealed_seal_at(&self, index: u16) -> Result>, UnknownDataError> { - Ok(match self { - TypedAssigns::Declarative(vec) => vec - .get(index as usize) - .ok_or(UnknownDataError)? - .revealed_seal(), - TypedAssigns::Fungible(vec) => vec - .get(index as usize) - .ok_or(UnknownDataError)? - .revealed_seal(), - TypedAssigns::Structured(vec) => vec - .get(index as usize) - .ok_or(UnknownDataError)? - .revealed_seal(), - TypedAssigns::Attachment(vec) => vec - .get(index as usize) - .ok_or(UnknownDataError)? - .revealed_seal(), - }) - } - - pub fn to_confidential_seals(&self) -> Vec> { - match self { - TypedAssigns::Declarative(s) => s - .iter() - .map(AssignRights::::to_confidential_seal) - .collect(), - TypedAssigns::Fungible(s) => s - .iter() - .map(AssignFungible::::to_confidential_seal) - .collect(), - TypedAssigns::Structured(s) => s - .iter() - .map(AssignData::::to_confidential_seal) - .collect(), - TypedAssigns::Attachment(s) => s - .iter() - .map(AssignAttach::::to_confidential_seal) - .collect(), - } - } - - pub fn as_structured_state_at( - &self, - index: u16, - ) -> Result, UnknownDataError> { - match self { - TypedAssigns::Structured(vec) => Ok(vec - .get(index as usize) - .ok_or(UnknownDataError)? - .as_revealed_state()), - _ => Err(UnknownDataError), - } - } - - pub fn as_fungible_state_at( - &self, - index: u16, - ) -> Result, UnknownDataError> { - match self { - TypedAssigns::Fungible(vec) => Ok(vec - .get(index as usize) - .ok_or(UnknownDataError)? - .as_revealed_state()), - _ => Err(UnknownDataError), - } - } - - pub fn into_structured_state_at( - self, - index: u16, - ) -> Result, UnknownDataError> { - match self { - TypedAssigns::Structured(vec) => { - if index as usize >= vec.len() { - return Err(UnknownDataError); - } - Ok(vec.release().remove(index as usize).into_revealed_state()) - } - _ => Err(UnknownDataError), - } - } - - pub fn into_fungible_state_at( - self, - index: u16, - ) -> Result, UnknownDataError> { - match self { - TypedAssigns::Fungible(vec) => { - if index as usize >= vec.len() { - return Err(UnknownDataError); - } - Ok(vec.release().remove(index as usize).into_revealed_state()) - } - _ => Err(UnknownDataError), - } - } -} - -impl TypedAssigns { - pub fn transmutate_seals(&self) -> TypedAssigns { - match self { - TypedAssigns::Declarative(a) => TypedAssigns::Declarative( - Confined::try_from_iter(a.iter().map(|a| a.transmutate_seals())) - .expect("same size"), - ), - TypedAssigns::Fungible(a) => TypedAssigns::Fungible( - Confined::try_from_iter(a.iter().map(|a| a.transmutate_seals())) - .expect("same size"), - ), - TypedAssigns::Structured(a) => TypedAssigns::Structured( - Confined::try_from_iter(a.iter().map(|a| a.transmutate_seals())) - .expect("same size"), - ), - TypedAssigns::Attachment(a) => TypedAssigns::Attachment( - Confined::try_from_iter(a.iter().map(|a| a.transmutate_seals())) - .expect("same size"), - ), - } - } -} - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, Debug, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde( - crate = "serde_crate", - transparent, - bound = "Seal: serde::Serialize + serde::de::DeserializeOwned" - ) -)] -pub struct Assignments(TinyOrdMap>) -where Seal: ExposedSeal; - -impl Default for Assignments { - fn default() -> Self { Self(empty!()) } -} - -impl Assignments { - pub fn transmutate_seals(&self) -> Assignments { - Assignments( - Confined::try_from_iter(self.iter().map(|(t, a)| (*t, a.transmutate_seals()))) - .expect("same size"), - ) - } -} - -impl IntoIterator for Assignments { - type Item = (AssignmentType, TypedAssigns); - type IntoIter = btree_map::IntoIter>; - - fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug, From)] -pub enum AssignmentsRef<'op> { - #[from] - Genesis(&'op Assignments), - - #[from] - Graph(&'op Assignments), -} - -impl AssignmentsRef<'_> { - pub fn len(&self) -> usize { - match self { - AssignmentsRef::Genesis(a) => a.len(), - AssignmentsRef::Graph(a) => a.len(), - } - } - - pub fn is_empty(&self) -> bool { self.len() == 0 } - - pub fn flat(&self) -> Assignments { - match *self { - AssignmentsRef::Genesis(a) => a.transmutate_seals(), - AssignmentsRef::Graph(a) => a.clone(), - } - } - - pub fn types(&self) -> BTreeSet { - match self { - AssignmentsRef::Genesis(a) => a.keys().copied().collect(), - AssignmentsRef::Graph(a) => a.keys().copied().collect(), - } - } - - pub fn has_type(&self, t: AssignmentType) -> bool { - match self { - AssignmentsRef::Genesis(a) => a.contains_key(&t), - AssignmentsRef::Graph(a) => a.contains_key(&t), - } - } - - pub fn get(&self, t: AssignmentType) -> Option> { - match self { - AssignmentsRef::Genesis(a) => a.get(&t).map(TypedAssigns::transmutate_seals), - AssignmentsRef::Graph(a) => a.get(&t).cloned(), - } - } -} diff --git a/src/operation/attachment.rs b/src/operation/attachment.rs deleted file mode 100644 index 43084a06..00000000 --- a/src/operation/attachment.rs +++ /dev/null @@ -1,210 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::fmt; -use std::fmt::{Display, Formatter}; -use std::str::FromStr; - -use amplify::{ByteArray, Bytes32}; -use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use bp::secp256k1::rand::{random, Rng, RngCore}; -use commit_verify::{CommitId, CommitmentId, Conceal, DigestExt, Sha256}; -use strict_encoding::{StrictEncode, StrictSerialize}; - -use super::{ConfidentialState, ExposedState}; -use crate::{ - impl_serde_baid64, ConcealedState, MediaType, RevealedState, StateType, LIB_NAME_RGB_COMMIT, -}; - -/// Unique data attachment identifier -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -pub struct AttachId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl DisplayBaid64 for AttachId { - const HRI: &'static str = "rgb:fs"; - const CHUNKING: bool = true; - const PREFIX: bool = true; - const EMBED_CHECKSUM: bool = false; - const MNEMONIC: bool = true; - fn to_baid64_payload(&self) -> [u8; 32] { self.to_byte_array() } -} -impl FromBaid64Str for AttachId {} -impl FromStr for AttachId { - type Err = Baid64ParseError; - fn from_str(s: &str) -> Result { Self::from_baid64_str(s) } -} -impl Display for AttachId { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) } -} - -impl_serde_baid64!(AttachId); - -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[display("{id}:{media_type}")] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct AttachState { - pub id: AttachId, - /// We do not enforce a MIME standard since non-standard types can be also - /// used - pub media_type: MediaType, -} -impl StrictSerialize for AttachState {} - -impl From for AttachState { - fn from(attach: RevealedAttach) -> Self { - AttachState { - id: attach.file.id, - media_type: attach.file.media_type, - } - } -} - -#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = ConcealedAttach)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct RevealedAttach { - pub file: AttachState, - pub salt: u64, -} - -impl RevealedAttach { - /// Constructs new state using the provided value using random blinding - /// factor. - pub fn new_random_salt(id: AttachId, media_type: impl Into) -> Self { - Self::with_salt(id, media_type, random()) - } - - /// Constructs new state using the provided value and random generator for - /// creating blinding factor. - pub fn with_rng( - id: AttachId, - media_type: impl Into, - rng: &mut R, - ) -> Self { - Self::with_salt(id, media_type, rng.next_u64()) - } - - /// Convenience constructor. - pub fn with_salt(id: AttachId, media_type: impl Into, salt: u64) -> Self { - Self { - file: AttachState { - id, - media_type: media_type.into(), - }, - salt, - } - } -} - -impl ExposedState for RevealedAttach { - type Confidential = ConcealedAttach; - fn state_type(&self) -> StateType { StateType::Attachment } - fn state_data(&self) -> RevealedState { RevealedState::Attachment(self.clone()) } -} - -impl Conceal for RevealedAttach { - type Concealed = ConcealedAttach; - - fn conceal(&self) -> Self::Concealed { self.commit_id() } -} - -/// Confidential version of an attachment information. -/// -/// See also revealed version [`RevealedAttach`]. -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct ConcealedAttach( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl ConfidentialState for ConcealedAttach { - fn state_type(&self) -> StateType { StateType::Attachment } - fn state_commitment(&self) -> ConcealedState { ConcealedState::Attachment(*self) } -} - -impl From for ConcealedAttach { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for ConcealedAttach { - const TAG: &'static str = "urn:lnp-bp:rgb:state-attach#2024-02-12"; -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn attach_id_display() { - const ID: &str = - "rgb:fs:bGxsbGxs-bGxsbGx-sbGxsbG-xsbGxsb-GxsbGxs-bGxsbGw#invite-potato-oval"; - let id = AttachId::from_byte_array([0x6c; 32]); - assert_eq!(ID, id.to_string()); - assert_eq!(ID, id.to_baid64_string()); - assert_eq!("invite-potato-oval", id.to_baid64_mnemonic()); - } - - #[test] - fn attach_id_from_str() { - let id = AttachId::from_byte_array([0x6c; 32]); - assert_eq!( - id, - AttachId::from_str( - "rgb:fs:bGxsbGxs-bGxsbGx-sbGxsbG-xsbGxsb-GxsbGxs-bGxsbGw#invite-potato-oval" - ) - .unwrap() - ); - assert_eq!( - id, - AttachId::from_str("rgb:fs:bGxsbGxs-bGxsbGx-sbGxsbG-xsbGxsb-GxsbGxs-bGxsbGw").unwrap() - ); - } -} diff --git a/src/operation/bundle.rs b/src/operation/bundle.rs deleted file mode 100644 index 6a69d4f1..00000000 --- a/src/operation/bundle.rs +++ /dev/null @@ -1,138 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::collections::{btree_map, BTreeMap}; - -use amplify::confinement::{Confined, U16 as U16MAX}; -use amplify::{Bytes32, Wrapper}; -use bp::seals::txout::CloseMethod; -use bp::Vout; -use commit_verify::{mpc, CommitEncode, CommitEngine, CommitId, CommitmentId, DigestExt, Sha256}; -use strict_encoding::{StrictDumb, StrictEncode}; - -use crate::{OpId, Transition, LIB_NAME_RGB_COMMIT}; - -pub type Vin = Vout; - -/// Unique state transition bundle identifier equivalent to the bundle -/// commitment hash -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Display, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct BundleId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl From for BundleId { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for BundleId { - const TAG: &'static str = "urn:lnp-bp:rgb:bundle#2024-02-03"; -} - -impl From for mpc::Message { - fn from(id: BundleId) -> Self { mpc::Message::from_inner(id.into_inner()) } -} - -impl From for BundleId { - fn from(id: mpc::Message) -> Self { BundleId(id.into_inner()) } -} - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, Hash, Debug, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct InputMap(Confined, 1, U16MAX>); - -impl StrictDumb for InputMap { - fn strict_dumb() -> Self { Self(Confined::with_key_value(strict_dumb!(), strict_dumb!())) } -} - -impl InputMap { - pub fn with(input: Vin, id: OpId) -> Self { InputMap(Confined::with((input, id))) } -} - -impl IntoIterator for InputMap { - type Item = (Vin, OpId); - type IntoIter = btree_map::IntoIter; - - fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } -} - -impl<'a> IntoIterator for &'a InputMap { - type Item = (&'a Vin, &'a OpId); - type IntoIter = btree_map::Iter<'a, Vin, OpId>; - - fn into_iter(self) -> Self::IntoIter { self.0.iter() } -} - -#[derive(Clone, PartialEq, Eq, Debug, From)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct TransitionBundle { - pub close_method: CloseMethod, - pub input_map: InputMap, - pub known_transitions: Confined, 1, U16MAX>, -} - -impl CommitEncode for TransitionBundle { - type CommitmentId = BundleId; - - fn commit_encode(&self, e: &mut CommitEngine) { - e.commit_to_serialized(&self.close_method); - e.commit_to_serialized(&self.input_map); - } -} - -impl StrictDumb for TransitionBundle { - fn strict_dumb() -> Self { - Self { - close_method: strict_dumb!(), - input_map: strict_dumb!(), - known_transitions: Confined::with_key_value(strict_dumb!(), strict_dumb!()), - } - } -} - -impl TransitionBundle { - pub fn bundle_id(&self) -> BundleId { self.commit_id() } -} diff --git a/src/operation/commit.rs b/src/operation/commit.rs deleted file mode 100644 index 93796a4d..00000000 --- a/src/operation/commit.rs +++ /dev/null @@ -1,448 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::collections::BTreeSet; -use std::fmt::{Display, Formatter}; -use std::str::FromStr; -use std::{fmt, vec}; - -use amplify::confinement::{Confined, MediumOrdMap, U16 as U16MAX}; -use amplify::hex::{FromHex, ToHex}; -use amplify::num::u256; -use amplify::{hex, ByteArray, Bytes32, FromSliceError, Wrapper}; -use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use commit_verify::{ - mpc, CommitEncode, CommitEngine, CommitId, CommitmentId, Conceal, DigestExt, MerkleHash, - MerkleLeaves, ReservedBytes, Sha256, StrictHash, -}; -use strict_encoding::StrictDumb; - -use crate::{ - impl_serde_baid64, Assign, AssignmentType, Assignments, BundleId, ConcealedAttach, - ConcealedData, ConcealedState, ConfidentialState, DataState, ExposedSeal, ExposedState, - Extension, ExtensionType, Ffv, Genesis, GlobalState, GlobalStateType, Operation, - PedersenCommitment, Redeemed, SchemaId, SecretSeal, Transition, TransitionBundle, - TransitionType, TypedAssigns, XChain, LIB_NAME_RGB_COMMIT, -}; - -/// Unique contract identifier equivalent to the contract genesis commitment -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -pub struct ContractId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl PartialEq for ContractId { - fn eq(&self, other: &OpId) -> bool { self.to_byte_array() == other.to_byte_array() } -} -impl PartialEq for OpId { - fn eq(&self, other: &ContractId) -> bool { self.to_byte_array() == other.to_byte_array() } -} - -impl ContractId { - pub fn copy_from_slice(slice: impl AsRef<[u8]>) -> Result { - Bytes32::copy_from_slice(slice).map(Self) - } -} - -impl DisplayBaid64 for ContractId { - const HRI: &'static str = "rgb"; - const CHUNKING: bool = true; - const PREFIX: bool = true; - const EMBED_CHECKSUM: bool = false; - const MNEMONIC: bool = false; - fn to_baid64_payload(&self) -> [u8; 32] { self.to_byte_array() } -} -impl FromBaid64Str for ContractId {} -impl FromStr for ContractId { - type Err = Baid64ParseError; - fn from_str(s: &str) -> Result { Self::from_baid64_str(s) } -} -impl Display for ContractId { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) } -} - -impl From for ContractId { - fn from(id: mpc::ProtocolId) -> Self { ContractId(id.into_inner()) } -} - -impl From for mpc::ProtocolId { - fn from(id: ContractId) -> Self { mpc::ProtocolId::from_inner(id.into_inner()) } -} - -impl_serde_baid64!(ContractId); - -/// Unique operation (genesis, extensions & state transition) identifier -/// equivalent to the commitment hash -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[display(Self::to_hex)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct OpId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl From for OpId { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for OpId { - const TAG: &'static str = "urn:lnp-bp:rgb:operation#2024-02-03"; -} - -impl FromStr for OpId { - type Err = hex::Error; - fn from_str(s: &str) -> Result { Self::from_hex(s) } -} - -impl OpId { - pub fn copy_from_slice(slice: impl AsRef<[u8]>) -> Result { - Bytes32::copy_from_slice(slice).map(Self) - } -} - -/// Hash committing to all data which are disclosed by a contract or some part -/// of it (operation, bundle, consignment, disclosure). -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[display(Self::to_hex)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct DiscloseHash( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl From for DiscloseHash { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for DiscloseHash { - const TAG: &'static str = "urn:lnp-bp:rgb:disclose#2024-02-16"; -} - -impl FromStr for DiscloseHash { - type Err = hex::Error; - fn from_str(s: &str) -> Result { Self::from_hex(s) } -} - -impl DiscloseHash { - pub fn copy_from_slice(slice: impl AsRef<[u8]>) -> Result { - Bytes32::copy_from_slice(slice).map(Self) - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -pub struct AssignmentIndex { - pub ty: AssignmentType, - pub pos: u16, -} - -impl AssignmentIndex { - pub fn new(ty: AssignmentType, pos: u16) -> Self { AssignmentIndex { ty, pos } } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = DiscloseHash)] -pub struct OpDisclose { - pub id: OpId, - pub seals: MediumOrdMap>, - pub fungible: MediumOrdMap, - pub data: MediumOrdMap, - pub attach: MediumOrdMap, -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = DiscloseHash)] -pub struct BundleDisclosure { - pub id: BundleId, - pub known_transitions: Confined, 1, U16MAX>, -} - -impl StrictDumb for BundleDisclosure { - fn strict_dumb() -> Self { - Self { - id: strict_dumb!(), - known_transitions: Confined::with(strict_dumb!()), - } - } -} - -impl TransitionBundle { - /// Provides summary about parts of the bundle which are revealed. - pub fn disclose(&self) -> BundleDisclosure { - BundleDisclosure { - id: self.bundle_id(), - known_transitions: Confined::from_iter_checked( - self.known_transitions.values().map(|t| t.disclose_hash()), - ), - } - } - - /// Returns commitment to the bundle plus revealed data within it. - pub fn disclose_hash(&self) -> DiscloseHash { self.disclose().commit_id() } -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -pub struct BaseCommitment { - pub flags: ReservedBytes<1, 0>, - pub schema_id: SchemaId, - pub timestamp: i64, - pub issuer: StrictHash, - pub testnet: bool, - pub alt_layers1: StrictHash, - pub asset_tags: StrictHash, -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = custom, dumb = Self::Transition(strict_dumb!(), strict_dumb!()))] -pub enum TypeCommitment { - #[strict_type(tag = 0)] - Genesis(BaseCommitment), - - #[strict_type(tag = 1)] - Transition(ContractId, TransitionType), - - #[strict_type(tag = 2)] - Extension(ContractId, ExtensionType), -} - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = OpId)] -pub struct OpCommitment { - pub ffv: Ffv, - pub nonce: u64, - pub op_type: TypeCommitment, - pub metadata: StrictHash, - pub globals: MerkleHash, - pub inputs: MerkleHash, - pub assignments: MerkleHash, - pub redeemed: StrictHash, - pub valencies: StrictHash, - pub witness: MerkleHash, - pub validator: StrictHash, -} - -impl Genesis { - pub fn commit(&self) -> OpCommitment { - let base = BaseCommitment { - flags: self.flags, - schema_id: self.schema_id, - timestamp: self.timestamp, - testnet: self.testnet, - alt_layers1: self.alt_layers1.commit_id(), - issuer: self.issuer.commit_id(), - asset_tags: self.asset_tags.commit_id(), - }; - OpCommitment { - ffv: self.ffv, - nonce: u64::MAX, - op_type: TypeCommitment::Genesis(base), - metadata: self.metadata.commit_id(), - globals: MerkleHash::merklize(&self.globals), - inputs: MerkleHash::void(0, u256::ZERO), - assignments: MerkleHash::merklize(&self.assignments), - redeemed: Redeemed::default().commit_id(), - valencies: self.valencies.commit_id(), - witness: MerkleHash::void(0, u256::ZERO), - validator: self.validator.commit_id(), - } - } - - pub fn disclose_hash(&self) -> DiscloseHash { self.disclose().commit_id() } -} - -impl Transition { - pub fn commit(&self) -> OpCommitment { - OpCommitment { - ffv: self.ffv, - nonce: self.nonce, - op_type: TypeCommitment::Transition(self.contract_id, self.transition_type), - metadata: self.metadata.commit_id(), - globals: MerkleHash::merklize(&self.globals), - inputs: MerkleHash::merklize(&self.inputs), - assignments: MerkleHash::merklize(&self.assignments), - redeemed: Redeemed::default().commit_id(), - valencies: self.valencies.commit_id(), - witness: MerkleHash::void(0, u256::ZERO), - validator: self.validator.commit_id(), - } - } -} - -impl Extension { - pub fn commit(&self) -> OpCommitment { - OpCommitment { - ffv: self.ffv, - nonce: self.nonce, - op_type: TypeCommitment::Extension(self.contract_id, self.extension_type), - metadata: self.metadata.commit_id(), - globals: MerkleHash::merklize(&self.globals), - inputs: MerkleHash::void(0, u256::ZERO), - assignments: MerkleHash::merklize(&self.assignments), - redeemed: self.redeemed.commit_id(), - valencies: self.valencies.commit_id(), - witness: MerkleHash::void(0, u256::ZERO), - validator: self.validator.commit_id(), - } - } -} - -impl ConcealedState { - fn commit_encode(&self, e: &mut CommitEngine) { - match self { - ConcealedState::Void => {} - ConcealedState::Fungible(val) => e.commit_to_serialized(&val.commitment), - ConcealedState::Structured(dat) => e.commit_to_serialized(dat), - ConcealedState::Attachment(att) => e.commit_to_serialized(att), - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct AssignmentCommitment { - pub ty: AssignmentType, - pub state: ConcealedState, - pub seal: XChain, - pub lock: ReservedBytes<2, 0>, -} - -impl CommitEncode for AssignmentCommitment { - type CommitmentId = MerkleHash; - - fn commit_encode(&self, e: &mut CommitEngine) { - e.commit_to_serialized(&self.ty); - self.state.commit_encode(e); - e.commit_to_serialized(&self.seal); - e.commit_to_serialized(&self.lock); - e.set_finished(); - } -} - -impl Assign { - pub fn commitment(&self, ty: AssignmentType) -> AssignmentCommitment { - let Self::Confidential { seal, state, lock } = self.conceal() else { - unreachable!(); - }; - AssignmentCommitment { - ty, - state: state.state_commitment(), - seal, - lock, - } - } -} - -impl MerkleLeaves for Assignments { - type Leaf = AssignmentCommitment; - type LeafIter<'tmp> - = vec::IntoIter - where Seal: 'tmp; - - fn merkle_leaves(&self) -> Self::LeafIter<'_> { - self.iter() - .flat_map(|(ty, a)| { - match a { - TypedAssigns::Declarative(list) => { - list.iter().map(|a| a.commitment(*ty)).collect::>() - } - TypedAssigns::Fungible(list) => { - list.iter().map(|a| a.commitment(*ty)).collect() - } - TypedAssigns::Structured(list) => { - list.iter().map(|a| a.commitment(*ty)).collect() - } - TypedAssigns::Attachment(list) => { - list.iter().map(|a| a.commitment(*ty)).collect() - } - } - .into_iter() - }) - .collect::>() - .into_iter() - } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug)] -pub struct GlobalCommitment { - pub ty: GlobalStateType, - pub state: DataState, -} - -impl CommitEncode for GlobalCommitment { - type CommitmentId = MerkleHash; - - fn commit_encode(&self, e: &mut CommitEngine) { - e.commit_to_serialized(&self.ty); - e.commit_to_serialized(&self.state); - e.set_finished(); - } -} - -impl MerkleLeaves for GlobalState { - type Leaf = GlobalCommitment; - type LeafIter<'tmp> = vec::IntoIter; - - fn merkle_leaves(&self) -> Self::LeafIter<'_> { - self.iter() - .flat_map(|(ty, list)| { - list.iter().map(|val| GlobalCommitment { - ty: *ty, - state: val.clone(), - }) - }) - .collect::>() - .into_iter() - } -} diff --git a/src/operation/data.rs b/src/operation/data.rs deleted file mode 100644 index 1ad420b0..00000000 --- a/src/operation/data.rs +++ /dev/null @@ -1,192 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use core::fmt::{self, Debug, Formatter}; -use std::cmp::Ordering; - -use amplify::confinement::SmallBlob; -use amplify::hex::ToHex; -use amplify::{Bytes32, Wrapper}; -use bp::secp256k1::rand::{random, Rng, RngCore}; -use commit_verify::{CommitId, CommitmentId, Conceal, DigestExt, Sha256}; -use strict_encoding::{StrictSerialize, StrictType}; - -use super::{ConfidentialState, ExposedState}; -use crate::{ConcealedState, RevealedState, StateType, LIB_NAME_RGB_COMMIT}; - -/// Struct using for storing Void (i.e. absent) state -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Display, Default)] -#[display("void")] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct VoidState(()); - -impl ConfidentialState for VoidState { - fn state_type(&self) -> StateType { StateType::Void } - fn state_commitment(&self) -> ConcealedState { ConcealedState::Void } -} - -impl ExposedState for VoidState { - type Confidential = VoidState; - fn state_type(&self) -> StateType { StateType::Void } - fn state_data(&self) -> RevealedState { RevealedState::Void } -} - -impl Conceal for VoidState { - type Concealed = VoidState; - fn conceal(&self) -> Self::Concealed { *self } -} - -#[derive(Wrapper, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash, From, Display, Default)] -#[display(LowerHex)] -#[wrapper(Deref, AsSlice, BorrowSlice, Hex)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -pub struct DataState(SmallBlob); -impl StrictSerialize for DataState {} - -impl From for DataState { - fn from(data: RevealedData) -> Self { data.value } -} - -#[cfg(feature = "serde")] -mod _serde { - use amplify::hex::FromHex; - use serde_crate::de::Error; - use serde_crate::{Deserialize, Deserializer, Serialize, Serializer}; - - use super::*; - - impl Serialize for DataState { - fn serialize(&self, serializer: S) -> Result - where S: Serializer { - serializer.serialize_str(&self.to_string()) - } - } - - impl<'de> Deserialize<'de> for DataState { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> { - let s = String::deserialize(deserializer)?; - Self::from_hex(&s).map_err(D::Error::custom) - } - } -} - -#[derive(Clone, Eq, PartialEq, Hash)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = ConcealedData)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct RevealedData { - pub value: DataState, - pub salt: u128, -} - -impl RevealedData { - /// Constructs new state using the provided value using random blinding - /// factor. - pub fn new_random_salt(value: impl Into) -> Self { Self::with_salt(value, random()) } - - /// Constructs new state using the provided value and random generator for - /// creating blinding factor. - pub fn with_rng(value: impl Into, rng: &mut R) -> Self { - Self::with_salt(value, rng.gen()) - } - - /// Convenience constructor. - pub fn with_salt(value: impl Into, salt: u128) -> Self { - Self { - value: value.into(), - salt, - } - } -} - -impl ExposedState for RevealedData { - type Confidential = ConcealedData; - fn state_type(&self) -> StateType { StateType::Structured } - fn state_data(&self) -> RevealedState { RevealedState::Structured(self.clone()) } -} - -impl Conceal for RevealedData { - type Concealed = ConcealedData; - - fn conceal(&self) -> Self::Concealed { self.commit_id() } -} - -impl PartialOrd for RevealedData { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl Ord for RevealedData { - fn cmp(&self, other: &Self) -> Ordering { - match self.value.cmp(&other.value) { - Ordering::Equal => self.salt.cmp(&other.salt), - other => other, - } - } -} - -impl Debug for RevealedData { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let val = String::from_utf8(self.value.to_vec()).unwrap_or_else(|_| self.value.to_hex()); - - f.debug_struct("RevealedData") - .field("value", &val) - .field("salt", &self.salt) - .finish() - } -} - -/// Confidential version of an structured state data. -/// -/// See also revealed version [`RevealedData`]. -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, rename = "ConcealedData")] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct ConcealedData( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl ConfidentialState for ConcealedData { - fn state_type(&self) -> StateType { StateType::Structured } - fn state_commitment(&self) -> ConcealedState { ConcealedState::Structured(*self) } -} - -impl From for ConcealedData { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for ConcealedData { - const TAG: &'static str = "urn:lnp-bp:rgb:state-data#2024-02-12"; -} diff --git a/src/operation/fungible.rs b/src/operation/fungible.rs deleted file mode 100644 index 1af77801..00000000 --- a/src/operation/fungible.rs +++ /dev/null @@ -1,636 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! This mod represents **atomic rational values** (or, simply just **value**), -//! it a value representing a portion of something whole with a certain fixed -//! level of precision (atomicity). Such values are commonly used to represent -//! some coins of fungible tokens, where each coin or token consists of an -//! integer number of atomic subdivisions of the total supply (like satoshis in -//! bitcoin represent just a portion, i.e. fixed-precision rational number, of -//! the total possible bitcoin supply). Such numbers demonstrate constant -//! properties regarding their total sum and, thus, can be made confidential -//! using elliptic curve homomorphic cryptography such as Pedesen commitments. - -use core::cmp::Ordering; -use core::fmt::Debug; -use core::num::ParseIntError; -use core::ops::Deref; -use core::str::FromStr; -use std::hash::Hash; -use std::io; - -use amplify::confinement::U8; -use amplify::hex::ToHex; -// We do not import particular modules to keep aware with namespace prefixes -// that we do not use the standard secp256k1zkp library -use amplify::{hex, Array, Bytes32, Wrapper}; -use bp::secp256k1::rand::thread_rng; -use chrono::{DateTime, Utc}; -use commit_verify::{ - CommitVerify, CommitmentProtocol, Conceal, DigestExt, Sha256, UntaggedProtocol, -}; -use secp256k1_zkp::rand::{Rng, RngCore}; -use secp256k1_zkp::SECP256K1; -use strict_encoding::{ - DecodeError, ReadTuple, StrictDecode, StrictDumb, StrictEncode, TypedRead, TypedWrite, - WriteTuple, -}; - -use super::{ConfidentialState, ExposedState}; -use crate::{ - schema, AssignmentType, ConcealedState, RevealedState, StateType, LIB_NAME_RGB_COMMIT, -}; - -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct AssetTag( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl AssetTag { - pub fn new_random(contract_domain: impl AsRef, assignment_type: AssignmentType) -> Self { - AssetTag::new_deterministic( - contract_domain, - assignment_type, - Utc::now(), - thread_rng().next_u64(), - ) - } - - pub fn new_deterministic( - contract_domain: impl AsRef, - assignment_type: AssignmentType, - timestamp: DateTime, - salt: u64, - ) -> Self { - let timestamp = timestamp.timestamp(); - let mut hasher = Sha256::default(); - hasher.input_with_len::(contract_domain.as_ref().as_bytes()); - hasher.input_raw(&assignment_type.to_le_bytes()); - hasher.input_raw(×tamp.to_le_bytes()); - hasher.input_raw(&salt.to_le_bytes()); - AssetTag::from(hasher.finish()) - } -} - -/// An atom of an additive state, which thus can be monomorphically encrypted. -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, From)] -#[display(inner)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", untagged) -)] -pub enum FungibleState { - /// 64-bit value. - #[from] - #[strict_type(tag = 8)] // Matches strict types U64 primitive value - Bits64(u64), - // When/if adding more variants do not forget to re-write FromStr impl -} - -impl Default for FungibleState { - fn default() -> Self { FungibleState::Bits64(0) } -} - -impl From for FungibleState { - fn from(revealed: RevealedValue) -> Self { revealed.value } -} - -impl FromStr for FungibleState { - type Err = ParseIntError; - fn from_str(s: &str) -> Result { s.parse().map(FungibleState::Bits64) } -} - -impl From for u64 { - fn from(value: FungibleState) -> Self { - match value { - FungibleState::Bits64(val) => val, - } - } -} - -impl FungibleState { - pub fn fungible_type(&self) -> schema::FungibleType { - match self { - FungibleState::Bits64(_) => schema::FungibleType::Unsigned64Bit, - } - } - - pub fn as_u64(&self) -> u64 { (*self).into() } -} - -/// value provided for a blinding factor overflows prime field order for -/// Secp256k1 curve. -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error, From)] -#[display(doc_comments)] -#[from(secp256k1_zkp::UpstreamError)] -pub struct InvalidFieldElement; - -/// Errors parsing string representation of a blinding factor. -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum BlindingParseError { - /// invalid blinding factor hex representation - {0} - #[from] - Hex(hex::Error), - - /// blinding factor value is invalid and does not belong to the Secp256k1 - /// curve field. - #[from(InvalidFieldElement)] - InvalidFieldElement, -} - -/// Blinding factor used in creating Pedersen commitment to an [`AtomicValue`]. -/// -/// Knowledge of the blinding factor is important to reproduce the commitment -/// process if the original value is kept. -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -#[display(Self::to_hex)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", try_from = "secp256k1_zkp::SecretKey") -)] -pub struct BlindingFactor(Bytes32); - -impl BlindingFactor { - pub const EMPTY: Self = BlindingFactor(Bytes32::from_array([0x7E; 32])); -} - -impl Deref for BlindingFactor { - type Target = [u8; 32]; - fn deref(&self) -> &Self::Target { self.0.as_inner() } -} - -impl ToHex for BlindingFactor { - fn to_hex(&self) -> String { self.0.to_hex() } -} - -impl FromStr for BlindingFactor { - type Err = BlindingParseError; - fn from_str(s: &str) -> Result { - let bytes = Bytes32::from_str(s)?; - Self::try_from(bytes).map_err(BlindingParseError::from) - } -} - -impl From for BlindingFactor { - fn from(key: secp256k1_zkp::SecretKey) -> Self { Self(Bytes32::from_inner(*key.as_ref())) } -} - -impl From for secp256k1_zkp::SecretKey { - fn from(bf: BlindingFactor) -> Self { bf.to_secret_key() } -} - -impl BlindingFactor { - /// Creates a random blinding factor. - #[inline] - pub fn random() -> Self { Self::random_custom(&mut thread_rng()) } - - /// Generates a random blinding factor using custom random number generator. - #[inline] - pub fn random_custom(rng: &mut R) -> Self { - secp256k1_zkp::SecretKey::new(rng).into() - } - - /// Generates new blinding factor which balances a given set of negatives - /// and positives into zero. - /// - /// # Errors - /// - /// * if negatives are empty set; - /// * if any subset of the negatives or positives are inverses of other negatives or positives, - /// * if the balancing factor is zero (sum of negatives already equal to the sum of positives). - pub fn zero_balanced( - negative: impl IntoIterator, - positive: impl IntoIterator, - ) -> Result { - let mut blinding_neg_sum = secp256k1_zkp::Scalar::ZERO; - let mut blinding_pos_sum = secp256k1_zkp::Scalar::ZERO; - for neg in negative { - blinding_neg_sum = neg.to_secret_key().add_tweak(&blinding_neg_sum)?.into(); - } - let blinding_neg_sum = - secp256k1_zkp::SecretKey::from_slice(&blinding_neg_sum.to_be_bytes())?.negate(); - for pos in positive { - blinding_pos_sum = pos.to_secret_key().add_tweak(&blinding_pos_sum)?.into(); - } - let blinding_correction = blinding_neg_sum.add_tweak(&blinding_pos_sum)?.negate(); - Ok(blinding_correction.into()) - } - - fn to_secret_key(self) -> secp256k1_zkp::SecretKey { - secp256k1_zkp::SecretKey::from_slice(self.0.as_slice()) - .expect("blinding factor is an invalid secret key") - } -} - -impl TryFrom<[u8; 32]> for BlindingFactor { - type Error = InvalidFieldElement; - - fn try_from(array: [u8; 32]) -> Result { - secp256k1_zkp::SecretKey::from_slice(&array) - .map_err(|_| InvalidFieldElement) - .map(Self::from) - } -} - -impl TryFrom for BlindingFactor { - type Error = InvalidFieldElement; - - fn try_from(bytes: Bytes32) -> Result { - Self::try_from(bytes.to_byte_array()) - } -} - -/// State item for a homomorphically-encryptable state. -/// -/// Consists of the 64-bit value and -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, rename = "RevealedFungible")] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct RevealedValue { - /// Original value in smallest indivisible units - pub value: FungibleState, - - /// Blinding factor used in Pedersen commitment - pub blinding: BlindingFactor, - - /// Asset-specific tag preventing mixing assets of different type. - pub tag: AssetTag, -} - -impl RevealedValue { - /// Constructs new state using the provided value using random blinding - /// factor. - pub fn new_random_blinding(value: impl Into, tag: AssetTag) -> Self { - Self::with_blinding(value, BlindingFactor::random(), tag) - } - - /// Constructs new state using the provided value and random generator for - /// creating blinding factor. - pub fn with_rng( - value: impl Into, - rng: &mut R, - tag: AssetTag, - ) -> Self { - Self::with_blinding(value, BlindingFactor::random_custom(rng), tag) - } - - /// Convenience constructor. - pub fn with_blinding( - value: impl Into, - blinding: BlindingFactor, - tag: AssetTag, - ) -> Self { - Self { - value: value.into(), - blinding, - tag, - } - } -} - -impl ExposedState for RevealedValue { - type Confidential = ConcealedValue; - fn state_type(&self) -> StateType { StateType::Fungible } - fn state_data(&self) -> RevealedState { RevealedState::Fungible(*self) } -} - -impl Conceal for RevealedValue { - type Concealed = ConcealedValue; - - fn conceal(&self) -> Self::Concealed { ConcealedValue::commit(self) } -} - -impl PartialOrd for RevealedValue { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl Ord for RevealedValue { - fn cmp(&self, other: &Self) -> Ordering { - match self.value.cmp(&other.value) { - Ordering::Equal => self.blinding.0.cmp(&other.blinding.0), - other => other, - } - } -} - -/// Opaque type holding pedersen commitment for an [`FungibleState`]. -#[derive(Wrapper, Copy, Clone, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, FromStr, Display, LowerHex)] -#[derive(StrictType)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct PedersenCommitment(secp256k1_zkp::PedersenCommitment); - -impl StrictDumb for PedersenCommitment { - fn strict_dumb() -> Self { - secp256k1_zkp::PedersenCommitment::from_slice(&[0x08; 33]) - .expect("hardcoded pedersen commitment value") - .into() - } -} - -impl StrictEncode for PedersenCommitment { - fn strict_encode(&self, writer: W) -> io::Result { - writer.write_tuple::(|w| Ok(w.write_field(&self.0.serialize())?.complete())) - } -} - -impl StrictDecode for PedersenCommitment { - fn strict_decode(reader: &mut impl TypedRead) -> Result { - reader.read_tuple(|r| { - let commitment = r.read_field::<[u8; 33]>()?; - secp256k1_zkp::PedersenCommitment::from_slice(&commitment) - .map_err(|_| { - DecodeError::DataIntegrityError(s!("invalid pedersen commitment data")) - }) - .map(PedersenCommitment::from_inner) - }) - } -} - -impl CommitVerify for PedersenCommitment { - fn commit(revealed: &RevealedValue) -> Self { - use secp256k1_zkp::{Generator, Tag, Tweak}; - - let blinding = Tweak::from_inner(revealed.blinding.0.into_inner()) - .expect("type guarantees of BlindingFactor are broken"); - let FungibleState::Bits64(value) = revealed.value; - - let tag = Tag::from(revealed.tag.to_byte_array()); - let generator = Generator::new_unblinded(SECP256K1, tag); - - secp256k1_zkp::PedersenCommitment::new(SECP256K1, value, blinding, generator).into() - } -} - -/// A dumb placeholder for a future bulletproofs. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct NoiseDumb(Array); - -impl Default for NoiseDumb { - fn default() -> Self { - let mut dumb = [0u8; 512]; - thread_rng().fill(&mut dumb); - NoiseDumb(dumb.into()) - } -} - -/// Range proof value. -/// -/// Range proofs must be used alongside [`PedersenCommitment`]s to ensure that -/// the value do not overflow on arithmetic operations with the commitments. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[derive(StrictType)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", untagged) -)] -pub enum RangeProof { - /// Value used when bulletproofs library is not available. - /// - /// Always fails validation if no source value is given. - #[strict_type(tag = 0xFF)] - Placeholder(NoiseDumb), -} - -impl Default for RangeProof { - fn default() -> Self { RangeProof::Placeholder(default!()) } -} - -impl StrictEncode for RangeProof { - fn strict_encode(&self, writer: W) -> io::Result { - eprintln!("bulletproof dummies must never be stored"); - Ok(writer) - } -} - -impl StrictDecode for RangeProof { - fn strict_decode(_: &mut impl TypedRead) -> Result { - panic!("bulletproofs dummies must never be read") - } -} - -pub struct PedersenProtocol; - -impl CommitmentProtocol for PedersenProtocol {} - -/// Confidential version of the additive state. -/// -/// See also revealed version [`RevealedValue`]. -#[derive(Clone, Copy, Eq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, rename = "ConcealedFungible")] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ConcealedValue { - /// Pedersen commitment to the original [`FungibleState`]. - pub commitment: PedersenCommitment, - /// Range proof for the [`FungibleState`] not exceeding type boundaries. - pub range_proof: RangeProof, -} - -impl PartialEq for ConcealedValue { - fn eq(&self, other: &Self) -> bool { self.commitment == other.commitment } -} - -impl ConfidentialState for ConcealedValue { - fn state_type(&self) -> StateType { StateType::Fungible } - fn state_commitment(&self) -> ConcealedState { ConcealedState::Fungible(*self) } -} - -impl CommitVerify for ConcealedValue { - fn commit(revealed: &RevealedValue) -> Self { - let commitment = PedersenCommitment::commit(revealed); - // TODO: Do actual conceal upon integration of bulletproofs library - let range_proof = RangeProof::default(); - ConcealedValue { - commitment, - range_proof, - } - } -} - -/// Errors verifying range proofs. -#[derive(Copy, Clone, PartialEq, Eq, Debug, Display, Error)] -#[display(doc_comments)] -pub enum RangeProofError { - /// invalid blinding factor {0}. - InvalidBlinding(BlindingFactor), - - /// bulletproofs verification is not implemented in RGB Core v0.10. Please - /// update your software and try again, or ask your software producer to use - /// latest RGB release. - BulletproofsAbsent, -} - -impl ConcealedValue { - /// Verifies validity of the range proof. - pub fn verify_range_proof(&self) -> Result { - // We always fail here - Err(RangeProofError::BulletproofsAbsent) - } -} - -#[cfg(test)] -mod test { - use amplify::ByteArray; - - use super::*; - - #[test] - fn pedersen_blinding_mismatch() { - let mut r = thread_rng(); - let tag = AssetTag::from_byte_array([1u8; 32]); - - let a = PedersenCommitment::commit(&RevealedValue::with_rng(15, &mut r, tag)).into_inner(); - let b = PedersenCommitment::commit(&RevealedValue::with_rng(7, &mut r, tag)).into_inner(); - - let c = PedersenCommitment::commit(&RevealedValue::with_rng(13, &mut r, tag)).into_inner(); - let d = PedersenCommitment::commit(&RevealedValue::with_rng(9, &mut r, tag)).into_inner(); - - assert!(!secp256k1_zkp::verify_commitments_sum_to_equal(SECP256K1, &[a, b], &[c, d])) - } - - #[test] - fn pedersen_blinding_same() { - let blinding = - BlindingFactor::from(secp256k1_zkp::SecretKey::from_slice(&[1u8; 32]).unwrap()); - let tag = AssetTag::from_byte_array([1u8; 32]); - - let a = PedersenCommitment::commit(&RevealedValue::with_blinding(15, blinding, tag)) - .into_inner(); - let b = PedersenCommitment::commit(&RevealedValue::with_blinding(7, blinding, tag)) - .into_inner(); - - let c = PedersenCommitment::commit(&RevealedValue::with_blinding(13, blinding, tag)) - .into_inner(); - let d = PedersenCommitment::commit(&RevealedValue::with_blinding(9, blinding, tag)) - .into_inner(); - - assert!(secp256k1_zkp::verify_commitments_sum_to_equal(SECP256K1, &[a, b], &[c, d])) - } - - #[test] - fn pedersen_blinding_same_tag_differ() { - let blinding = - BlindingFactor::from(secp256k1_zkp::SecretKey::from_slice(&[1u8; 32]).unwrap()); - let tag = AssetTag::from_byte_array([1u8; 32]); - let tag2 = AssetTag::from_byte_array([2u8; 32]); - - let a = PedersenCommitment::commit(&RevealedValue::with_blinding(15, blinding, tag2)) - .into_inner(); - let b = PedersenCommitment::commit(&RevealedValue::with_blinding(7, blinding, tag)) - .into_inner(); - - let c = PedersenCommitment::commit(&RevealedValue::with_blinding(13, blinding, tag2)) - .into_inner(); - let d = PedersenCommitment::commit(&RevealedValue::with_blinding(9, blinding, tag)) - .into_inner(); - - assert!(!secp256k1_zkp::verify_commitments_sum_to_equal(SECP256K1, &[a, b], &[c, d])) - } - - #[test] - fn pedersen_two_tags() { - let blinding = - BlindingFactor::from(secp256k1_zkp::SecretKey::from_slice(&[1u8; 32]).unwrap()); - let tag = AssetTag::from_byte_array([1u8; 32]); - let tag2 = AssetTag::from_byte_array([2u8; 32]); - - let a = PedersenCommitment::commit(&RevealedValue::with_blinding(15, blinding, tag2)) - .into_inner(); - let b = PedersenCommitment::commit(&RevealedValue::with_blinding(7, blinding, tag2)) - .into_inner(); - let c = PedersenCommitment::commit(&RevealedValue::with_blinding(2, blinding, tag)) - .into_inner(); - let d = PedersenCommitment::commit(&RevealedValue::with_blinding(4, blinding, tag)) - .into_inner(); - - let e = PedersenCommitment::commit(&RevealedValue::with_blinding(13, blinding, tag2)) - .into_inner(); - let f = PedersenCommitment::commit(&RevealedValue::with_blinding(9, blinding, tag2)) - .into_inner(); - let g = PedersenCommitment::commit(&RevealedValue::with_blinding(1, blinding, tag)) - .into_inner(); - let h = PedersenCommitment::commit(&RevealedValue::with_blinding(5, blinding, tag)) - .into_inner(); - - assert!(secp256k1_zkp::verify_commitments_sum_to_equal(SECP256K1, &[a, b, c, d], &[ - e, f, g, h - ])) - } - - #[test] - fn pedersen_blinding_balance() { - let blinding1 = BlindingFactor::random(); - let blinding2 = BlindingFactor::random(); - let blinding3 = BlindingFactor::random(); - let blinding4 = BlindingFactor::zero_balanced([blinding1, blinding2], [blinding3]).unwrap(); - let tag = AssetTag::from_byte_array([1u8; 32]); - - let a = PedersenCommitment::commit(&RevealedValue::with_blinding(15, blinding1, tag)) - .into_inner(); - let b = PedersenCommitment::commit(&RevealedValue::with_blinding(7, blinding2, tag)) - .into_inner(); - - let c = PedersenCommitment::commit(&RevealedValue::with_blinding(13, blinding3, tag)) - .into_inner(); - let d = PedersenCommitment::commit(&RevealedValue::with_blinding(9, blinding4, tag)) - .into_inner(); - - assert!(secp256k1_zkp::verify_commitments_sum_to_equal(SECP256K1, &[a, b], &[c, d])) - } -} diff --git a/src/operation/global.rs b/src/operation/global.rs deleted file mode 100644 index 25dadc12..00000000 --- a/src/operation/global.rs +++ /dev/null @@ -1,102 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::collections::btree_map; -use std::vec; - -use amplify::confinement::{Confined, TinyOrdMap, U16}; -use amplify::{confinement, Wrapper}; -use strict_encoding::StrictDumb; - -use crate::{schema, DataState, LIB_NAME_RGB_COMMIT}; - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, Hash, Debug, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct GlobalValues(Confined, 1, U16>); - -impl StrictDumb for GlobalValues { - fn strict_dumb() -> Self { Self(Confined::with(DataState::strict_dumb())) } -} - -impl GlobalValues { - pub fn with(state: DataState) -> Self { GlobalValues(Confined::with(state)) } -} - -impl IntoIterator for GlobalValues { - type Item = DataState; - type IntoIter = vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } -} - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, Hash, Default, Debug, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct GlobalState(TinyOrdMap); - -impl GlobalState { - pub fn add_state( - &mut self, - ty: schema::GlobalStateType, - state: DataState, - ) -> Result<(), confinement::Error> { - match self.0.get_mut(&ty) { - Some(vec) => vec.push(state), - None => self.insert(ty, GlobalValues::with(state)).map(|_| ()), - } - } - - pub fn extend_state( - &mut self, - ty: schema::GlobalStateType, - iter: impl IntoIterator, - ) -> Result<(), confinement::Error> { - match self.0.get_mut(&ty) { - Some(vec) => vec.extend(iter), - None => self - .insert(ty, GlobalValues::from_inner(Confined::try_from_iter(iter)?)) - .map(|_| ()), - } - } -} - -impl<'a> IntoIterator for &'a GlobalState { - type Item = (&'a schema::GlobalStateType, &'a GlobalValues); - type IntoIter = btree_map::Iter<'a, schema::GlobalStateType, GlobalValues>; - - fn into_iter(self) -> Self::IntoIter { self.0.iter() } -} diff --git a/src/operation/meta.rs b/src/operation/meta.rs deleted file mode 100644 index b8246a4c..00000000 --- a/src/operation/meta.rs +++ /dev/null @@ -1,109 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::collections::btree_map; - -use amplify::confinement::{SmallBlob, TinyOrdMap}; -use amplify::{confinement, Wrapper}; -use commit_verify::StrictHash; - -use crate::{schema, LIB_NAME_RGB_COMMIT}; - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum MetadataError { - /// value of metadata type #{0} is already set. - AlreadyExists(schema::MetaType), - - /// too many metadata values. - #[from(confinement::Error)] - TooManyValues, -} - -#[derive( - Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Default, From -)] -#[display(LowerHex)] -#[wrapper(Deref, AsSlice, BorrowSlice, Hex)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -pub struct MetaValue(SmallBlob); - -#[cfg(feature = "serde")] -mod _serde { - use amplify::hex::FromHex; - use serde_crate::de::Error; - use serde_crate::{Deserialize, Deserializer, Serialize, Serializer}; - - use super::*; - - impl Serialize for MetaValue { - fn serialize(&self, serializer: S) -> Result - where S: Serializer { - serializer.serialize_str(&self.to_string()) - } - } - - impl<'de> Deserialize<'de> for MetaValue { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> { - let s = String::deserialize(deserializer)?; - Self::from_hex(&s).map_err(D::Error::custom) - } - } -} - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, Hash, Default, Debug, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = StrictHash)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct Metadata(TinyOrdMap); - -impl Metadata { - pub fn add_value( - &mut self, - ty: schema::MetaType, - meta: MetaValue, - ) -> Result<(), MetadataError> { - if self.0.contains_key(&ty) { - return Err(MetadataError::AlreadyExists(ty)); - } - self.0.insert(ty, meta)?; - Ok(()) - } -} - -impl<'a> IntoIterator for &'a Metadata { - type Item = (&'a schema::MetaType, &'a MetaValue); - type IntoIter = btree_map::Iter<'a, schema::MetaType, MetaValue>; - - fn into_iter(self) -> Self::IntoIter { self.0.iter() } -} diff --git a/src/operation/mod.rs b/src/operation/mod.rs deleted file mode 100644 index c13450be..00000000 --- a/src/operation/mod.rs +++ /dev/null @@ -1,65 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -mod meta; -mod global; -mod data; -mod fungible; -mod attachment; -mod state; -pub mod seal; -pub mod assignments; -mod operations; -mod bundle; -mod xchain; -mod commit; - -pub use assignments::{ - Assign, AssignAttach, AssignData, AssignFungible, AssignRights, Assignments, AssignmentsRef, - TypedAssigns, -}; -pub use attachment::{AttachId, AttachState, ConcealedAttach, RevealedAttach}; -pub use bundle::{BundleId, InputMap, TransitionBundle, Vin}; -pub use commit::{ - AssignmentCommitment, AssignmentIndex, BaseCommitment, BundleDisclosure, ContractId, - DiscloseHash, GlobalCommitment, OpCommitment, OpDisclose, OpId, TypeCommitment, -}; -pub use data::{ConcealedData, DataState, RevealedData, VoidState}; -pub use fungible::{ - AssetTag, BlindingFactor, BlindingParseError, ConcealedValue, FungibleState, - InvalidFieldElement, NoiseDumb, PedersenCommitment, RangeProof, RangeProofError, RevealedValue, -}; -pub use global::{GlobalState, GlobalValues}; -pub use meta::{MetaValue, Metadata, MetadataError}; -pub use operations::{ - AssetTags, Extension, Genesis, Identity, Input, Inputs, Operation, Opout, OpoutParseError, - Redeemed, Transition, Valencies, -}; -pub use seal::{ - ExposedSeal, GenesisSeal, GraphSeal, OutputSeal, SecretSeal, TxoSeal, XGenesisSeal, XGraphSeal, - XOutputSeal, -}; -pub use state::{ConcealedState, ConfidentialState, ExposedState, RevealedState, StateType}; -pub use xchain::{ - AltLayer1, AltLayer1Set, Impossible, Layer1, XChain, XChainParseError, XOutpoint, - XCHAIN_BITCOIN_PREFIX, XCHAIN_LIQUID_PREFIX, -}; diff --git a/src/operation/operations.rs b/src/operation/operations.rs deleted file mode 100644 index e4ed6cf2..00000000 --- a/src/operation/operations.rs +++ /dev/null @@ -1,685 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::cmp::Ordering; -use std::collections::{btree_map, btree_set, BTreeMap}; -use std::iter; -use std::num::ParseIntError; -use std::str::FromStr; - -use amplify::confinement::{Confined, SmallOrdSet, TinyOrdMap, TinyOrdSet}; -use amplify::{hex, Wrapper}; -use commit_verify::{ - CommitEncode, CommitEngine, CommitId, Conceal, MerkleHash, MerkleLeaves, ReservedBytes, - StrictHash, -}; -use strict_encoding::stl::AsciiPrintable; -use strict_encoding::{RString, StrictDeserialize, StrictEncode, StrictSerialize}; - -use crate::schema::{self, ExtensionType, OpFullType, OpType, SchemaId, TransitionType}; -use crate::{ - AltLayer1Set, AssetTag, Assign, AssignmentIndex, AssignmentType, Assignments, AssignmentsRef, - ConcealedAttach, ConcealedData, ConcealedValue, ContractId, DiscloseHash, ExposedState, Ffv, - GenesisSeal, GlobalState, GraphSeal, Metadata, OpDisclose, OpId, SecretSeal, TypedAssigns, - VoidState, XChain, LIB_NAME_RGB_COMMIT, -}; - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display("{op}/{ty}/{no}")] -/// RGB contract operation output pointer, defined by the operation ID and -/// output number. -pub struct Opout { - pub op: OpId, - pub ty: AssignmentType, - pub no: u16, -} - -impl Opout { - pub fn new(op: OpId, ty: AssignmentType, no: u16) -> Opout { Opout { op, ty, no } } -} - -#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] -#[display(inner)] -pub enum OpoutParseError { - #[from] - InvalidNodeId(hex::Error), - - InvalidType(ParseIntError), - - InvalidOutputNo(ParseIntError), - - /// invalid operation outpoint format ('{0}') - #[display(doc_comments)] - WrongFormat(String), -} - -impl FromStr for Opout { - type Err = OpoutParseError; - - fn from_str(s: &str) -> Result { - let mut split = s.split('/'); - match (split.next(), split.next(), split.next(), split.next()) { - (Some(op), Some(ty), Some(no), None) => Ok(Opout { - op: op.parse()?, - ty: ty.parse().map_err(OpoutParseError::InvalidType)?, - no: no.parse().map_err(OpoutParseError::InvalidOutputNo)?, - }), - _ => Err(OpoutParseError::WrongFormat(s.to_owned())), - } - } -} - -#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = StrictHash)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct AssetTags(TinyOrdMap); - -#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = StrictHash)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct Valencies(TinyOrdSet); - -impl<'a> IntoIterator for &'a Valencies { - type Item = schema::ValencyType; - type IntoIter = iter::Copied>; - - fn into_iter(self) -> Self::IntoIter { self.0.iter().copied() } -} - -#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = StrictHash)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct Redeemed(TinyOrdMap); - -impl<'a> IntoIterator for &'a Redeemed { - type Item = (&'a schema::ValencyType, &'a OpId); - type IntoIter = btree_map::Iter<'a, schema::ValencyType, OpId>; - - fn into_iter(self) -> Self::IntoIter { self.0.iter() } -} - -#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -// TODO: Consider requiring minimum number of inputs to be 1 -pub struct Inputs(SmallOrdSet); - -impl<'a> IntoIterator for &'a Inputs { - type Item = Input; - type IntoIter = iter::Copied>; - - fn into_iter(self) -> Self::IntoIter { self.0.iter().copied() } -} - -impl MerkleLeaves for Inputs { - type Leaf = Input; - type LeafIter<'tmp> = as MerkleLeaves>::LeafIter<'tmp>; - - fn merkle_leaves(&self) -> Self::LeafIter<'_> { self.0.merkle_leaves() } -} - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = MerkleHash)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display("{prev_out}")] -pub struct Input { - pub prev_out: Opout, - #[cfg_attr(feature = "serde", serde(skip))] - reserved: ReservedBytes<2>, -} - -impl Input { - pub fn with(prev_out: Opout) -> Input { - Input { - prev_out, - reserved: default!(), - } - } -} - -/// RGB contract operation API, defined as trait -/// -/// Implemented by all contract operation types (see [`OpType`]): -/// - Genesis ([`Genesis`]) -/// - State transitions ([`Transitions`]) -/// - Public state extensions ([`Extensions`]) -pub trait Operation { - /// Returns type of the operation (see [`OpType`]). Unfortunately, this - /// can't be just a const, since it will break our ability to convert - /// concrete `Node` types into `&dyn Node` (entities implementing traits - /// with const definitions can't be made into objects) - fn op_type(&self) -> OpType; - - /// Returns full contract operation type information - fn full_type(&self) -> OpFullType; - - /// Returns [`OpId`], which is a hash of this operation commitment - /// serialization - fn id(&self) -> OpId; - - /// Returns [`ContractId`] this operation belongs to. - fn contract_id(&self) -> ContractId; - - /// Returns nonce used in consensus ordering of state transitions and - /// extensions. - fn nonce(&self) -> u64; - - /// Returns [`Option::Some`]`(`[`TransitionType`]`)` for transitions or - /// [`Option::None`] for genesis and extension operation types - fn transition_type(&self) -> Option; - - /// Returns [`Option::Some`]`(`[`ExtensionType`]`)` for extension nodes or - /// [`Option::None`] for genesis and state transitions - fn extension_type(&self) -> Option; - - /// Returns metadata associated with the operation, if any. - fn metadata(&self) -> &Metadata; - - /// Returns reference to a full set of metadata (in form of [`GlobalState`] - /// wrapper structure) for the contract operation. - fn globals(&self) -> &GlobalState; - fn valencies(&self) -> &Valencies; - - fn assignments(&self) -> AssignmentsRef; - - fn assignments_by_type(&self, t: AssignmentType) -> Option>; - - /// For genesis and public state extensions always returns an empty list. - /// While public state extension do have parent nodes, they do not contain - /// indexed rights. - fn inputs(&self) -> Inputs; - - /// Provides summary about parts of the operation which are revealed. - fn disclose(&self) -> OpDisclose { - fn proc_seals( - ty: AssignmentType, - a: &[Assign], - seals: &mut BTreeMap>, - state: &mut BTreeMap, - ) { - for (index, assignment) in a.iter().enumerate() { - if let Some(seal) = assignment.revealed_seal() { - seals.insert(AssignmentIndex::new(ty, index as u16), seal.to_secret_seal()); - } - if let Some(revealed) = assignment.as_revealed_state() { - state.insert(AssignmentIndex::new(ty, index as u16), revealed.conceal()); - } - } - } - - let mut seals: BTreeMap> = bmap!(); - let mut void: BTreeMap = bmap!(); - let mut fungible: BTreeMap = bmap!(); - let mut data: BTreeMap = bmap!(); - let mut attach: BTreeMap = bmap!(); - for (ty, assigns) in self.assignments().flat() { - match assigns { - TypedAssigns::Declarative(a) => { - proc_seals(ty, &a, &mut seals, &mut void); - } - TypedAssigns::Fungible(a) => { - proc_seals(ty, &a, &mut seals, &mut fungible); - } - TypedAssigns::Structured(a) => { - proc_seals(ty, &a, &mut seals, &mut data); - } - TypedAssigns::Attachment(a) => { - proc_seals(ty, &a, &mut seals, &mut attach); - } - } - } - - OpDisclose { - id: self.id(), - seals: Confined::from_checked(seals), - fungible: Confined::from_iter_checked( - fungible.into_iter().map(|(k, s)| (k, s.commitment)), - ), - data: Confined::from_checked(data), - attach: Confined::from_checked(attach), - } - } - - fn disclose_hash(&self) -> DiscloseHash { self.disclose().commit_id() } -} - -/// An ASCII printable string up to 4096 chars representing identity of the -/// developer. -/// -/// We deliberately do not define the internal structure of the identity such -/// that it can be updated without changes to the consensus level. -/// -/// Contract or schema validity doesn't assume any checks on the identity; these -/// checks must be performed at the application level. -#[derive(Wrapper, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From, Display)] -#[wrapper(Deref, FromStr)] -#[display(inner)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = StrictHash)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct Identity(RString); - -impl Default for Identity { - fn default() -> Self { Self::from("ssi:anonymous") } -} - -impl From<&'static str> for Identity { - fn from(s: &'static str) -> Self { Self(RString::from(s)) } -} - -impl Identity { - pub fn is_empty(&self) -> bool { self.is_anonymous() } - pub fn is_anonymous(&self) -> bool { self == &default!() } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Genesis { - pub ffv: Ffv, - pub schema_id: SchemaId, - pub flags: ReservedBytes<1, 0>, - pub timestamp: i64, - pub issuer: Identity, - pub testnet: bool, - pub alt_layers1: AltLayer1Set, - pub asset_tags: AssetTags, - pub metadata: Metadata, - pub globals: GlobalState, - pub assignments: Assignments, - pub valencies: Valencies, - pub validator: ReservedBytes<1, 0>, -} - -impl StrictSerialize for Genesis {} -impl StrictDeserialize for Genesis {} - -#[derive(Clone, PartialEq, Eq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Extension { - pub ffv: Ffv, - pub contract_id: ContractId, - pub nonce: u64, - pub extension_type: ExtensionType, - pub metadata: Metadata, - pub globals: GlobalState, - pub assignments: Assignments, - pub redeemed: Redeemed, - pub valencies: Valencies, - pub validator: ReservedBytes<1, 0>, - pub witness: ReservedBytes<2, 0>, -} - -impl StrictSerialize for Extension {} -impl StrictDeserialize for Extension {} - -impl Ord for Extension { - fn cmp(&self, other: &Self) -> Ordering { self.id().cmp(&other.id()) } -} - -impl PartialOrd for Extension { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Transition { - pub ffv: Ffv, - pub contract_id: ContractId, - pub nonce: u64, - pub transition_type: TransitionType, - pub metadata: Metadata, - pub globals: GlobalState, - pub inputs: Inputs, - pub assignments: Assignments, - pub valencies: Valencies, - pub validator: ReservedBytes<1, 0>, - pub witness: ReservedBytes<2, 0>, -} - -impl StrictSerialize for Transition {} -impl StrictDeserialize for Transition {} - -impl Ord for Transition { - fn cmp(&self, other: &Self) -> Ordering { self.id().cmp(&other.id()) } -} - -impl PartialOrd for Transition { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl Conceal for Genesis { - type Concealed = Self; - fn conceal(&self) -> Self::Concealed { - let mut concealed = self.clone(); - concealed - .assignments - .keyed_values_mut() - .for_each(|(_, a)| *a = a.conceal()); - concealed - } -} - -impl Conceal for Transition { - type Concealed = Self; - fn conceal(&self) -> Self::Concealed { - let mut concealed = self.clone(); - concealed - .assignments - .keyed_values_mut() - .for_each(|(_, a)| *a = a.conceal()); - concealed - } -} - -impl Conceal for Extension { - type Concealed = Self; - fn conceal(&self) -> Self::Concealed { - let mut concealed = self.clone(); - concealed - .assignments - .keyed_values_mut() - .for_each(|(_, a)| *a = a.conceal()); - concealed - } -} - -impl CommitEncode for Genesis { - type CommitmentId = OpId; - fn commit_encode(&self, e: &mut CommitEngine) { e.commit_to_serialized(&self.commit()) } -} - -impl CommitEncode for Transition { - type CommitmentId = OpId; - fn commit_encode(&self, e: &mut CommitEngine) { e.commit_to_serialized(&self.commit()) } -} - -impl CommitEncode for Extension { - type CommitmentId = OpId; - fn commit_encode(&self, e: &mut CommitEngine) { e.commit_to_serialized(&self.commit()) } -} - -impl Transition { - /// Returns reference to information about the owned rights in form of - /// [`Inputs`] wrapper structure which this operation updates with - /// state transition ("parent owned rights"). - pub fn prev_state(&self) -> &Inputs { &self.inputs } -} - -impl Extension { - /// Returns reference to information about the public rights (in form of - /// [`Redeemed`] wrapper structure), defined with "parent" state - /// extensions (i.e. those finalized with the current state transition) or - /// referenced by another state extension, which this operation updates - /// ("parent public rights"). - pub fn redeemed(&self) -> &Redeemed { &self.redeemed } -} - -impl Operation for Genesis { - #[inline] - fn op_type(&self) -> OpType { OpType::Genesis } - - #[inline] - fn full_type(&self) -> OpFullType { OpFullType::Genesis } - - #[inline] - fn id(&self) -> OpId { self.commit_id() } - - #[inline] - fn contract_id(&self) -> ContractId { ContractId::from_inner(self.id().into_inner()) } - - #[inline] - fn nonce(&self) -> u64 { u64::MAX } - - #[inline] - fn transition_type(&self) -> Option { None } - - #[inline] - fn extension_type(&self) -> Option { None } - - #[inline] - fn metadata(&self) -> &Metadata { &self.metadata } - - #[inline] - fn globals(&self) -> &GlobalState { &self.globals } - - #[inline] - fn valencies(&self) -> &Valencies { &self.valencies } - - #[inline] - fn assignments(&self) -> AssignmentsRef { (&self.assignments).into() } - - #[inline] - fn assignments_by_type(&self, t: AssignmentType) -> Option> { - self.assignments - .get(&t) - .map(TypedAssigns::transmutate_seals) - } - - #[inline] - fn inputs(&self) -> Inputs { empty!() } -} - -impl Operation for Extension { - #[inline] - fn op_type(&self) -> OpType { OpType::StateExtension } - - #[inline] - fn full_type(&self) -> OpFullType { OpFullType::StateExtension(self.extension_type) } - - #[inline] - fn id(&self) -> OpId { self.commit_id() } - - #[inline] - fn contract_id(&self) -> ContractId { self.contract_id } - - #[inline] - fn nonce(&self) -> u64 { self.nonce } - - #[inline] - fn transition_type(&self) -> Option { None } - - #[inline] - fn extension_type(&self) -> Option { Some(self.extension_type) } - - #[inline] - fn metadata(&self) -> &Metadata { &self.metadata } - - #[inline] - fn globals(&self) -> &GlobalState { &self.globals } - - #[inline] - fn valencies(&self) -> &Valencies { &self.valencies } - - #[inline] - fn assignments(&self) -> AssignmentsRef { (&self.assignments).into() } - - #[inline] - fn assignments_by_type(&self, t: AssignmentType) -> Option> { - self.assignments - .get(&t) - .map(TypedAssigns::transmutate_seals) - } - - #[inline] - fn inputs(&self) -> Inputs { empty!() } -} - -impl Operation for Transition { - #[inline] - fn op_type(&self) -> OpType { OpType::StateTransition } - - #[inline] - fn full_type(&self) -> OpFullType { OpFullType::StateTransition(self.transition_type) } - - #[inline] - fn id(&self) -> OpId { self.commit_id() } - - #[inline] - fn contract_id(&self) -> ContractId { self.contract_id } - - #[inline] - fn nonce(&self) -> u64 { self.nonce } - - #[inline] - fn transition_type(&self) -> Option { Some(self.transition_type) } - - #[inline] - fn extension_type(&self) -> Option { None } - - #[inline] - fn metadata(&self) -> &Metadata { &self.metadata } - - #[inline] - fn globals(&self) -> &GlobalState { &self.globals } - - #[inline] - fn valencies(&self) -> &Valencies { &self.valencies } - - #[inline] - fn assignments(&self) -> AssignmentsRef { (&self.assignments).into() } - - #[inline] - fn assignments_by_type(&self, t: AssignmentType) -> Option> { - self.assignments.get(&t).cloned() - } - - fn inputs(&self) -> Inputs { self.inputs.clone() } -} - -#[cfg(test)] -mod test { - use amplify::ByteArray; - use baid64::DisplayBaid64; - - use super::*; - - #[test] - fn contract_id_display() { - const ID: &str = "rgb:bGxsbGxs-bGxsbGx-sbGxsbG-xsbGxsb-GxsbGxs-bGxsbGw"; - let id = ContractId::from_byte_array([0x6c; 32]); - assert_eq!(ID.len(), 52); - assert_eq!(ID, id.to_string()); - assert_eq!(ID, id.to_baid64_string()); - } - - #[test] - fn contract_id_from_str() { - let id = ContractId::from_byte_array([0x6c; 32]); - assert_eq!( - id, - ContractId::from_str("rgb:bGxsbGxs-bGxsbGx-sbGxsbG-xsbGxsb-GxsbGxs-bGxsbGw").unwrap() - ); - assert_eq!( - id, - ContractId::from_str("bGxsbGxs-bGxsbGx-sbGxsbG-xsbGxsb-GxsbGxs-bGxsbGw").unwrap() - ); - assert_eq!( - id, - ContractId::from_str("rgb:bGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGw").unwrap() - ); - assert_eq!( - id, - ContractId::from_str("bGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGw").unwrap() - ); - - // Wrong separator placement - assert!( - ContractId::from_str("rgb:bGxsbGx-sbGxsbGx-sbGxsbG-xsbGxsb-GxsbGxs-bGxsbGw").is_ok() - ); - // Wrong separator number - assert!( - ContractId::from_str("rgb:bGxs-bGxs-bGxsbGx-sbGxsbG-xsbGxsb-GxsbGxs-bGxsbGw").is_ok() - ); - } -} diff --git a/src/operation/seal.rs b/src/operation/seal.rs deleted file mode 100644 index 186af74c..00000000 --- a/src/operation/seal.rs +++ /dev/null @@ -1,164 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use core::fmt::Debug; -use std::hash::Hash; - -use bp::dbc::Method; -pub use bp::seals::txout::blind::{ChainBlindSeal, ParseError, SingleBlindSeal}; -pub use bp::seals::txout::TxoSeal; -use bp::seals::txout::{BlindSeal, CloseMethod, ExplicitSeal, SealTxid}; -pub use bp::seals::SecretSeal; -use bp::{Outpoint, Txid, Vout}; -use commit_verify::Conceal; -use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; - -use crate::{XChain, XOutpoint}; - -pub type GenesisSeal = SingleBlindSeal; -pub type GraphSeal = ChainBlindSeal; - -pub type OutputSeal = ExplicitSeal; - -pub type XGenesisSeal = XChain; -pub type XGraphSeal = XChain; -pub type XOutputSeal = XChain; - -pub trait ExposedSeal: - Debug - + StrictDumb - + StrictEncode - + StrictDecode - + Eq - + Ord - + Copy - + Hash - + TxoSeal - + Conceal -{ -} - -impl ExposedSeal for GraphSeal {} - -impl ExposedSeal for GenesisSeal {} - -impl TxoSeal for XChain { - fn method(&self) -> CloseMethod { - match self { - XChain::Bitcoin(seal) | XChain::Liquid(seal) => seal.method(), - XChain::Other(_) => unreachable!(), - } - } - - fn txid(&self) -> Option { - match self { - XChain::Bitcoin(seal) | XChain::Liquid(seal) => seal.txid(), - XChain::Other(_) => unreachable!(), - } - } - - fn vout(&self) -> Vout { - match self { - XChain::Bitcoin(seal) | XChain::Liquid(seal) => seal.vout(), - XChain::Other(_) => unreachable!(), - } - } - - fn outpoint(&self) -> Option { - match self { - XChain::Bitcoin(seal) | XChain::Liquid(seal) => seal.outpoint(), - XChain::Other(_) => unreachable!(), - } - } - - fn txid_or(&self, default_txid: Txid) -> Txid { - match self { - XChain::Bitcoin(seal) | XChain::Liquid(seal) => seal.txid_or(default_txid), - XChain::Other(_) => unreachable!(), - } - } - - fn outpoint_or(&self, default_txid: Txid) -> Outpoint { - match self { - XChain::Bitcoin(seal) | XChain::Liquid(seal) => seal.outpoint_or(default_txid), - XChain::Other(_) => unreachable!(), - } - } -} - -/* -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct SealPreimage(Bytes32); - */ - -impl From> for XOutpoint { - #[inline] - fn from(seal: XChain) -> Self { seal.to_outpoint() } -} - -impl XChain { - pub fn transmutate(self) -> XChain { self.map_ref(|seal| seal.transmutate()) } - - /// Converts seal into a transaction outpoint. - #[inline] - pub fn to_outpoint(&self) -> XOutpoint { self.map_ref(GenesisSeal::to_outpoint).into() } -} - -impl XChain> { - /// Converts revealed seal into concealed. - #[inline] - pub fn to_secret_seal(&self) -> XChain { self.conceal() } -} - -#[cfg(test)] -mod test { - use amplify::hex::FromHex; - use bp::seals::txout::TxPtr; - - use super::*; - - #[test] - fn secret_seal_is_sha256d() { - let reveal = XChain::Bitcoin(BlindSeal { - method: CloseMethod::TapretFirst, - blinding: 54683213134637, - txid: TxPtr::Txid( - Txid::from_hex("646ca5c1062619e2a2d60771c9dfd820551fb773e4dc8c4ed67965a8d1fae839") - .unwrap(), - ), - vout: Vout::from(2), - }); - let secret = reveal.to_secret_seal(); - assert_eq!( - secret.to_string(), - "bc:utxob:lD72u61i-sxCEKth-vqjH0mI-kcEwa1Q-fbnPLon-tDtXveO-keHh0" - ); - assert_eq!(reveal.to_secret_seal(), reveal.conceal()) - } -} diff --git a/src/operation/state.rs b/src/operation/state.rs deleted file mode 100644 index db230257..00000000 --- a/src/operation/state.rs +++ /dev/null @@ -1,128 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use core::fmt::Debug; -use core::hash::Hash; - -use commit_verify::Conceal; -use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; - -use crate::{ - ConcealedAttach, ConcealedData, ConcealedValue, RevealedAttach, RevealedData, RevealedValue, -}; - -/// Marker trait for types of state which are just a commitment to the actual -/// state data. -pub trait ConfidentialState: Debug + Eq + Copy { - fn state_type(&self) -> StateType; - fn state_commitment(&self) -> ConcealedState; -} - -/// Marker trait for types of state holding explicit state data. -pub trait ExposedState: - Debug - + StrictDumb - + StrictEncode - + StrictDecode - + Conceal - + Eq - + Ord - + Clone -{ - type Confidential: ConfidentialState + StrictEncode + StrictDecode + StrictDumb; - fn state_type(&self) -> StateType; - fn state_data(&self) -> RevealedState; -} - -/// Categories of the state -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display(lowercase)] -pub enum StateType { - /// No state data - Void, - - /// Value-based state, i.e. which can be committed to with a Pedersen - /// commitment - Fungible, - - /// State defined with custom data - Structured, - - /// Attached data container - Attachment, -} - -/// Categories of the state -#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", tag = "type") -)] -pub enum RevealedState { - Void, - Fungible(RevealedValue), - Structured(RevealedData), - Attachment(RevealedAttach), -} - -impl RevealedState { - pub fn state_type(&self) -> StateType { - match self { - RevealedState::Void => StateType::Void, - RevealedState::Fungible(_) => StateType::Fungible, - RevealedState::Structured(_) => StateType::Structured, - RevealedState::Attachment(_) => StateType::Attachment, - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", tag = "type") -)] -#[allow(clippy::large_enum_variant)] -pub enum ConcealedState { - Void, - Fungible(ConcealedValue), - Structured(ConcealedData), - Attachment(ConcealedAttach), -} - -impl ConfidentialState for ConcealedState { - fn state_type(&self) -> StateType { - match self { - ConcealedState::Void => StateType::Void, - ConcealedState::Fungible(_) => StateType::Fungible, - ConcealedState::Structured(_) => StateType::Structured, - ConcealedState::Attachment(_) => StateType::Attachment, - } - } - fn state_commitment(&self) -> ConcealedState { *self } -} diff --git a/src/operation/xchain.rs b/src/operation/xchain.rs deleted file mode 100644 index 81fc737d..00000000 --- a/src/operation/xchain.rs +++ /dev/null @@ -1,580 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::cmp::Ordering; -use std::convert::Infallible; -use std::fmt::{Debug, Display, Formatter}; -use std::str::FromStr; -use std::{fmt, io}; - -use amplify::confinement::TinyOrdSet; -use bp::{Bp, Outpoint}; -use commit_verify::{Conceal, StrictHash}; -use strict_encoding::{ - DecodeError, DefineUnion, ReadTuple, ReadUnion, StrictDecode, StrictDumb, StrictEncode, - StrictEnum, StrictSum, StrictType, StrictUnion, TypedRead, TypedWrite, VariantError, - WriteUnion, -}; - -use crate::{OutputSeal, XOutputSeal, LIB_NAME_RGB_COMMIT}; - -pub const XCHAIN_BITCOIN_PREFIX: &str = "bc"; -pub const XCHAIN_LIQUID_PREFIX: &str = "lq"; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)] -#[display(lowercase)] -#[derive( - strict_encoding::StrictType, - StrictDumb, - strict_encoding::StrictEncode, - strict_encoding::StrictDecode -)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -pub enum Layer1 { - #[strict_type(dumb)] - Bitcoin = 0, - Liquid = 1, -} - -#[derive(Wrapper, WrapperMut, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From)] -#[wrapper(Deref, FromStr, Display)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -pub struct XOutpoint(XChain); - -impl From for XOutpoint { - #[inline] - fn from(seal: XOutputSeal) -> Self { seal.to_outpoint() } -} - -impl XOutputSeal { - /// Converts seal into a transaction outpoint. - #[inline] - pub fn to_outpoint(&self) -> XOutpoint { self.map_ref(OutputSeal::to_outpoint).into() } -} - -#[cfg(feature = "serde")] -mod _serde { - use serde_crate::de::Error; - use serde_crate::{Deserialize, Deserializer, Serialize, Serializer}; - - use super::*; - - impl Serialize for XOutpoint { - fn serialize(&self, serializer: S) -> Result - where S: Serializer { - if serializer.is_human_readable() { - serializer.serialize_str(&self.to_string()) - } else { - self.0.serialize(serializer) - } - } - } - - impl<'de> Deserialize<'de> for XOutpoint { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> { - if deserializer.is_human_readable() { - let s = String::deserialize(deserializer)?; - Self::from_str(&s).map_err(D::Error::custom) - } else { - XChain::::deserialize(deserializer).map(Self) - } - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)] -#[display(lowercase)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -pub enum AltLayer1 { - #[strict_type(dumb)] - Liquid = 1, - // Abraxas = 0x10, - // Prime = 0x11, -} - -impl AltLayer1 { - pub fn layer1(&self) -> Layer1 { - match self { - AltLayer1::Liquid => Layer1::Liquid, - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", tag = "chain", content = "data") -)] -pub enum Impossible {} - -impl TryFrom for Impossible { - type Error = VariantError; - - fn try_from(_: u8) -> Result { panic!("must not be instantiated") } -} -impl From for u8 { - fn from(_: Impossible) -> Self { unreachable!() } -} - -impl StrictDumb for Impossible { - fn strict_dumb() -> Self { panic!("must not be instantiated") } -} -impl StrictType for Impossible { - const STRICT_LIB_NAME: &'static str = LIB_NAME_RGB_COMMIT; -} -impl StrictSum for Impossible { - const ALL_VARIANTS: &'static [(u8, &'static str)] = &[]; - fn variant_name(&self) -> &'static str { unreachable!() } -} -impl StrictEnum for Impossible {} -impl StrictEncode for Impossible { - fn strict_encode(&self, _writer: W) -> io::Result { unreachable!() } -} -impl StrictDecode for Impossible { - fn strict_decode(_reader: &mut impl TypedRead) -> Result { - panic!("must not be deserialized") - } -} - -impl Conceal for Impossible { - type Concealed = Self; - fn conceal(&self) -> Self::Concealed { unreachable!() } -} - -impl Display for Impossible { - fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result { unreachable!() } -} -impl FromStr for Impossible { - type Err = Infallible; - fn from_str(_: &str) -> Result { panic!("must not be parsed") } -} - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = StrictHash)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct AltLayer1Set(TinyOrdSet); - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", tag = "chain", content = "data") -)] -pub enum XChain { - Bitcoin(T), - - Liquid(T), - - Other(X), -} - -impl PartialOrd for XChain { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl Ord for XChain { - fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - (Self::Bitcoin(t1), Self::Bitcoin(t2)) => t1.cmp(t2), - (Self::Liquid(t1), Self::Liquid(t2)) => t1.cmp(t2), - (Self::Bitcoin(_), _) => Ordering::Greater, - (_, Self::Bitcoin(_)) => Ordering::Less, - (Self::Liquid(_), _) => Ordering::Greater, - (_, Self::Liquid(_)) => Ordering::Less, - (Self::Other(x1), Self::Other(x2)) => x1.cmp(x2), - } - } -} - -impl Conceal for XChain { - type Concealed = XChain; - - #[inline] - fn conceal(&self) -> Self::Concealed { self.map2_ref(|t| t.conceal(), |x| x.conceal()) } -} - -impl StrictType for XChain -where T: StrictDumb + StrictType -{ - const STRICT_LIB_NAME: &'static str = LIB_NAME_RGB_COMMIT; -} -impl StrictSum for XChain -where T: StrictDumb + StrictType -{ - const ALL_VARIANTS: &'static [(u8, &'static str)] = &[(0x00, "bitcoin"), (0x01, "liquid")]; - - fn variant_name(&self) -> &'static str { - match self { - XChain::Bitcoin(_) => Self::ALL_VARIANTS[0].1, - XChain::Liquid(_) => Self::ALL_VARIANTS[1].1, - XChain::Other(_) => unreachable!(), - } - } -} -impl StrictUnion for XChain where T: StrictDumb + StrictType {} -impl StrictDumb for XChain -where T: StrictDumb -{ - fn strict_dumb() -> Self { XChain::Bitcoin(strict_dumb!()) } -} -impl StrictEncode for XChain -where T: StrictDumb + StrictEncode -{ - fn strict_encode(&self, writer: W) -> io::Result { - writer.write_union::(|w| { - let w = w - .define_newtype::(vname!(Self::ALL_VARIANTS[0].1)) - .define_newtype::(vname!(Self::ALL_VARIANTS[1].1)) - .complete(); - Ok(match self { - XChain::Bitcoin(t) => w.write_newtype(vname!(Self::ALL_VARIANTS[0].1), t)?, - XChain::Liquid(t) => w.write_newtype(vname!(Self::ALL_VARIANTS[1].1), t)?, - XChain::Other(_) => unreachable!(), - } - .complete()) - }) - } -} -impl StrictDecode for XChain -where T: StrictDumb + StrictDecode -{ - fn strict_decode(reader: &mut impl TypedRead) -> Result { - reader.read_union(|field, r| match field.as_str() { - x if x == Self::ALL_VARIANTS[0].1 => { - r.read_tuple(|r| r.read_field().map(Self::Bitcoin)) - } - x if x == Self::ALL_VARIANTS[1].1 => r.read_tuple(|r| r.read_field().map(Self::Liquid)), - _ => unreachable!(), - }) - } -} - -impl XChain { - pub fn layer1(&self) -> Layer1 { - match self { - XChain::Bitcoin(_) => Layer1::Bitcoin, - XChain::Liquid(_) => Layer1::Liquid, - XChain::Other(_) => unreachable!(), - } - } - - pub fn as_bp(&self) -> Bp<&T> - where for<'a> &'a T: StrictDumb + StrictEncode + StrictDecode { - match self { - XChain::Bitcoin(t) => Bp::Bitcoin(t), - XChain::Liquid(t) => Bp::Liquid(t), - XChain::Other(_) => unreachable!(), - } - } - - pub fn into_bp(self) -> Bp - where T: StrictDumb + StrictEncode + StrictDecode { - match self { - XChain::Bitcoin(t) => Bp::Bitcoin(t), - XChain::Liquid(t) => Bp::Liquid(t), - XChain::Other(_) => unreachable!(), - } - } - - pub fn as_reduced_unsafe(&self) -> &T { - match self { - XChain::Bitcoin(t) | XChain::Liquid(t) => t, - XChain::Other(_) => unreachable!(), - } - } - - /// Maps the value from one internal type into another. - pub fn map(self, f: impl FnOnce(T) -> U) -> XChain { - match self { - Self::Bitcoin(t) => XChain::Bitcoin(f(t)), - Self::Liquid(t) => XChain::Liquid(f(t)), - Self::Other(_) => unreachable!(), - } - } - - /// Maps the value from a reference on internal type into another. - pub fn map_ref(&self, f: impl FnOnce(&T) -> U) -> XChain { - match self { - Self::Bitcoin(t) => XChain::Bitcoin(f(t)), - Self::Liquid(t) => XChain::Liquid(f(t)), - Self::Other(_) => unreachable!(), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may error. - pub fn try_map(self, f: impl FnOnce(T) -> Result) -> Result, E> { - match self { - Self::Bitcoin(t) => f(t).map(XChain::Bitcoin), - Self::Liquid(t) => f(t).map(XChain::Liquid), - Self::Other(_) => unreachable!(), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may error. - pub fn try_map_ref(&self, f: impl FnOnce(&T) -> Result) -> Result, E> { - match self { - Self::Bitcoin(t) => f(t).map(XChain::Bitcoin), - Self::Liquid(t) => f(t).map(XChain::Liquid), - Self::Other(_) => unreachable!(), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may result in an optional value. - pub fn maybe_map(self, f: impl FnOnce(T) -> Option) -> Option> { - match self { - Self::Bitcoin(t) => f(t).map(XChain::Bitcoin), - Self::Liquid(t) => f(t).map(XChain::Liquid), - Self::Other(_) => unreachable!(), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may result in an optional value. - pub fn maybe_map_ref(&self, f: impl FnOnce(&T) -> Option) -> Option> { - match self { - Self::Bitcoin(t) => f(t).map(XChain::Bitcoin), - Self::Liquid(t) => f(t).map(XChain::Liquid), - Self::Other(_) => unreachable!(), - } - } - - /// Returns iterator over elements - pub fn iter<'i>( - &'i self, - ) -> Box::Item>> + 'i> - where &'i T: IntoIterator { - match self { - XChain::Bitcoin(t) => Box::new(t.into_iter().map(XChain::Bitcoin)), - XChain::Liquid(t) => Box::new(t.into_iter().map(XChain::Liquid)), - Self::Other(_) => unreachable!(), - } - } -} - -impl XChain { - pub fn with(layer1: Layer1, data: impl Into) -> Self { - match layer1 { - Layer1::Bitcoin => XChain::Bitcoin(data.into()), - Layer1::Liquid => XChain::Liquid(data.into()), - } - } - - pub fn is_bitcoin(&self) -> bool { matches!(self, XChain::Bitcoin(_)) } - pub fn is_liquid(&self) -> bool { matches!(self, XChain::Liquid(_)) } - pub fn is_bp(&self) -> bool { - match self { - XChain::Bitcoin(_) | XChain::Liquid(_) => true, - XChain::Other(_) => false, - } - } - - /// Maps the value from one internal type into another. - pub fn map2(self, f1: impl FnOnce(T) -> U, f2: impl FnOnce(X) -> Y) -> XChain { - match self { - Self::Bitcoin(t) => XChain::Bitcoin(f1(t)), - Self::Liquid(t) => XChain::Liquid(f1(t)), - Self::Other(x) => XChain::Other(f2(x)), - } - } - - /// Maps the value from a reference on internal type into another. - pub fn map2_ref( - &self, - f1: impl FnOnce(&T) -> U, - f2: impl FnOnce(&X) -> Y, - ) -> XChain { - match self { - Self::Bitcoin(t) => XChain::Bitcoin(f1(t)), - Self::Liquid(t) => XChain::Liquid(f1(t)), - Self::Other(x) => XChain::Other(f2(x)), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may error. - pub fn try_map2( - self, - f1: impl FnOnce(T) -> Result, - f2: impl FnOnce(X) -> Result, - ) -> Result, E> { - match self { - Self::Bitcoin(t) => f1(t).map(XChain::Bitcoin), - Self::Liquid(t) => f1(t).map(XChain::Liquid), - Self::Other(x) => f2(x).map(XChain::Other), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may error. - pub fn try_map2_ref( - &self, - f1: impl FnOnce(&T) -> Result, - f2: impl FnOnce(&X) -> Result, - ) -> Result, E> { - match self { - Self::Bitcoin(t) => f1(t).map(XChain::Bitcoin), - Self::Liquid(t) => f1(t).map(XChain::Liquid), - Self::Other(x) => f2(x).map(XChain::Other), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may result in an optional value. - pub fn maybe_map2( - self, - f1: impl FnOnce(T) -> Option, - f2: impl FnOnce(X) -> Option, - ) -> Option> { - match self { - Self::Bitcoin(t) => f1(t).map(XChain::Bitcoin), - Self::Liquid(t) => f1(t).map(XChain::Liquid), - Self::Other(x) => f2(x).map(XChain::Other), - } - } - - /// Maps the value from one internal type into another, covering cases which - /// may result in an optional value. - pub fn maybe_map2_ref( - &self, - f1: impl FnOnce(&T) -> Option, - f2: impl FnOnce(&X) -> Option, - ) -> Option> { - match self { - Self::Bitcoin(t) => f1(t).map(XChain::Bitcoin), - Self::Liquid(t) => f1(t).map(XChain::Liquid), - Self::Other(x) => f2(x).map(XChain::Other), - } - } -} - -impl<'a, T: Copy, X: Copy> XChain<&'a T, &'a X> { - pub fn copied(self) -> XChain { self.map2(|t| *t, |x| *x) } -} - -impl<'a, T: Clone, X: Clone> XChain<&'a T, &'a X> { - pub fn cloned(self) -> XChain { self.map2(T::clone, X::clone) } -} - -impl XChain, Impossible> { - pub fn transpose(self) -> Option> { - match self { - XChain::Bitcoin(inner) => inner.map(XChain::Bitcoin), - XChain::Liquid(inner) => inner.map(XChain::Liquid), - XChain::Other(_) => unreachable!(), - } - } -} - -impl Iterator for XChain { - type Item = XChain<::Item>; - - fn next(&mut self) -> Option { - match self { - XChain::Bitcoin(t) => t.next().map(XChain::Bitcoin), - XChain::Liquid(t) => t.next().map(XChain::Liquid), - XChain::Other(_) => unreachable!(), - } - } -} - -#[derive(Clone, Debug, Display, Error, From)] -pub enum XChainParseError { - #[display("unknown chain prefix '{0}'; only 'bc:' and 'lq:' are currently supported")] - UnknownPrefix(String), - - #[from] - #[display(inner)] - Inner(E), -} - -impl FromStr for XChain -where - T: StrictDumb + StrictEncode + StrictDecode, - T::Err: Debug + Display, - X: StrictDumb + StrictEncode + StrictDecode, - X::Err: Debug + Display, -{ - type Err = XChainParseError; - - fn from_str(s: &str) -> Result { - if let Some((prefix, s)) = s.split_once(':') { - match prefix { - XCHAIN_BITCOIN_PREFIX => s - .parse() - .map(XChain::Bitcoin) - .map_err(XChainParseError::from), - XCHAIN_LIQUID_PREFIX => s - .parse() - .map(XChain::Liquid) - .map_err(XChainParseError::from), - unknown => Err(XChainParseError::UnknownPrefix(unknown.to_owned())), - } - } else { - s.parse() - .map(XChain::Bitcoin) - .map_err(XChainParseError::from) - } - } -} - -impl Display for XChain -where - T: StrictDumb + StrictEncode + StrictDecode, - X: StrictDumb + StrictEncode + StrictDecode, -{ - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - XChain::Bitcoin(t) => write!(f, "{XCHAIN_BITCOIN_PREFIX}:{t}"), - XChain::Liquid(t) => write!(f, "{XCHAIN_LIQUID_PREFIX}:{t}"), - XChain::Other(x) => Display::fmt(x, f), - } - } -} diff --git a/src/schema/mod.rs b/src/schema/mod.rs deleted file mode 100644 index 54073447..00000000 --- a/src/schema/mod.rs +++ /dev/null @@ -1,35 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -mod operations; -#[allow(clippy::module_inception)] -mod schema; -mod state; -mod occurrences; - -pub use occurrences::{Occurrences, OccurrencesMismatch}; -pub use operations::{ - AssignmentType, AssignmentsSchema, ExtensionSchema, GenesisSchema, GlobalSchema, MetaSchema, - OpFullType, OpSchema, OpType, TransitionSchema, ValencySchema, ValencyType, -}; -pub use schema::{ExtensionType, GlobalStateType, MetaType, Schema, SchemaId, TransitionType}; -pub use state::{FungibleType, GlobalStateSchema, MediaType, OwnedStateSchema}; diff --git a/src/schema/occurrences.rs b/src/schema/occurrences.rs deleted file mode 100644 index de12e19a..00000000 --- a/src/schema/occurrences.rs +++ /dev/null @@ -1,263 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::io; -use std::ops::RangeInclusive; - -use strict_encoding::{ - DecodeError, ReadStruct, StrictDecode, StrictEncode, StrictProduct, StrictStruct, StrictType, - TypeName, TypedRead, TypedWrite, WriteStruct, -}; - -use crate::LIB_NAME_RGB_COMMIT; - -#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -pub enum Occurrences { - #[default] - Once, - NoneOrOnce, - NoneOrMore, - OnceOrMore, - NoneOrUpTo(u16), - OnceOrUpTo(u16), - Exactly(u16), - Range(RangeInclusive), -} - -impl Occurrences { - pub fn min_value(&self) -> u16 { - match self { - Occurrences::Once => 1, - Occurrences::NoneOrOnce => 0, - Occurrences::NoneOrMore => 0, - Occurrences::OnceOrMore => 1, - Occurrences::NoneOrUpTo(_) => 0, - Occurrences::OnceOrUpTo(_) => 1, - Occurrences::Exactly(val) => *val, - Occurrences::Range(range) => *range.start(), - } - } - - pub fn max_value(&self) -> u16 { - match self { - Occurrences::Once | Occurrences::NoneOrOnce => 1, - Occurrences::NoneOrMore | Occurrences::OnceOrMore => u16::MAX, - Occurrences::OnceOrUpTo(max) | Occurrences::NoneOrUpTo(max) => *max, - Occurrences::Exactly(val) => *val, - Occurrences::Range(range) => *range.end(), - } - } - - pub fn check(&self, count: u16) -> Result<(), OccurrencesMismatch> { - let orig_count = count; - match self { - Occurrences::Once if count == 1 => Ok(()), - Occurrences::NoneOrOnce if count <= 1 => Ok(()), - Occurrences::OnceOrMore if count > 0 => Ok(()), - Occurrences::OnceOrUpTo(max) if count > 0 && count <= *max => Ok(()), - Occurrences::NoneOrMore => Ok(()), - Occurrences::NoneOrUpTo(max) if count <= *max => Ok(()), - Occurrences::Exactly(val) if count == *val => Ok(()), - Occurrences::Range(range) if range.contains(&count) => Ok(()), - _ => Err(OccurrencesMismatch { - min: self.min_value(), - max: self.max_value(), - found: orig_count, - }), - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)] -#[display(doc_comments)] -pub enum OccurrencesError { - /// unable to construct occurrences value with both minimum and maximum - /// number set to zero. - Zero, - - /// unable to construct occurrences value with minimum number exceeding - /// maximum - MinExceedsMax, -} - -impl TryFrom> for Occurrences { - type Error = OccurrencesError; - - fn try_from(range: RangeInclusive) -> Result { - Ok(match (*range.start(), *range.end()) { - (0, 0) => return Err(OccurrencesError::Zero), - (a, b) if a > b => return Err(OccurrencesError::MinExceedsMax), - (0, 1) => Occurrences::NoneOrOnce, - (1, 1) => Occurrences::Once, - (0, u16::MAX) => Occurrences::NoneOrMore, - (1, u16::MAX) => Occurrences::OnceOrMore, - (0, max) => Occurrences::NoneOrUpTo(max), - (1, max) => Occurrences::OnceOrUpTo(max), - (a, b) if a == b => Occurrences::Exactly(a), - (min, max) => Occurrences::Range(min..=max), - }) - } -} - -impl StrictType for Occurrences { - const STRICT_LIB_NAME: &'static str = LIB_NAME_RGB_COMMIT; - fn strict_name() -> Option { Some(tn!("Occurrences")) } -} -impl StrictProduct for Occurrences {} -impl StrictStruct for Occurrences { - const ALL_FIELDS: &'static [&'static str] = &["min", "max"]; -} -impl StrictEncode for Occurrences { - fn strict_encode(&self, writer: W) -> io::Result { - writer.write_struct::(|w| { - Ok(w.write_field(fname!("min"), &self.min_value())? - .write_field(fname!("max"), &self.max_value())? - .complete()) - }) - } -} -impl StrictDecode for Occurrences { - fn strict_decode(reader: &mut impl TypedRead) -> Result { - reader.read_struct(|r| { - let min = r.read_field(fname!("min"))?; - let max = r.read_field(fname!("max"))?; - Occurrences::try_from(min..=max) - .map_err(|err| DecodeError::DataIntegrityError(err.to_string())) - }) - } -} - -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Display)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -#[display("expected from {min} to {max} elements, while {found} were provided")] -pub struct OccurrencesMismatch { - pub min: u16, - pub max: u16, - pub found: u16, -} - -#[cfg(test)] -mod test { - use super::Occurrences; - - #[test] - fn test_once_check_count() { - let occurrence: Occurrences = Occurrences::Once; - occurrence.check(1).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 1, max: 1, found: 0 }")] - fn test_once_check_count_fail_zero() { - let occurrence: Occurrences = Occurrences::Once; - occurrence.check(0).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 1, max: 1, found: 2 }")] - fn test_once_check_count_fail_two() { - let occurrence: Occurrences = Occurrences::Once; - occurrence.check(2).unwrap(); - } - - #[test] - fn test_none_or_once_check_count() { - let occurrence: Occurrences = Occurrences::NoneOrOnce; - occurrence.check(1).unwrap(); - } - #[test] - fn test_none_or_once_check_count_zero() { - let occurrence: Occurrences = Occurrences::NoneOrOnce; - occurrence.check(0).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 0, max: 1, found: 2 }")] - fn test_none_or_once_check_count_fail_two() { - let occurrence: Occurrences = Occurrences::NoneOrOnce; - occurrence.check(2).unwrap(); - } - - #[test] - fn test_once_or_up_to_none() { - let occurrence: Occurrences = Occurrences::OnceOrMore; - occurrence.check(1).unwrap(); - } - #[test] - fn test_once_or_up_to_none_large() { - let occurrence: Occurrences = Occurrences::OnceOrMore; - occurrence.check(u16::MAX).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 1, max: 65535, found: 0 }")] - fn test_once_or_up_to_none_fail_zero() { - let occurrence: Occurrences = Occurrences::OnceOrMore; - occurrence.check(0).unwrap(); - } - #[test] - fn test_once_or_up_to_42() { - let occurrence: Occurrences = Occurrences::OnceOrUpTo(42); - occurrence.check(42).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 1, max: 42, found: 43 }")] - fn test_once_or_up_to_42_large() { - let occurrence: Occurrences = Occurrences::OnceOrUpTo(42); - occurrence.check(43).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 1, max: 42, found: 0 }")] - fn test_once_or_up_to_42_fail_zero() { - let occurrence: Occurrences = Occurrences::OnceOrUpTo(42); - occurrence.check(0).unwrap(); - } - - #[test] - fn test_none_or_up_to_none_zero() { - let occurrence: Occurrences = Occurrences::NoneOrMore; - occurrence.check(0).unwrap(); - } - #[test] - fn test_none_or_up_to_none_large() { - let occurrence: Occurrences = Occurrences::NoneOrMore; - occurrence.check(u16::MAX).unwrap(); - } - #[test] - fn test_none_or_up_to_42_zero() { - let occurrence: Occurrences = Occurrences::NoneOrMore; - occurrence.check(0).unwrap(); - } - #[test] - fn test_none_or_up_to_42() { - let occurrence: Occurrences = Occurrences::NoneOrMore; - occurrence.check(42).unwrap(); - } - #[test] - #[should_panic(expected = "OccurrencesMismatch { min: 0, max: 42, found: 43 }")] - fn test_none_or_up_to_42_large() { - let occurrence: Occurrences = Occurrences::NoneOrUpTo(42); - occurrence.check(43).unwrap(); - } -} diff --git a/src/schema/operations.rs b/src/schema/operations.rs deleted file mode 100644 index fa1dc820..00000000 --- a/src/schema/operations.rs +++ /dev/null @@ -1,244 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use aluvm::library::LibSite; -use amplify::confinement::{TinyOrdMap, TinyOrdSet}; -use amplify::Wrapper; - -use super::{ExtensionType, GlobalStateType, Occurrences, TransitionType}; -use crate::schema::schema::MetaType; -use crate::LIB_NAME_RGB_COMMIT; - -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] -#[wrapper(FromStr, LowerHex, UpperHex)] -#[display("0x{0:04X}")] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct AssignmentType(u16); -impl AssignmentType { - pub const fn with(ty: u16) -> Self { Self(ty) } - #[inline] - pub fn to_le_bytes(&self) -> [u8; 2] { self.0.to_le_bytes() } -} - -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] -#[wrapper(FromStr, LowerHex, UpperHex)] -#[display("0x{0:04X}")] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ValencyType(u16); -impl ValencyType { - pub const fn with(ty: u16) -> Self { Self(ty) } -} - -pub type MetaSchema = TinyOrdSet; -pub type GlobalSchema = TinyOrdMap; -pub type ValencySchema = TinyOrdSet; -pub type InputsSchema = TinyOrdMap; -pub type AssignmentsSchema = TinyOrdMap; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -/// Node type: genesis, extensions and state transitions -pub enum OpType { - /// Genesis: single operation per contract, defining contract and - /// committing to a specific schema and underlying chain hash - #[display("genesis")] - Genesis = 0, - - /// Multiple points for decentralized & unowned contract extension, - /// committing either to a genesis or some state transition via their - /// valencies - #[display("extension")] - StateExtension = 1, - - /// State transition performing owned change to the state data and - /// committing to (potentially multiple) ancestors (i.e. genesis, - /// extensions and/or other state transitions) via spending - /// corresponding transaction outputs assigned some state by ancestors - #[display("transition")] - StateTransition = 2, -} - -/// Aggregated type used to supply full contract operation type and -/// transition/state extension type information -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum OpFullType { - /// Genesis operation (no subtypes) - #[display("genesis")] - Genesis, - - /// State transition contract operation, subtyped by transition type - #[display("state transition #{0}")] - StateTransition(TransitionType), - - /// State extension contract operation, subtyped by extension type - #[display("state extension #{0}")] - StateExtension(ExtensionType), -} - -impl OpFullType { - pub fn subtype(self) -> u16 { - match self { - OpFullType::Genesis => 0, - OpFullType::StateTransition(ty) => ty.to_inner(), - OpFullType::StateExtension(ty) => ty.to_inner(), - } - } - - pub fn is_transition(self) -> bool { matches!(self, Self::StateTransition(_)) } - - pub fn is_extension(self) -> bool { matches!(self, Self::StateExtension(_)) } -} - -/// Trait defining common API for all operation type schemata -pub trait OpSchema { - fn op_type(&self) -> OpType; - fn metadata(&self) -> &MetaSchema; - fn globals(&self) -> &GlobalSchema; - fn inputs(&self) -> Option<&InputsSchema>; - fn redeems(&self) -> Option<&ValencySchema>; - fn assignments(&self) -> &AssignmentsSchema; - fn valencies(&self) -> &ValencySchema; -} - -#[derive(Clone, PartialEq, Eq, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct GenesisSchema { - pub metadata: MetaSchema, - pub globals: GlobalSchema, - pub assignments: AssignmentsSchema, - pub valencies: ValencySchema, - // NB: it is possible to transform option into enum covering other virtual machines - pub validator: Option, -} - -#[derive(Clone, PartialEq, Eq, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ExtensionSchema { - pub metadata: MetaSchema, - pub globals: GlobalSchema, - pub redeems: ValencySchema, - pub assignments: AssignmentsSchema, - pub valencies: ValencySchema, - pub validator: Option, -} - -#[derive(Clone, PartialEq, Eq, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct TransitionSchema { - pub metadata: MetaSchema, - pub globals: GlobalSchema, - pub inputs: InputsSchema, - pub assignments: AssignmentsSchema, - pub valencies: ValencySchema, - pub validator: Option, -} - -impl OpSchema for GenesisSchema { - #[inline] - fn op_type(&self) -> OpType { OpType::Genesis } - #[inline] - fn metadata(&self) -> &MetaSchema { &self.metadata } - #[inline] - fn globals(&self) -> &GlobalSchema { &self.globals } - #[inline] - fn inputs(&self) -> Option<&InputsSchema> { None } - #[inline] - fn redeems(&self) -> Option<&ValencySchema> { None } - #[inline] - fn assignments(&self) -> &AssignmentsSchema { &self.assignments } - #[inline] - fn valencies(&self) -> &ValencySchema { &self.valencies } -} - -impl OpSchema for ExtensionSchema { - #[inline] - fn op_type(&self) -> OpType { OpType::StateExtension } - #[inline] - fn metadata(&self) -> &MetaSchema { &self.metadata } - #[inline] - fn globals(&self) -> &GlobalSchema { &self.globals } - #[inline] - fn inputs(&self) -> Option<&InputsSchema> { None } - #[inline] - fn redeems(&self) -> Option<&ValencySchema> { Some(&self.redeems) } - #[inline] - fn assignments(&self) -> &AssignmentsSchema { &self.assignments } - #[inline] - fn valencies(&self) -> &ValencySchema { &self.valencies } -} - -impl OpSchema for TransitionSchema { - #[inline] - fn op_type(&self) -> OpType { OpType::StateTransition } - #[inline] - fn metadata(&self) -> &MetaSchema { &self.metadata } - #[inline] - fn globals(&self) -> &GlobalSchema { &self.globals } - #[inline] - fn inputs(&self) -> Option<&AssignmentsSchema> { Some(&self.inputs) } - #[inline] - fn redeems(&self) -> Option<&ValencySchema> { None } - #[inline] - fn assignments(&self) -> &AssignmentsSchema { &self.assignments } - #[inline] - fn valencies(&self) -> &ValencySchema { &self.valencies } -} diff --git a/src/schema/schema.rs b/src/schema/schema.rs deleted file mode 100644 index 5f70800f..00000000 --- a/src/schema/schema.rs +++ /dev/null @@ -1,286 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::cmp::Ordering; -use std::fmt::{self, Display, Formatter}; -use std::str::FromStr; - -use aluvm::library::LibId; -use amplify::confinement::{TinyOrdMap, TinyOrdSet}; -use amplify::{ByteArray, Bytes32}; -use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use commit_verify::{ - CommitEncode, CommitEngine, CommitId, CommitmentId, DigestExt, ReservedBytes, Sha256, -}; -use strict_encoding::{ - StrictDecode, StrictDeserialize, StrictEncode, StrictSerialize, StrictType, TypeName, -}; -use strict_types::SemId; - -use super::{ - AssignmentType, ExtensionSchema, GenesisSchema, OwnedStateSchema, TransitionSchema, ValencyType, -}; -use crate::{ - impl_serde_baid64, Ffv, GlobalStateSchema, Identity, Occurrences, LIB_NAME_RGB_COMMIT, -}; - -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] -#[wrapper(FromStr, LowerHex, UpperHex)] -#[display("0x{0:04X}")] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct MetaType(u16); -impl MetaType { - pub const fn with(ty: u16) -> Self { Self(ty) } -} - -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] -#[wrapper(FromStr, LowerHex, UpperHex)] -#[display("0x{0:04X}")] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct GlobalStateType(u16); -impl GlobalStateType { - pub const fn with(ty: u16) -> Self { Self(ty) } -} - -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] -#[wrapper(FromStr, LowerHex, UpperHex)] -#[display("0x{0:04X}")] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ExtensionType(u16); -impl ExtensionType { - pub const fn with(ty: u16) -> Self { Self(ty) } -} - -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] -#[wrapper(FromStr, LowerHex, UpperHex)] -#[display("0x{0:04X}")] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct TransitionType(u16); -impl TransitionType { - pub const fn with(ty: u16) -> Self { Self(ty) } -} - -impl TransitionType { - pub const BLANK: Self = TransitionType(u16::MAX); - /// Easily check if the TransitionType is blank with convention method - pub fn is_blank(self) -> bool { self == Self::BLANK } -} - -/// Schema identifier. -/// -/// Schema identifier commits to all the schema data. -#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] -#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -pub struct SchemaId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl From for SchemaId { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for SchemaId { - const TAG: &'static str = "urn:lnp-bp:rgb:schema#2024-02-03"; -} - -impl DisplayBaid64 for SchemaId { - const HRI: &'static str = "rgb:sch"; - const CHUNKING: bool = false; - const PREFIX: bool = true; - const EMBED_CHECKSUM: bool = false; - const MNEMONIC: bool = true; - fn to_baid64_payload(&self) -> [u8; 32] { self.to_byte_array() } -} -impl FromBaid64Str for SchemaId {} -impl FromStr for SchemaId { - type Err = Baid64ParseError; - fn from_str(s: &str) -> Result { Self::from_baid64_str(s) } -} -impl Display for SchemaId { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) } -} - -impl_serde_baid64!(SchemaId); - -#[derive(Clone, Eq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Schema { - pub ffv: Ffv, - pub flags: ReservedBytes<1, 0>, - - pub name: TypeName, - pub timestamp: i64, - pub developer: Identity, - - pub meta_types: TinyOrdMap, - pub global_types: TinyOrdMap, - pub owned_types: TinyOrdMap, - pub valency_types: TinyOrdSet, - pub genesis: GenesisSchema, - pub extensions: TinyOrdMap, - pub transitions: TinyOrdMap, - - pub reserved: ReservedBytes<8, 0>, -} - -impl CommitEncode for Schema { - type CommitmentId = SchemaId; - - fn commit_encode(&self, e: &mut CommitEngine) { - e.commit_to_serialized(&self.ffv); - e.commit_to_serialized(&self.flags); - - e.commit_to_serialized(&self.name); - e.commit_to_serialized(&self.timestamp); - e.commit_to_serialized(&self.developer); - - e.commit_to_map(&self.meta_types); - e.commit_to_map(&self.global_types); - e.commit_to_map(&self.owned_types); - e.commit_to_set(&self.valency_types); - e.commit_to_serialized(&self.genesis); - e.commit_to_map(&self.extensions); - e.commit_to_map(&self.transitions); - - e.commit_to_serialized(&self.reserved); - } -} - -impl PartialEq for Schema { - fn eq(&self, other: &Self) -> bool { self.schema_id() == other.schema_id() } -} - -impl Ord for Schema { - fn cmp(&self, other: &Self) -> Ordering { self.schema_id().cmp(&other.schema_id()) } -} - -impl PartialOrd for Schema { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl StrictSerialize for Schema {} -impl StrictDeserialize for Schema {} - -impl Schema { - #[inline] - pub fn schema_id(&self) -> SchemaId { self.commit_id() } - - pub fn blank_transition(&self) -> TransitionSchema { - let mut schema = TransitionSchema::default(); - for id in self.owned_types.keys() { - schema.inputs.insert(*id, Occurrences::NoneOrMore).ok(); - schema.assignments.insert(*id, Occurrences::NoneOrMore).ok(); - } - schema - } - - pub fn types(&self) -> impl Iterator + '_ { - self.meta_types - .values() - .copied() - .chain(self.global_types.values().map(|i| i.sem_id)) - .chain( - self.owned_types - .values() - .filter_map(OwnedStateSchema::sem_id), - ) - } - - pub fn libs(&self) -> impl Iterator + '_ { - self.genesis - .validator - .iter() - .copied() - .chain(self.transitions.values().filter_map(|i| i.validator)) - .chain(self.extensions.values().filter_map(|i| i.validator)) - .map(|site| site.lib) - } -} - -#[cfg(test)] -mod test { - use strict_encoding::StrictDumb; - - use super::*; - - #[test] - fn display() { - let dumb = SchemaId::strict_dumb(); - assert_eq!( - dumb.to_string(), - "rgb:sch:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#distant-history-exotic" - ); - assert_eq!( - &format!("{dumb:-}"), - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#distant-history-exotic" - ); - - let less_dumb = SchemaId::from_byte_array(*b"EV4350-'4vwj'4;v-w94w'e'vFVVDhpq"); - assert_eq!( - less_dumb.to_string(), - "rgb:sch:RVY0MzUwLSc0dndqJzQ7di13OTR3J2UndkZWVkRocHE#lemon-diamond-cartoon" - ); - assert_eq!( - &format!("{less_dumb:-}"), - "RVY0MzUwLSc0dndqJzQ7di13OTR3J2UndkZWVkRocHE#lemon-diamond-cartoon" - ); - assert_eq!( - &format!("{less_dumb:#}"), - "rgb:sch:RVY0MzUwLSc0dndqJzQ7di13OTR3J2UndkZWVkRocHE" - ); - assert_eq!(&format!("{less_dumb:-#}"), "RVY0MzUwLSc0dndqJzQ7di13OTR3J2UndkZWVkRocHE"); - } -} diff --git a/src/schema/state.rs b/src/schema/state.rs deleted file mode 100644 index 27db9a15..00000000 --- a/src/schema/state.rs +++ /dev/null @@ -1,145 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use amplify::num::u24; -use commit_verify::ReservedBytes; -use strict_encoding::Primitive; -use strict_types::SemId; - -use crate::{StateType, LIB_NAME_RGB_COMMIT}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", tag = "type") -)] -#[non_exhaustive] -#[repr(u8)] -pub enum MediaType { - #[display("*/*")] - #[strict_type(dumb)] - Any = 0xFF, - // TODO: Complete MIME type implementation -} - -impl MediaType { - pub fn conforms(&self, other: &MediaType) -> bool { - match (self, other) { - (MediaType::Any, MediaType::Any) => true, - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = order)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum OwnedStateSchema { - #[strict_type(dumb)] - Declarative, - Fungible(FungibleType), - Structured(SemId), - Attachment(MediaType), - // TODO: Computed state (RCP240327A) will be added here -} - -impl OwnedStateSchema { - pub fn state_type(&self) -> StateType { - match self { - OwnedStateSchema::Declarative => StateType::Void, - OwnedStateSchema::Fungible(_) => StateType::Fungible, - OwnedStateSchema::Structured(_) => StateType::Structured, - OwnedStateSchema::Attachment(_) => StateType::Attachment, - } - } - - pub fn sem_id(&self) -> Option { - if let Self::Structured(id) = self { - Some(*id) - } else { - None - } - } -} - -/// Today we support only a single format of confidential data, because of the -/// limitations of the underlying secp256k1-zkp library: it works only with -/// u64 numbers. Nevertheless, homomorphic commitments can be created to -/// everything that has up to 256 bits and commutative arithmetics, so in the -/// future we plan to support more types. We reserve this possibility by -/// internally encoding [`ConfidentialFormat`] with the same type specification -/// details as used for [`DateFormat`] -#[derive(Copy, Clone, PartialEq, Eq, Debug, Default, Display)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -pub enum FungibleType { - #[default] - #[display("64bit")] - Unsigned64Bit = Primitive::U64.into_code(), -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_COMMIT)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct GlobalStateSchema { - // TODO: Reserved for computed state (RCP240327A): will be used as an enum tag with computed - // state having value 1. - pub reserved: ReservedBytes<1>, - pub sem_id: SemId, - pub max_items: u24, -} - -impl GlobalStateSchema { - pub fn once(sem_id: SemId) -> Self { - GlobalStateSchema { - reserved: default!(), - sem_id, - max_items: u24::ONE, - } - } - - pub fn many(sem_id: SemId) -> Self { - GlobalStateSchema { - reserved: default!(), - sem_id, - max_items: u24::MAX, - } - } -} diff --git a/src/seals.rs b/src/seals.rs new file mode 100644 index 00000000..d6990ec9 --- /dev/null +++ b/src/seals.rs @@ -0,0 +1,104 @@ +// RGB Core Library: consensus layer for RGB smart contracts. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed under the License +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +// or implied. See the License for the specific language governing permissions and limitations under +// the License. + +use core::fmt::{Debug, Display}; + +use single_use_seals::{PublishedWitness, SingleUseSeal}; +use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; +use ultrasonic::AuthToken; + +pub trait RgbSealDef: Clone + Eq + Debug + Display + StrictDumb + StrictEncode + StrictDecode { + type Src: RgbSealSrc; + fn auth_token(&self) -> AuthToken; + fn resolve( + &self, + witness_id: <::PubWitness as PublishedWitness>::PubId, + ) -> Self::Src; + fn to_src(&self) -> Option; +} + +pub trait RgbSealSrc: SingleUseSeal> + Ord {} + +// Below are capabilities constants used in the standard library: + +#[cfg(any(feature = "bitcoin", feature = "liquid"))] +pub mod bitcoin { + use bp::seals::{TxoSeal, WOutpoint, WTxoSeal}; + use bp::Outpoint; + use commit_verify::CommitId; + + use super::*; + + impl RgbSealSrc for TxoSeal {} + + impl RgbSealDef for WTxoSeal { + type Src = TxoSeal; + + // SECURITY: Here we cut SHA256 tagged hash of a single-use seal definition to 30 bytes in order + // to fit it into a field element with no overflows. This must be a secure operation since we + // still have a sufficient 120-bit collision resistance. + fn auth_token(&self) -> AuthToken { + let id = self.commit_id().to_byte_array(); + let mut shortened_id = [0u8; 30]; + shortened_id.copy_from_slice(&id[0..30]); + AuthToken::from_byte_array(shortened_id) + } + + fn resolve( + &self, + witness_id: <::PubWitness as PublishedWitness>::PubId, + ) -> Self::Src { + let primary = match self.primary { + WOutpoint::Wout(wout) => Outpoint::new(witness_id, wout), + WOutpoint::Extern(outpoint) => outpoint, + }; + TxoSeal { primary, secondary: self.secondary } + } + + fn to_src(&self) -> Option { + let primary = match self.primary { + WOutpoint::Wout(_) => return None, + WOutpoint::Extern(outpoint) => outpoint, + }; + Some(TxoSeal { primary, secondary: self.secondary }) + } + } +} + +#[cfg(test)] +mod tests { + use bp::seals::{TxoSealExt, WOutpoint, WTxoSeal}; + use bp::Outpoint; + + use super::*; + + #[test] + fn auth_token() { + let seal = WTxoSeal { + primary: WOutpoint::Wout(0u32.into()), + secondary: TxoSealExt::Fallback(Outpoint::coinbase()), + }; + assert_eq!(seal.auth_token().to_string(), "at:lIIfSD7P-RQi0r3kA-7gZdmE7Q-S66QSwzG-NCxNnh7V-225u4Q"); + } +} diff --git a/src/stl.rs b/src/stl.rs deleted file mode 100644 index bbc97c6f..00000000 --- a/src/stl.rs +++ /dev/null @@ -1,105 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -pub use aluvm::stl::aluvm_stl; -pub use bp::bc::stl::bp_tx_stl; -pub use bp::stl::bp_core_stl; -use commit_verify::stl::commit_verify_stl; -use strict_types::stl::{std_stl, strict_types_stl}; -use strict_types::typelib::LibBuilder; -use strict_types::{CompileError, TypeLib}; - -use crate::validation::DbcProof; -use crate::vm::{GlobalOrd, XWitnessId}; -use crate::{ - Extension, Genesis, OpCommitment, Schema, TransitionBundle, LIB_NAME_RGB_COMMIT, - LIB_NAME_RGB_LOGIC, -}; - -/// Strict types id for the library providing data types for RGB consensus. -pub const LIB_ID_RGB_COMMIT: &str = - "stl:IFcnrPeI-TANxLfZ-feJax6Q-1TUM4Hq-AjI161s-3tbmxak#harvest-person-orion"; -/// Strict types id for the library providing data types for RGB consensus. -pub const LIB_ID_RGB_LOGIC: &str = - "stl:mqltqlPk-O9$pYOd-BACRI70-DOMJ6cp-TFvhcK1-ibrOI9U#import-boxer-seminar"; - -fn _rgb_commit_stl() -> Result { - LibBuilder::new(libname!(LIB_NAME_RGB_COMMIT), tiny_bset! { - std_stl().to_dependency(), - strict_types_stl().to_dependency(), - commit_verify_stl().to_dependency(), - bp_tx_stl().to_dependency(), - bp_core_stl().to_dependency(), - aluvm_stl().to_dependency() - }) - .transpile::() - .transpile::() - .transpile::() - .transpile::() - .transpile::() - .transpile::() - .compile() -} - -fn _rgb_logic_stl() -> Result { - LibBuilder::new(libname!(LIB_NAME_RGB_LOGIC), tiny_bset! { - std_stl().to_dependency(), - strict_types_stl().to_dependency(), - commit_verify_stl().to_dependency(), - bp_tx_stl().to_dependency(), - bp_core_stl().to_dependency(), - aluvm_stl().to_dependency(), - rgb_commit_stl().to_dependency() - }) - .transpile::() - .transpile::() - // TODO: Commit to the RGB ISA once AluVM will support strict types - // .transpile::() - .compile() -} - -/// Generates strict type library providing data types for RGB consensus. -pub fn rgb_commit_stl() -> TypeLib { - _rgb_commit_stl().expect("invalid strict type RGB consensus commitments library") -} - -/// Generates strict type library providing data types for RGB consensus. -pub fn rgb_logic_stl() -> TypeLib { - _rgb_logic_stl().expect("invalid strict type RGB consensus logic library") -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn commit_lib_id() { - let lib = rgb_commit_stl(); - assert_eq!(lib.id().to_string(), LIB_ID_RGB_COMMIT); - } - - #[test] - fn logic_lib_id() { - let lib = rgb_logic_stl(); - assert_eq!(lib.id().to_string(), LIB_ID_RGB_LOGIC); - } -} diff --git a/src/validation/commitments.rs b/src/validation/commitments.rs deleted file mode 100644 index 6ca98014..00000000 --- a/src/validation/commitments.rs +++ /dev/null @@ -1,120 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use bp::dbc::opret::{OpretError, OpretProof}; -use bp::dbc::tapret::TapretProof; -use bp::dbc::Method; -use bp::{dbc, Tx}; -use commit_verify::mpc::Commitment; -use commit_verify::{mpc, ConvolveVerifyError, EmbedVerifyError}; -use strict_encoding::{StrictDeserialize, StrictDumb, StrictSerialize}; - -use crate::LIB_NAME_RGB_LOGIC; - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display(doc_comments)] -pub enum DbcError { - /// transaction doesn't contain OP_RETURN output. - NoOpretOutput, - - /// first OP_RETURN output inside the transaction already contains some - /// data. - InvalidOpretScript, - - /// commitment doesn't match the message. - CommitmentMismatch, - - /// the proof is invalid and the commitment can't be verified since the - /// original container can't be restored from it. - UnrestorableProof, - - /// the proof does not match to the proof generated for the same message - /// during the verification. - ProofMismatch, - - /// the message is invalid since a valid commitment to it can't be created. - ImpossibleMessage, - - /// the proof is invalid and the commitment can't be verified. - InvalidProof, -} - -#[derive(Clone, Eq, PartialEq, Debug, From)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_LOGIC, tags = custom, dumb = Self::Tapret(strict_dumb!()))] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase", untagged) -)] -pub enum DbcProof { - #[from] - #[strict_type(tag = 0x01)] - Tapret(TapretProof), - - #[from] - #[strict_type(tag = 0x02)] - Opret(OpretProof), -} - -impl StrictSerialize for DbcProof {} -impl StrictDeserialize for DbcProof {} - -impl dbc::Proof for DbcProof { - type Error = DbcError; - - fn method(&self) -> Method { - match self { - DbcProof::Tapret(_) => Method::TapretFirst, - DbcProof::Opret(_) => Method::OpretFirst, - } - } - - fn verify(&self, msg: &Commitment, tx: &Tx) -> Result<(), Self::Error> { - match self { - DbcProof::Tapret(tapret) => tapret.verify(msg, tx).map_err(|err| match err { - ConvolveVerifyError::CommitmentMismatch => DbcError::CommitmentMismatch, - ConvolveVerifyError::ImpossibleMessage => DbcError::ImpossibleMessage, - ConvolveVerifyError::InvalidProof => DbcError::InvalidProof, - }), - DbcProof::Opret(opret) => opret.verify(msg, tx).map_err(|err| match err { - EmbedVerifyError::CommitmentMismatch => DbcError::CommitmentMismatch, - EmbedVerifyError::InvalidMessage(OpretError::NoOpretOutput) => { - DbcError::NoOpretOutput - } - EmbedVerifyError::InvalidMessage(OpretError::InvalidOpretScript) => { - DbcError::InvalidOpretScript - } - EmbedVerifyError::InvalidProof => DbcError::UnrestorableProof, - EmbedVerifyError::ProofMismatch => DbcError::ProofMismatch, - }), - } - } -} - -/// Anchor which DBC proof is either Tapret or Opret. -pub type EAnchor

= dbc::Anchor; diff --git a/src/validation/consignment.rs b/src/validation/consignment.rs deleted file mode 100644 index 9499d2e1..00000000 --- a/src/validation/consignment.rs +++ /dev/null @@ -1,231 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Common API for accessing RGB contract operation graph, including individual -//! state transitions, extensions, genesis, outputs, assignments & -//! single-use-seal data. - -use std::collections::BTreeMap; - -use aluvm::library::{Lib, LibId}; -use amplify::confinement::Confined; -use strict_types::TypeSystem; - -use super::EAnchor; -use crate::vm::XWitnessId; -use crate::{ - AssignmentType, AssignmentsRef, BundleId, ContractId, Extension, ExtensionType, Genesis, - GlobalState, GraphSeal, Inputs, Metadata, OpFullType, OpId, OpType, Operation, Schema, - Transition, TransitionBundle, TransitionType, TypedAssigns, Valencies, -}; - -pub const CONSIGNMENT_MAX_LIBS: usize = 1024; - -pub type Scripts = Confined, 0, CONSIGNMENT_MAX_LIBS>; - -#[derive(Copy, Clone, PartialEq, Eq, Debug, From)] -pub enum OpRef<'op> { - #[from] - Genesis(&'op Genesis), - #[from] - Transition(&'op Transition), - #[from] - Extension(&'op Extension), -} - -impl<'op> Operation for OpRef<'op> { - fn op_type(&self) -> OpType { - match self { - Self::Genesis(op) => op.op_type(), - Self::Transition(op) => op.op_type(), - Self::Extension(op) => op.op_type(), - } - } - - fn full_type(&self) -> OpFullType { - match self { - Self::Genesis(op) => op.full_type(), - Self::Transition(op) => op.full_type(), - Self::Extension(op) => op.full_type(), - } - } - - fn id(&self) -> OpId { - match self { - Self::Genesis(op) => op.id(), - Self::Transition(op) => op.id(), - Self::Extension(op) => op.id(), - } - } - - fn contract_id(&self) -> ContractId { - match self { - Self::Genesis(op) => op.contract_id(), - Self::Transition(op) => op.contract_id(), - Self::Extension(op) => op.contract_id(), - } - } - - fn nonce(&self) -> u64 { - match self { - Self::Genesis(op) => op.nonce(), - Self::Transition(op) => op.nonce(), - Self::Extension(op) => op.nonce(), - } - } - - fn transition_type(&self) -> Option { - match self { - Self::Genesis(op) => op.transition_type(), - Self::Transition(op) => op.transition_type(), - Self::Extension(op) => op.transition_type(), - } - } - - fn extension_type(&self) -> Option { - match self { - Self::Genesis(op) => op.extension_type(), - Self::Transition(op) => op.extension_type(), - Self::Extension(op) => op.extension_type(), - } - } - - fn metadata(&self) -> &Metadata { - match self { - Self::Genesis(op) => op.metadata(), - Self::Transition(op) => op.metadata(), - Self::Extension(op) => op.metadata(), - } - } - - fn globals(&self) -> &GlobalState { - match self { - Self::Genesis(op) => op.globals(), - Self::Transition(op) => op.globals(), - Self::Extension(op) => op.globals(), - } - } - - fn valencies(&self) -> &Valencies { - match self { - Self::Genesis(op) => op.valencies(), - Self::Transition(op) => op.valencies(), - Self::Extension(op) => op.valencies(), - } - } - - fn assignments(&self) -> AssignmentsRef<'op> { - match self { - Self::Genesis(op) => (&op.assignments).into(), - Self::Transition(op) => (&op.assignments).into(), - Self::Extension(op) => (&op.assignments).into(), - } - } - - fn assignments_by_type(&self, t: AssignmentType) -> Option> { - match self { - Self::Genesis(op) => op.assignments_by_type(t), - Self::Transition(op) => op.assignments_by_type(t), - Self::Extension(op) => op.assignments_by_type(t), - } - } - - fn inputs(&self) -> Inputs { - match self { - Self::Genesis(op) => op.inputs(), - Self::Transition(op) => op.inputs(), - Self::Extension(op) => op.inputs(), - } - } -} - -pub struct CheckedConsignment<'consignment, C: ConsignmentApi>(&'consignment C); - -impl<'consignment, C: ConsignmentApi> CheckedConsignment<'consignment, C> { - pub fn new(consignment: &'consignment C) -> Self { Self(consignment) } -} - -impl<'consignment, C: ConsignmentApi> ConsignmentApi for CheckedConsignment<'consignment, C> { - fn schema(&self) -> &Schema { self.0.schema() } - - fn types(&self) -> &TypeSystem { self.0.types() } - - fn scripts(&self) -> &Scripts { self.0.scripts() } - - fn operation(&self, opid: OpId) -> Option { - self.0.operation(opid).filter(|op| op.id() == opid) - } - - fn genesis(&self) -> &Genesis { self.0.genesis() } - - fn bundle_ids<'iter>(&self) -> impl Iterator + 'iter { self.0.bundle_ids() } - - fn bundle(&self, bundle_id: BundleId) -> Option<&TransitionBundle> { - self.0 - .bundle(bundle_id) - .filter(|b| b.bundle_id() == bundle_id) - } - - fn anchor(&self, bundle_id: BundleId) -> Option<(XWitnessId, &EAnchor)> { - self.0.anchor(bundle_id) - } - - fn op_witness_id(&self, opid: OpId) -> Option { self.0.op_witness_id(opid) } -} - -/// Trait defining common data access API for all storage-related RGB structures -/// -/// The API provided for the consignment should not verify the internal -/// consistency, schema conformance or validation status of the RGB contract -/// data within the storage or container. If the methods are called on an -/// invalid or absent data, the API must always return [`None`] or empty -/// collections/iterators. -pub trait ConsignmentApi { - /// Returns reference to the schema object used by the consignment. - fn schema(&self) -> &Schema; - - /// Returns reference to the type system. - fn types(&self) -> &TypeSystem; - - /// Returns reference to a collection of AluVM libraries used for the - /// validation. - fn scripts(&self) -> &Scripts; - - /// Retrieves reference to an operation (genesis, state transition or state - /// extension) matching the provided id, or `None` otherwise - fn operation(&self, opid: OpId) -> Option; - - /// Contract genesis. - fn genesis(&self) -> &Genesis; - - /// Returns iterator over all bundle ids present in the consignment. - fn bundle_ids<'iter>(&self) -> impl Iterator + 'iter; - - /// Returns reference to a bundle given a bundle id. - fn bundle(&self, bundle_id: BundleId) -> Option<&TransitionBundle>; - - /// Returns a grip given a bundle id. - fn anchor(&self, bundle_id: BundleId) -> Option<(XWitnessId, &EAnchor)>; - - /// Returns witness id for a given operation. - fn op_witness_id(&self, opid: OpId) -> Option; -} diff --git a/src/validation/logic.rs b/src/validation/logic.rs deleted file mode 100644 index 0afd7f93..00000000 --- a/src/validation/logic.rs +++ /dev/null @@ -1,667 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::cell::RefCell; -use std::collections::BTreeSet; -use std::rc::Rc; - -use aluvm::data::Number; -use aluvm::isa::Instr; -use aluvm::reg::{Reg32, RegA}; -use aluvm::Vm; -use amplify::confinement::Confined; -use amplify::Wrapper; -use strict_types::TypeSystem; - -use crate::schema::{AssignmentsSchema, GlobalSchema, ValencySchema}; -use crate::validation::{CheckedConsignment, ConsignmentApi}; -use crate::vm::{ContractStateAccess, ContractStateEvolve, OpInfo, OrdOpRef, RgbIsa, VmContext}; -use crate::{ - validation, Assign, AssignmentType, Assignments, AssignmentsRef, ConcealedState, - ConfidentialState, ExposedSeal, ExposedState, Extension, GlobalState, GlobalStateSchema, - GlobalValues, GraphSeal, Inputs, MetaSchema, Metadata, OpId, Operation, Opout, - OwnedStateSchema, RevealedState, Schema, StateType, Transition, TypedAssigns, Valencies, -}; - -impl Schema { - pub fn validate_state< - 'validator, - C: ConsignmentApi, - S: ContractStateAccess + ContractStateEvolve, - >( - &'validator self, - consignment: &'validator CheckedConsignment<'_, C>, - op: OrdOpRef, - contract_state: Rc>, - ) -> validation::Status { - let opid = op.id(); - let mut status = validation::Status::new(); - - let empty_assign_schema = AssignmentsSchema::default(); - let empty_valency_schema = ValencySchema::default(); - let blank_transition = self.blank_transition(); - let ( - metadata_schema, - global_schema, - owned_schema, - redeem_schema, - assign_schema, - valency_schema, - validator, - ty, - ) = match op { - OrdOpRef::Genesis(genesis) => { - for id in genesis.asset_tags.keys() { - if !matches!(self.owned_types.get(id), Some(OwnedStateSchema::Fungible(_))) { - status.add_failure(validation::Failure::AssetTagNoState(*id)); - } - } - for (id, ss) in &self.owned_types { - if ss.state_type() == StateType::Fungible - && !genesis.asset_tags.contains_key(id) - { - status.add_failure(validation::Failure::FungibleStateNoTag(*id)); - } - } - - ( - &self.genesis.metadata, - &self.genesis.globals, - &empty_assign_schema, - &empty_valency_schema, - &self.genesis.assignments, - &self.genesis.valencies, - self.genesis.validator, - None::, - ) - } - OrdOpRef::Transition( - Transition { - transition_type, .. - }, - .., - ) => { - // Right now we do not have actions to implement; but later - // we may have embedded procedures which must be verified - // here - /* - if let Some(procedure) = transition_type.abi.get(&TransitionAction::NoOp) { - - } - */ - - let transition_schema = match self.transitions.get(transition_type) { - None if transition_type.is_blank() => &blank_transition, - None => { - return validation::Status::with_failure( - validation::Failure::SchemaUnknownTransitionType( - opid, - *transition_type, - ), - ); - } - Some(transition_schema) => transition_schema, - }; - - ( - &transition_schema.metadata, - &transition_schema.globals, - &transition_schema.inputs, - &empty_valency_schema, - &transition_schema.assignments, - &transition_schema.valencies, - transition_schema.validator, - Some(transition_type.into_inner()), - ) - } - OrdOpRef::Extension(Extension { extension_type, .. }, ..) => { - // Right now we do not have actions to implement; but later - // we may have embedded procedures which must be verified - // here - /* - if let Some(procedure) = extension_type.abi.get(&ExtensionAction::NoOp) { - - } - */ - - let extension_schema = match self.extensions.get(extension_type) { - None => { - return validation::Status::with_failure( - validation::Failure::SchemaUnknownExtensionType(opid, *extension_type), - ); - } - Some(extension_schema) => extension_schema, - }; - - ( - &extension_schema.metadata, - &extension_schema.globals, - &empty_assign_schema, - &extension_schema.redeems, - &extension_schema.assignments, - &extension_schema.redeems, - extension_schema.validator, - Some(extension_type.into_inner()), - ) - } - }; - - // Validate type system - status += self.validate_type_system(); - status += self.validate_metadata(opid, op.metadata(), metadata_schema, consignment.types()); - status += - self.validate_global_state(opid, op.globals(), global_schema, consignment.types()); - let prev_state = if let OrdOpRef::Transition(transition, ..) = op { - let prev_state = extract_prev_state(consignment, opid, &transition.inputs, &mut status); - status += self.validate_prev_state(opid, &prev_state, owned_schema); - prev_state - } else { - Assignments::default() - }; - let mut redeemed = Valencies::default(); - if let OrdOpRef::Extension(extension, ..) = op { - for valency in extension.redeemed.keys() { - redeemed.push(*valency).expect("same size"); - } - status += self.validate_redeemed(opid, &redeemed, redeem_schema); - } - status += match op.assignments() { - AssignmentsRef::Genesis(assignments) => { - self.validate_owned_state(opid, assignments, assign_schema, consignment.types()) - } - AssignmentsRef::Graph(assignments) => { - self.validate_owned_state(opid, assignments, assign_schema, consignment.types()) - } - }; - - status += self.validate_valencies(opid, op.valencies(), valency_schema); - - let genesis = consignment.genesis(); - let op_info = OpInfo::with(opid, &op, &prev_state, &redeemed); - let context = VmContext { - contract_id: genesis.contract_id(), - asset_tags: &genesis.asset_tags, - op_info, - contract_state, - }; - - // We need to run scripts as the very last step, since before that - // we need to make sure that the operation data match the schema, so - // scripts are not required to validate the structure of the state - if let Some(validator) = validator { - let scripts = consignment.scripts(); - let mut vm = Vm::>>::new(); - if let Some(ty) = ty { - vm.registers.set_n(RegA::A16, Reg32::Reg0, ty); - } - if !vm.exec(validator, |id| scripts.get(&id), &context) { - let error_code: Option = vm.registers.get_n(RegA::A8, Reg32::Reg0).into(); - status.add_failure(validation::Failure::ScriptFailure( - opid, - error_code.map(u8::from), - None, - )); - // We return here since all other validations will have no valid state to access - return status; - } - let contract_state = context.contract_state; - if contract_state.borrow_mut().evolve_state(op).is_err() { - status.add_failure(validation::Failure::ContractStateFilled(opid)); - // We return here since all other validations will have no valid state to access - return status; - } - } - status - } - - fn validate_type_system(&self) -> validation::Status { - validation::Status::new() - // TODO: Validate type system - // Currently, validation is performed at the level of state values, i.e. - // if the system is inconsistent (references semantic ids not - // present in it) this will be detected during state validation. - // We should not prohibit schema with inconsistent type system, instead - // we need just to issue warnings here if some of semantic ids are - // missed - and add information messages if some excessive semantic ids - // are present. - } - - fn validate_metadata( - &self, - opid: OpId, - metadata: &Metadata, - metadata_schema: &MetaSchema, - types: &TypeSystem, - ) -> validation::Status { - let mut status = validation::Status::new(); - - metadata - .keys() - .copied() - .collect::>() - .difference(metadata_schema.as_unconfined()) - .for_each(|type_id| { - status.add_failure(validation::Failure::SchemaUnknownMetaType(opid, *type_id)); - }); - - for type_id in metadata_schema { - let Some(value) = metadata.get(type_id) else { - status.add_failure(validation::Failure::SchemaNoMetadata(opid, *type_id)); - continue; - }; - - let sem_id = self.meta_types.get(type_id).expect( - "if this metadata type were absent, the schema would not be able to pass the \ - internal validation and we would not reach this point", - ); - - if types - .strict_deserialize_type(*sem_id, value.as_ref()) - .is_err() - { - status.add_failure(validation::Failure::SchemaInvalidMetadata(opid, *sem_id)); - }; - } - - status - } - - fn validate_global_state( - &self, - opid: OpId, - global: &GlobalState, - global_schema: &GlobalSchema, - types: &TypeSystem, - ) -> validation::Status { - let mut status = validation::Status::new(); - - global - .keys() - .collect::>() - .difference(&global_schema.keys().collect()) - .for_each(|field_id| { - status.add_failure(validation::Failure::SchemaUnknownGlobalStateType( - opid, **field_id, - )); - }); - - for (type_id, occ) in global_schema { - let set = global - .get(type_id) - .cloned() - .map(GlobalValues::into_inner) - .map(Confined::release) - .unwrap_or_default(); - - let GlobalStateSchema { - sem_id, - max_items, - reserved: _, - } = self.global_types.get(type_id).expect( - "if the field were absent, the schema would not be able to pass the internal \ - validation and we would not reach this point", - ); - - // Checking number of field occurrences - let count = set.len() as u16; - if let Err(err) = occ.check(count) { - status.add_failure(validation::Failure::SchemaGlobalStateOccurrences( - opid, *type_id, err, - )); - } - if count as u32 > max_items.to_u32() { - status.add_failure(validation::Failure::SchemaGlobalStateLimit( - opid, *type_id, count, *max_items, - )); - } - - // Validating data types - for data in set { - if types - .strict_deserialize_type(*sem_id, data.as_ref()) - .is_err() - { - status.add_failure(validation::Failure::SchemaInvalidGlobalValue( - opid, *type_id, *sem_id, - )); - }; - } - } - - status - } - - fn validate_prev_state( - &self, - id: OpId, - owned_state: &Assignments, - assign_schema: &AssignmentsSchema, - ) -> validation::Status { - let mut status = validation::Status::new(); - - owned_state - .keys() - .collect::>() - .difference(&assign_schema.keys().collect()) - .for_each(|owned_type_id| { - status.add_failure(validation::Failure::SchemaUnknownAssignmentType( - id, - **owned_type_id, - )); - }); - - for (owned_type_id, occ) in assign_schema { - let len = owned_state - .get(owned_type_id) - .map(TypedAssigns::len_u16) - .unwrap_or(0); - - // Checking number of ancestor's assignment occurrences - if let Err(err) = occ.check(len) { - status.add_failure(validation::Failure::SchemaInputOccurrences( - id, - *owned_type_id, - err, - )); - } - } - - status - } - - fn validate_redeemed( - &self, - id: OpId, - valencies: &Valencies, - valency_schema: &ValencySchema, - ) -> validation::Status { - let mut status = validation::Status::new(); - - valencies - .difference(valency_schema) - .for_each(|public_type_id| { - status.add_failure(validation::Failure::SchemaUnknownValencyType( - id, - *public_type_id, - )); - }); - - status - } - - fn validate_owned_state( - &self, - id: OpId, - owned_state: &Assignments, - assign_schema: &AssignmentsSchema, - types: &TypeSystem, - ) -> validation::Status { - let mut status = validation::Status::new(); - - owned_state - .keys() - .collect::>() - .difference(&assign_schema.keys().collect()) - .for_each(|assignment_type_id| { - status.add_failure(validation::Failure::SchemaUnknownAssignmentType( - id, - **assignment_type_id, - )); - }); - - for (state_id, occ) in assign_schema { - let len = owned_state - .get(state_id) - .map(TypedAssigns::len_u16) - .unwrap_or(0); - - // Checking number of assignment occurrences - if let Err(err) = occ.check(len) { - status.add_failure(validation::Failure::SchemaAssignmentOccurrences( - id, *state_id, err, - )); - } - - let assignment = &self.owned_types.get(state_id).expect( - "If the assignment were absent, the schema would not be able to pass the internal \ - validation and we would not reach this point", - ); - - match owned_state.get(state_id) { - None => {} - Some(TypedAssigns::Declarative(set)) => set - .iter() - .for_each(|data| status += assignment.validate(id, *state_id, data, types)), - Some(TypedAssigns::Fungible(set)) => set - .iter() - .for_each(|data| status += assignment.validate(id, *state_id, data, types)), - Some(TypedAssigns::Structured(set)) => set - .iter() - .for_each(|data| status += assignment.validate(id, *state_id, data, types)), - Some(TypedAssigns::Attachment(set)) => set - .iter() - .for_each(|data| status += assignment.validate(id, *state_id, data, types)), - }; - } - - status - } - - fn validate_valencies( - &self, - id: OpId, - valencies: &Valencies, - valency_schema: &ValencySchema, - ) -> validation::Status { - let mut status = validation::Status::new(); - - valencies - .difference(valency_schema) - .for_each(|public_type_id| { - status.add_failure(validation::Failure::SchemaUnknownValencyType( - id, - *public_type_id, - )); - }); - - status - } -} - -fn extract_prev_state( - consignment: &C, - opid: OpId, - inputs: &Inputs, - status: &mut validation::Status, -) -> Assignments { - let mut assignments = bmap! {}; - for input in inputs { - let Opout { op, ty, no } = input.prev_out; - - let prev_op = match consignment.operation(op) { - None => { - status.add_failure(validation::Failure::OperationAbsent(op)); - continue; - } - Some(op) => op, - }; - - let no = no as usize; - match prev_op.assignments_by_type(ty) { - Some(TypedAssigns::Declarative(prev_assignments)) => { - if let Some(prev_assign) = prev_assignments.get(no) { - if let Some(typed_assigns) = assignments - .entry(ty) - .or_insert_with(|| TypedAssigns::Declarative(Default::default())) - .as_declarative_mut() - { - typed_assigns.push(prev_assign.clone()).expect("same size"); - } - } else { - status.add_failure(validation::Failure::NoPrevOut(opid, input.prev_out)); - } - } - Some(TypedAssigns::Fungible(prev_assignments)) => { - if let Some(prev_assign) = prev_assignments.get(no) { - if let Some(typed_assigns) = assignments - .entry(ty) - .or_insert_with(|| TypedAssigns::Fungible(Default::default())) - .as_fungible_mut() - { - typed_assigns.push(prev_assign.clone()).expect("same size"); - } - } else { - status.add_failure(validation::Failure::NoPrevOut(opid, input.prev_out)); - } - } - Some(TypedAssigns::Structured(prev_assignments)) => { - if let Some(prev_assign) = prev_assignments.get(no) { - if let Some(typed_assigns) = assignments - .entry(ty) - .or_insert_with(|| TypedAssigns::Structured(Default::default())) - .as_structured_mut() - { - typed_assigns.push(prev_assign.clone()).expect("same size"); - } - } else { - status.add_failure(validation::Failure::NoPrevOut(opid, input.prev_out)); - } - } - Some(TypedAssigns::Attachment(prev_assignments)) => { - if let Some(prev_assign) = prev_assignments.get(no) { - if let Some(typed_assigns) = assignments - .entry(ty) - .or_insert_with(|| TypedAssigns::Attachment(Default::default())) - .as_attachment_mut() - { - typed_assigns.push(prev_assign.clone()).expect("same size"); - } - } else { - status.add_failure(validation::Failure::NoPrevOut(opid, input.prev_out)); - } - } - None => { - // Presence of the required owned rights type in the - // parent operation was already validated; we have nothing - // to report here - } - } - } - Confined::try_from(assignments) - .expect("collections is assembled from another collection with the same size requirements") - .into() -} - -impl OwnedStateSchema { - pub fn validate( - &self, - opid: OpId, - state_type: AssignmentType, - data: &Assign, - type_system: &TypeSystem, - ) -> validation::Status { - let mut status = validation::Status::new(); - match data { - Assign::Confidential { state, .. } | Assign::ConfidentialState { state, .. } => { - match (self, state.state_commitment()) { - (OwnedStateSchema::Declarative, ConcealedState::Void) => {} - (OwnedStateSchema::Fungible(_), ConcealedState::Fungible(value)) => { - // [SECURITY-CRITICAL]: Bulletproofs validation - if let Err(err) = value.verify_range_proof() { - status.add_failure(validation::Failure::BulletproofsInvalid( - opid, - state_type, - err.to_string(), - )); - } - } - (OwnedStateSchema::Structured(_), ConcealedState::Structured(_)) => { - status.add_warning(validation::Warning::UncheckableConfidentialState( - opid, state_type, - )); - } - (OwnedStateSchema::Attachment(_), ConcealedState::Attachment(_)) => { - status.add_warning(validation::Warning::UncheckableConfidentialState( - opid, state_type, - )); - } - // all other options are mismatches - (state_schema, found) => { - status.add_failure(validation::Failure::StateTypeMismatch { - opid, - state_type, - expected: state_schema.state_type(), - found: found.state_type(), - }); - } - } - } - Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => { - match (self, state.state_data()) { - (OwnedStateSchema::Declarative, RevealedState::Void) => {} - ( - OwnedStateSchema::Attachment(media_type), - RevealedState::Attachment(attach), - ) if !attach.file.media_type.conforms(media_type) => { - status.add_failure(validation::Failure::MediaTypeMismatch { - opid, - state_type, - expected: *media_type, - found: attach.file.media_type, - }); - } - (OwnedStateSchema::Fungible(schema), RevealedState::Fungible(v)) - if v.value.fungible_type() != *schema => - { - status.add_failure(validation::Failure::FungibleTypeMismatch { - opid, - state_type, - expected: *schema, - found: v.value.fungible_type(), - }); - } - (OwnedStateSchema::Fungible(_), RevealedState::Fungible(_)) => {} - (OwnedStateSchema::Structured(sem_id), RevealedState::Structured(data)) => { - if type_system - .strict_deserialize_type(*sem_id, data.value.as_ref()) - .is_err() - { - status.add_failure(validation::Failure::SchemaInvalidOwnedValue( - opid, state_type, *sem_id, - )); - }; - } - // all other options are mismatches - (state_schema, found) => { - status.add_failure(validation::Failure::StateTypeMismatch { - opid, - state_type, - expected: state_schema.state_type(), - found: found.state_type(), - }); - } - } - } - } - status - } -} diff --git a/src/validation/mod.rs b/src/validation/mod.rs deleted file mode 100644 index c7c3eb09..00000000 --- a/src/validation/mod.rs +++ /dev/null @@ -1,33 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -mod schema; -mod logic; -mod validator; -mod consignment; -mod status; -mod commitments; - -pub use commitments::{DbcError, DbcProof, EAnchor}; -pub use consignment::{CheckedConsignment, ConsignmentApi, OpRef, Scripts, CONSIGNMENT_MAX_LIBS}; -pub use status::{Failure, Info, Status, Validity, Warning}; -pub use validator::{ResolveWitness, Validator, WitnessResolverError}; diff --git a/src/validation/schema.rs b/src/validation/schema.rs deleted file mode 100644 index 4e8dafc2..00000000 --- a/src/validation/schema.rs +++ /dev/null @@ -1,108 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use strict_types::TypeSystem; - -use crate::{validation, OpFullType, OpSchema, OwnedStateSchema, Schema, TransitionType}; - -impl Schema { - pub fn verify(&self, types: &TypeSystem) -> validation::Status { - let mut status = validation::Status::new(); - - status += self.verify_operation(OpFullType::Genesis, &self.genesis); - for (type_id, schema) in &self.transitions { - status += self.verify_operation(OpFullType::StateTransition(*type_id), schema); - } - for (type_id, schema) in &self.extensions { - status += self.verify_operation(OpFullType::StateExtension(*type_id), schema); - } - // Check that the schema doesn't contain reserved type ids - if self.transitions.contains_key(&TransitionType::BLANK) { - status.add_failure(validation::Failure::SchemaBlankTransitionRedefined); - } - - for (type_id, sem_id) in &self.meta_types { - if !types.contains_key(sem_id) { - status.add_failure(validation::Failure::SchemaMetaSemIdUnknown(*type_id, *sem_id)); - } - } - - for (type_id, schema) in &self.global_types { - if !types.contains_key(&schema.sem_id) { - status.add_failure(validation::Failure::SchemaGlobalSemIdUnknown( - *type_id, - schema.sem_id, - )); - } - } - - for (type_id, schema) in &self.owned_types { - if let OwnedStateSchema::Structured(sem_id) = schema { - if !types.contains_key(sem_id) { - status.add_failure(validation::Failure::SchemaOwnedSemIdUnknown( - *type_id, *sem_id, - )); - } - } - } - - status - } - - fn verify_operation(&self, op_type: OpFullType, schema: &impl OpSchema) -> validation::Status { - let mut status = validation::Status::new(); - - for type_id in schema.metadata() { - if !self.meta_types.contains_key(type_id) { - status.add_failure(validation::Failure::SchemaOpMetaTypeUnknown(op_type, *type_id)); - } - } - if matches!(schema.inputs(), Some(inputs) if inputs.is_empty()) { - status.add_failure(validation::Failure::SchemaOpEmptyInputs(op_type)); - } - if matches!(schema.redeems(), Some(inputs) if inputs.is_empty()) { - status.add_failure(validation::Failure::SchemaOpEmptyInputs(op_type)); - } - for type_id in schema.globals().keys() { - if !self.global_types.contains_key(type_id) { - status - .add_failure(validation::Failure::SchemaOpGlobalTypeUnknown(op_type, *type_id)); - } - } - for type_id in schema.assignments().keys() { - if !self.owned_types.contains_key(type_id) { - status.add_failure(validation::Failure::SchemaOpAssignmentTypeUnknown( - op_type, *type_id, - )); - } - } - for type_id in schema.valencies() { - if !self.valency_types.contains(type_id) { - status.add_failure(validation::Failure::SchemaOpValencyTypeUnknown( - op_type, *type_id, - )); - } - } - - status - } -} diff --git a/src/validation/status.rs b/src/validation/status.rs deleted file mode 100644 index f77c6a0a..00000000 --- a/src/validation/status.rs +++ /dev/null @@ -1,391 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use core::ops::AddAssign; -use std::fmt::{self, Display, Formatter}; - -use amplify::num::u24; -use commit_verify::mpc::InvalidProof; -use strict_types::SemId; - -use crate::schema::{self, SchemaId}; -use crate::validation::WitnessResolverError; -use crate::vm::XWitnessId; -use crate::{ - BundleId, ContractId, Layer1, OccurrencesMismatch, OpFullType, OpId, Opout, StateType, Vin, - XGraphSeal, XOutputSeal, -}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Display)] -#[repr(u8)] -pub enum Validity { - #[display("is valid")] - Valid, - - #[display("valid, with warnings")] - Warnings, - - #[display("is NOT valid")] - Invalid, -} - -#[derive(Clone, PartialEq, Eq, Debug, Default)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Status { - pub failures: Vec, - pub warnings: Vec, - pub info: Vec, -} - -impl Display for Status { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if f.alternate() { - writeln!(f, "Consignment {}", self.validity())?; - } - - if !self.failures.is_empty() { - f.write_str("Validation failures:\n")?; - for fail in &self.failures { - writeln!(f, "- {fail}")?; - } - } - - if !self.warnings.is_empty() { - f.write_str("Validation warnings:\n")?; - for warn in &self.warnings { - writeln!(f, "- {warn}")?; - } - } - - if !self.info.is_empty() { - f.write_str("Validation info:\n")?; - for info in &self.info { - writeln!(f, "- {info}")?; - } - } - - Ok(()) - } -} - -impl AddAssign for Status { - fn add_assign(&mut self, rhs: Self) { - self.failures.extend(rhs.failures); - self.warnings.extend(rhs.warnings); - self.info.extend(rhs.info); - } -} - -impl Status { - pub fn from_error(v: Failure) -> Self { - Status { - failures: vec![v], - warnings: vec![], - info: vec![], - } - } -} - -impl FromIterator for Status { - fn from_iter>(iter: T) -> Self { - Self { - failures: iter.into_iter().collect(), - ..Self::default() - } - } -} - -impl Status { - pub fn new() -> Self { Self::default() } - - pub fn with_failure(failure: impl Into) -> Self { - Self { - failures: vec![failure.into()], - ..Self::default() - } - } - - pub fn add_failure(&mut self, failure: impl Into) -> &Self { - self.failures.push(failure.into()); - self - } - - pub fn add_warning(&mut self, warning: impl Into) -> &Self { - self.warnings.push(warning.into()); - self - } - - pub fn add_info(&mut self, info: impl Into) -> &Self { - self.info.push(info.into()); - self - } - - pub fn validity(&self) -> Validity { - if !self.failures.is_empty() { - Validity::Invalid - } else if !self.warnings.is_empty() { - Validity::Warnings - } else { - Validity::Valid - } - } -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, From)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display(doc_comments)] -pub enum Failure { - /// the contract network doesn't match (validator runs in testnet={0} - /// configuration). - NetworkMismatch(bool), - - /// schema {actual} provided for the consignment validation doesn't match - /// schema {expected} used by the contract. This means that the consignment - /// is invalid. - SchemaMismatch { - /// Expected schema id required by the contract genesis. - expected: SchemaId, - /// Actual schema id provided by the consignment. - actual: SchemaId, - }, - /// schema uses reserved type for the blank state transition. - SchemaBlankTransitionRedefined, - - /// schema global state #{0} uses semantic data type absent in type library - /// ({1}). - SchemaGlobalSemIdUnknown(schema::GlobalStateType, SemId), - /// schema owned state #{0} uses semantic data type absent in type library - /// ({1}). - SchemaOwnedSemIdUnknown(schema::AssignmentType, SemId), - /// schema metadata #{0} uses semantic data type absent in type library - /// ({1}). - SchemaMetaSemIdUnknown(schema::MetaType, SemId), - - /// schema for {0} has zero inputs. - SchemaOpEmptyInputs(OpFullType), - /// schema for {0} references undeclared metadata type {1}. - SchemaOpMetaTypeUnknown(OpFullType, schema::MetaType), - /// schema for {0} references undeclared global state type {1}. - SchemaOpGlobalTypeUnknown(OpFullType, schema::GlobalStateType), - /// schema for {0} references undeclared owned state type {1}. - SchemaOpAssignmentTypeUnknown(OpFullType, schema::AssignmentType), - /// schema for {0} references undeclared valency type {1}. - SchemaOpValencyTypeUnknown(OpFullType, schema::ValencyType), - - /// operation {0} uses invalid state extension type {1}. - SchemaUnknownExtensionType(OpId, schema::ExtensionType), - /// operation {0} uses invalid state transition type {1}. - SchemaUnknownTransitionType(OpId, schema::TransitionType), - /// operation {0} uses invalid metadata type {1}. - SchemaUnknownMetaType(OpId, schema::MetaType), - /// operation {0} uses invalid global state type {1}. - SchemaUnknownGlobalStateType(OpId, schema::GlobalStateType), - /// operation {0} uses invalid assignment type {1}. - SchemaUnknownAssignmentType(OpId, schema::AssignmentType), - /// operation {0} uses invalid valency type {1}. - SchemaUnknownValencyType(OpId, schema::ValencyType), - - /// invalid number of global state entries of type {1} in operation {0} - - /// {2} - SchemaGlobalStateOccurrences(OpId, schema::GlobalStateType, OccurrencesMismatch), - /// number of global state entries of type {1} in operation {0} exceeds - /// schema-defined maximum for that global state type ({2} vs {3}). - SchemaGlobalStateLimit(OpId, schema::GlobalStateType, u16, u24), - /// required metadata type {1} is not present in the operation {0}. - SchemaNoMetadata(OpId, schema::MetaType), - /// invalid metadata in operation {0} not matching semantic type id {1}. - SchemaInvalidMetadata(OpId, SemId), - /// invalid global state value in operation {0}, state type #{1} which does - /// not match semantic type id {2}. - SchemaInvalidGlobalValue(OpId, schema::GlobalStateType, SemId), - /// invalid owned state value in operation {0}, state type #{1} which does - /// not match semantic type id {2}. - SchemaInvalidOwnedValue(OpId, schema::AssignmentType, SemId), - /// invalid number of input entries of type {1} in operation {0} - {2} - SchemaInputOccurrences(OpId, schema::AssignmentType, OccurrencesMismatch), - /// invalid number of assignment entries of type {1} in operation {0} - {2} - SchemaAssignmentOccurrences(OpId, schema::AssignmentType, OccurrencesMismatch), - - // Consignment consistency errors - /// operation {0} is referenced within the history multiple times. RGB - /// contracts allow only direct acyclic graphs. - CyclicGraph(OpId), - /// operation {0} is absent from the consignment. - OperationAbsent(OpId), - /// transition bundle {0} is absent in the consignment. - BundleAbsent(BundleId), - /// anchor for transitio bundle {0} is absent in the consignment. - AnchorAbsent(BundleId), - /// witness id for transition bundle {0} is absent in the consignment. - WitnessIdAbsent(BundleId), - /// bundle {0} public witness {1} is not known to the resolver; validation - /// stopped since operations can't be consensus-ordered. The resolver - /// responded with error {2} - WitnessUnresolved(BundleId, XWitnessId, WitnessResolverError), - /// operation {0} is under a different contract {1}. - ContractMismatch(OpId, ContractId), - - // Errors checking bundle commitments - /// transition bundle {0} references state transition {1} which is not - /// included into the bundle input map. - BundleExtraTransition(BundleId, OpId), - /// transition bundle {0} references non-existing input in witness {2} for - /// the state transition {1}. - BundleInvalidInput(BundleId, OpId, XWitnessId), - /// transition bundle {0} doesn't commit to the input {1} in the witness {2} - /// which is an input of the state transition {3}. - BundleInvalidCommitment(BundleId, Vin, XWitnessId, OpId), - - // Errors checking asset tags - /// asset type provided in genesis references unknown fungible state of type - /// {0}. - AssetTagNoState(schema::AssignmentType), - /// fungible state {0} has no asset tag defined. - FungibleStateNoTag(schema::AssignmentType), - - // Errors checking seal closing - /// transition {opid} references state type {state_type} absent in the - /// outputs of previous state transition {prev_id}. - NoPrevState { - opid: OpId, - prev_id: OpId, - state_type: schema::AssignmentType, - }, - /// transition {0} references non-existing previous output {1}. - NoPrevOut(OpId, Opout), - /// seal defined in the history as a part of operation output {0} is - /// confidential and can't be validated. - ConfidentialSeal(Opout), - /// bundle {0} public witness {1} is not known to the resolver. Resolver - /// reported error {2} - SealNoPubWitness(BundleId, XWitnessId, WitnessResolverError), - /// witness layer 1 {anchor} doesn't match seal definition {seal}. - SealWitnessLayer1Mismatch { seal: Layer1, anchor: Layer1 }, - /// seal {1} is defined on {0} which is not in the set of layers allowed - /// by the contract genesis. - SealLayerMismatch(Layer1, XGraphSeal), - /// seal {1} has a different closing method from the bundle {0} requirement. - SealInvalidMethod(BundleId, XOutputSeal), - /// transition bundle {0} doesn't close seal with the witness {1}. Details: - /// {2} - SealsInvalid(BundleId, XWitnessId, String), - /// single-use seals for the operation {0} were not validated, which - /// probably indicates unanchored state transition. - SealsUnvalidated(OpId), - /// anchor provides different type of DBC proof than required by the bundle - /// {0}. - AnchorMethodMismatch(BundleId), - /// transition bundle {0} is not properly anchored to the witness {1}. - /// Details: {2} - MpcInvalid(BundleId, XWitnessId, InvalidProof), - - // State extensions errors - /// valency {valency} redeemed by state extension {opid} references - /// non-existing operation {prev_id} - ValencyNoParent { - opid: OpId, - prev_id: OpId, - valency: schema::ValencyType, - }, - /// state extension {opid} references valency {valency} absent in the parent - /// {prev_id}. - NoPrevValency { - opid: OpId, - prev_id: OpId, - valency: schema::ValencyType, - }, - - // State check errors - /// state in {opid}/{state_type} is of {found} type, while schema requires - /// it to be {expected}. - StateTypeMismatch { - opid: OpId, - state_type: schema::AssignmentType, - expected: StateType, - found: StateType, - }, - /// state in {opid}/{state_type} is of {found} type, while schema requires - /// it to be {expected}. - MediaTypeMismatch { - opid: OpId, - state_type: schema::AssignmentType, - expected: schema::MediaType, - found: schema::MediaType, - }, - /// state in {opid}/{state_type} is of {found} type, while schema requires - /// it to be {expected}. - FungibleTypeMismatch { - opid: OpId, - state_type: schema::AssignmentType, - expected: schema::FungibleType, - found: schema::FungibleType, - }, - /// invalid bulletproofs in {0}:{1}: {2} - BulletproofsInvalid(OpId, schema::AssignmentType, String), - /// evaluation of AluVM script for operation {0} has failed with the code - /// {1:?} and message {2:?}. - ScriptFailure(OpId, Option, Option), - /// contract state can't fit more data (at operation id {0}). - ContractStateFilled(OpId), - - /// Custom error by external services on top of RGB Core. - #[display(inner)] - Custom(String), -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, From)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display(doc_comments)] -pub enum Warning { - /// operation {0} contains state in assignment {1} which is confidential and - /// thus was not validated. - UncheckableConfidentialState(OpId, schema::AssignmentType), - - /// Custom warning by external services on top of RGB Core. - #[display(inner)] - Custom(String), -} - -#[derive(Clone, PartialEq, Eq, Debug, Display, From)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display(doc_comments)] -pub enum Info { - /// Custom info by external services on top of RGB Core. - #[display(inner)] - Custom(String), -} diff --git a/src/validation/validator.rs b/src/validation/validator.rs deleted file mode 100644 index 941bc14f..00000000 --- a/src/validation/validator.rs +++ /dev/null @@ -1,672 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::cell::RefCell; -use std::collections::{BTreeMap, BTreeSet}; -use std::rc::Rc; - -use bp::dbc::{Anchor, Proof}; -use bp::seals::txout::{TxoSeal, Witness}; -use bp::{dbc, Outpoint}; -use commit_verify::mpc; -use single_use_seals::SealWitness; - -use super::status::Failure; -use super::{CheckedConsignment, ConsignmentApi, DbcProof, EAnchor, OpRef, Status, Validity}; -use crate::vm::{ - ContractStateAccess, ContractStateEvolve, OrdOpRef, WitnessOrd, XWitnessId, XWitnessTx, -}; -use crate::{ - validation, AltLayer1, BundleId, ContractId, Layer1, OpId, OpType, Operation, Opout, Schema, - SchemaId, TransitionBundle, XChain, XOutpoint, XOutputSeal, -}; - -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(doc_comments)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum WitnessResolverError { - /// actual witness id {actual} doesn't match expected id {expected}. - IdMismatch { - actual: XWitnessId, - expected: XWitnessId, - }, - /// witness {0} does not exist. - Unknown(XWitnessId), - /// unable to retrieve witness {0}, {1} - Other(XWitnessId, String), -} - -pub trait ResolveWitness { - // TODO: Return with SPV proof data - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result; - - fn resolve_pub_witness_ord( - &self, - witness_id: XWitnessId, - ) -> Result; -} - -impl ResolveWitness for &T { - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result { - ResolveWitness::resolve_pub_witness(*self, witness_id) - } - - fn resolve_pub_witness_ord( - &self, - witness_id: XWitnessId, - ) -> Result { - ResolveWitness::resolve_pub_witness_ord(*self, witness_id) - } -} - -struct CheckedWitnessResolver { - inner: R, -} - -impl From for CheckedWitnessResolver { - fn from(inner: R) -> Self { Self { inner } } -} - -impl ResolveWitness for CheckedWitnessResolver { - fn resolve_pub_witness( - &self, - witness_id: XWitnessId, - ) -> Result { - let witness = self.inner.resolve_pub_witness(witness_id)?; - let actual_id = witness.witness_id(); - if actual_id != witness_id { - return Err(WitnessResolverError::IdMismatch { - actual: actual_id, - expected: witness_id, - }); - } - Ok(witness) - } - - #[inline] - fn resolve_pub_witness_ord( - &self, - witness_id: XWitnessId, - ) -> Result { - self.inner.resolve_pub_witness_ord(witness_id) - } -} - -pub struct Validator< - 'consignment, - 'resolver, - S: ContractStateAccess + ContractStateEvolve, - C: ConsignmentApi, - R: ResolveWitness, -> { - consignment: CheckedConsignment<'consignment, C>, - - status: RefCell, - - schema_id: SchemaId, - contract_id: ContractId, - layers1: BTreeSet, - - contract_state: Rc>, - validated_op_seals: RefCell>, - - resolver: CheckedWitnessResolver<&'resolver R>, -} - -impl< - 'consignment, - 'resolver, - S: ContractStateAccess + ContractStateEvolve, - C: ConsignmentApi, - R: ResolveWitness, - > Validator<'consignment, 'resolver, S, C, R> -{ - fn init(consignment: &'consignment C, resolver: &'resolver R, context: S::Context<'_>) -> Self { - // We use validation status object to store all detected failures and - // warnings - let status = Status::default(); - let consignment = CheckedConsignment::new(consignment); - - // Frequently used computation-heavy data - let genesis = consignment.genesis(); - let contract_id = genesis.contract_id(); - let schema_id = genesis.schema_id; - - // Prevent repeated validation of single-use seals - let validated_op_seals = RefCell::new(BTreeSet::::new()); - - let mut layers1 = bset! { Layer1::Bitcoin }; - layers1.extend(genesis.alt_layers1.iter().map(AltLayer1::layer1)); - - Self { - consignment, - status: RefCell::new(status), - schema_id, - contract_id, - layers1, - validated_op_seals, - resolver: CheckedWitnessResolver::from(resolver), - contract_state: Rc::new(RefCell::new(S::init(context))), - } - } - - /// Validation procedure takes a schema object, root schema (if any), - /// resolver function returning transaction and its fee for a given - /// transaction id, and returns a validation object listing all detected - /// failures, warnings and additional information. - /// - /// When a failure detected, validation is not stopped; the failure is - /// logged into the status object, but the validation continues for the - /// rest of the consignment data. This can help to debug and detect all - /// problems with the consignment. - pub fn validate( - consignment: &'consignment C, - resolver: &'resolver R, - testnet: bool, - context: S::Context<'_>, - ) -> Status { - let mut validator = Self::init(consignment, resolver, context); - // If the network mismatches there is no point in validating the contract since - // all witness transactions will be missed. - if testnet != validator.consignment.genesis().testnet { - validator - .status - .borrow_mut() - .add_failure(Failure::NetworkMismatch(testnet)); - return validator.status.into_inner(); - } - - validator.validate_schema(consignment.schema()); - // We must return here, since if the schema is not valid there is no reason to - // validate contract nodes against it: it will produce a plenty of errors. - if validator.status.borrow().validity() == Validity::Invalid { - return validator.status.into_inner(); - } - - validator.validate_commitments(); - // We must return here, since if there were no proper commitments, it is - // pointless to validate the contract state. - if validator.status.borrow().validity() == Validity::Invalid { - return validator.status.into_inner(); - } - - validator.validate_logic(); - // Done. Returning status report with all possible failures, issues, warnings - // and notifications about transactions we were unable to obtain. - validator.status.into_inner() - } - - // *** PART I: Schema validation - fn validate_schema(&mut self, schema: &Schema) { - *self.status.borrow_mut() += schema.verify(self.consignment.types()); - } - - // *** PART II: Validating business logic - fn validate_logic(&self) { - let schema = self.consignment.schema(); - - // [VALIDATION]: Making sure that we were supplied with the schema - // that corresponds to the schema of the contract genesis - if schema.schema_id() != self.schema_id { - self.status - .borrow_mut() - .add_failure(Failure::SchemaMismatch { - expected: self.schema_id, - actual: schema.schema_id(), - }); - // Unlike other failures, here we return immediately, since there is no point - // to validate all consignment data against an invalid schema: it will result in - // a plenty of meaningless errors - return; - } - - // [VALIDATION]: Validate genesis - *self.status.borrow_mut() += schema.validate_state( - &self.consignment, - OrdOpRef::Genesis(self.consignment.genesis()), - self.contract_state.clone(), - ); - - // [VALIDATION]: Iterating over all consignment operations, ordering them according to the - // consensus ordering rules. - let mut ops = BTreeSet::::new(); - for bundle_id in self.consignment.bundle_ids() { - let bundle = self - .consignment - .bundle(bundle_id) - .expect("invalid checked consignment"); - let (witness_id, _) = self - .consignment - .anchor(bundle_id) - .expect("invalid checked consignment"); - let witness_ord = - match self.resolver.resolve_pub_witness_ord(witness_id) { - Ok(ord) => ord, - Err(err) => { - self.status.borrow_mut().add_failure( - validation::Failure::WitnessUnresolved(bundle_id, witness_id, err), - ); - // We need to stop validation there since we can't order operations - return; - } - }; - for op in bundle.known_transitions.values() { - ops.insert(OrdOpRef::Transition(op, witness_id, witness_ord)); - for input in &op.inputs { - // We will error in `validate_operations` below on the absent extension from the - // consignment. - if let Some(OpRef::Extension(extension)) = - self.consignment.operation(input.prev_out.op) - { - let ext = OrdOpRef::Extension(extension, witness_id, witness_ord); - // Account only for the first time when extension seal was closed - let prev = ops.iter().find(|r| matches!(r, OrdOpRef::Extension(ext, ..) if ext.id() == extension.id())).copied(); - match prev { - Some(old) if old > ext => { - ops.remove(&old); - ops.insert(ext) - } - None => ops.insert(ext), - _ => { - /* the extension is already present in the queue and properly - * ordered, so we have nothing to add or change */ - true - } - }; - } - } - } - } - for op in ops { - // We do not skip validating archive operations since after a re-org they may - // become valid and thus must be added to the contract state and validated - // beforehand. - self.validate_operation(op); - } - } - - fn validate_operation(&self, operation: OrdOpRef<'consignment>) { - let schema = self.consignment.schema(); - let opid = operation.id(); - - if operation.contract_id() != self.contract_id { - self.status - .borrow_mut() - .add_failure(Failure::ContractMismatch(opid, operation.contract_id())); - } - - if !self.validated_op_seals.borrow().contains(&opid) - && operation.op_type() == OpType::StateTransition - { - self.status - .borrow_mut() - .add_failure(Failure::SealsUnvalidated(opid)); - } - // [VALIDATION]: Verify operation against the schema and scripts - *self.status.borrow_mut() += - schema.validate_state(&self.consignment, operation, self.contract_state.clone()); - - match operation { - OrdOpRef::Genesis(_) => { - unreachable!("genesis is not a part of the operation history") - } - OrdOpRef::Transition(transition, ..) => { - for input in &transition.inputs { - if self.consignment.operation(input.prev_out.op).is_none() { - self.status - .borrow_mut() - .add_failure(Failure::OperationAbsent(input.prev_out.op)); - } - } - } - OrdOpRef::Extension(extension, ..) => { - for (valency, prev_id) in &extension.redeemed { - let Some(prev_op) = self.consignment.operation(*prev_id) else { - self.status - .borrow_mut() - .add_failure(Failure::ValencyNoParent { - opid, - prev_id: *prev_id, - valency: *valency, - }); - continue; - }; - - if !prev_op.valencies().contains(valency) { - self.status - .borrow_mut() - .add_failure(Failure::NoPrevValency { - opid, - prev_id: *prev_id, - valency: *valency, - }); - continue; - } - } - } - } - } - - // *** PART III: Validating single-use-seals - fn validate_commitments(&mut self) { - for bundle_id in self.consignment.bundle_ids() { - let Some(bundle) = self.consignment.bundle(bundle_id) else { - self.status - .borrow_mut() - .add_failure(Failure::BundleAbsent(bundle_id)); - continue; - }; - let Some((witness_id, anchor)) = self.consignment.anchor(bundle_id) else { - self.status - .borrow_mut() - .add_failure(Failure::AnchorAbsent(bundle_id)); - continue; - }; - - // [VALIDATION]: We validate that the seals were properly defined on BP-type layers - let (seals, input_map) = self.validate_seal_definitions(witness_id.layer1(), bundle); - - if anchor.dbc_proof.method() != bundle.close_method { - self.status - .borrow_mut() - .add_failure(Failure::AnchorMethodMismatch(bundle_id)); - continue; - } - - // [VALIDATION]: We validate that the seals were properly closed on BP-type layers - let Some(witness_tx) = - self.validate_seal_commitments(&seals, bundle_id, witness_id, anchor) - else { - continue; - }; - - // [VALIDATION]: We validate bundle commitments to the input map - self.validate_bundle_commitments(bundle_id, bundle, witness_tx, input_map); - } - } - - /// Validates that the transition bundle is internally consistent: inputs of - /// its state transitions correspond to the way how they are committed - /// in the input map of the bundle; and these inputs are real inputs of - /// the transaction. - fn validate_bundle_commitments( - &self, - bundle_id: BundleId, - bundle: &TransitionBundle, - pub_witness: XWitnessTx, - input_map: BTreeMap>, - ) { - let witness_id = pub_witness.witness_id(); - for (vin, opid) in &bundle.input_map { - let Some(outpoints) = input_map.get(opid) else { - self.status - .borrow_mut() - .add_failure(Failure::BundleExtraTransition(bundle_id, *opid)); - continue; - }; - let layer1 = pub_witness.layer1(); - let pub_witness = pub_witness.as_reduced_unsafe(); - let Some(input) = pub_witness.inputs.get(vin.to_usize()) else { - self.status - .borrow_mut() - .add_failure(Failure::BundleInvalidInput(bundle_id, *opid, witness_id)); - continue; - }; - if !outpoints.contains(&XChain::with(layer1, input.prev_output)) { - self.status - .borrow_mut() - .add_failure(Failure::BundleInvalidCommitment( - bundle_id, *vin, witness_id, *opid, - )); - } - } - } - - /// Bitcoin- and liquid-specific commitment validation using deterministic - /// bitcoin commitments with opret and tapret schema. - fn validate_seal_commitments( - &self, - seals: impl AsRef<[XOutputSeal]>, - bundle_id: BundleId, - witness_id: XWitnessId, - anchor: &EAnchor, - ) -> Option { - // Check that the anchor is committed into a transaction spending all the - // transition inputs. - // Here the method can do SPV proof instead of querying the indexer. The SPV - // proofs can be part of the consignments, but do not require . - match self.resolver.resolve_pub_witness(witness_id) { - Err(err) => { - // We wre unable to retrieve corresponding transaction, so can't check. - // Reporting this incident and continuing further. Why this happens? No - // connection to Bitcoin Core, Electrum or other backend etc. So this is not a - // failure in a strict sense, however we can't be sure that the consignment is - // valid. - // This also can mean that there is no known transaction with the id provided by - // the anchor, i.e. consignment is invalid. We are proceeding with further - // validation in order to detect the rest of problems (and reporting the - // failure!) - self.status - .borrow_mut() - .add_failure(Failure::SealNoPubWitness(bundle_id, witness_id, err)); - None - } - Ok(pub_witness) => { - let seals = seals.as_ref(); - for seal in seals - .iter() - .filter(|seal| seal.method() != anchor.dbc_proof.method()) - { - self.status - .borrow_mut() - .add_failure(Failure::SealInvalidMethod(bundle_id, *seal)); - } - match anchor.clone() { - EAnchor { - mpc_proof, - dbc_proof: DbcProof::Tapret(tapret), - .. - } => { - let witness = pub_witness.clone().map(|tx| Witness::with(tx, tapret)); - self.validate_seal_closing(seals, bundle_id, witness, mpc_proof) - } - EAnchor { - mpc_proof, - dbc_proof: DbcProof::Opret(opret), - .. - } => { - let witness = pub_witness.clone().map(|tx| Witness::with(tx, opret)); - self.validate_seal_closing(seals, bundle_id, witness, mpc_proof) - } - } - - Some(pub_witness) - } - } - } - - /// Single-use-seal definition validation. - /// - /// Takes state transition, extracts all seals from its inputs and makes - /// sure they are defined or a correct layer1. - fn validate_seal_definitions( - &self, - layer1: Layer1, - bundle: &TransitionBundle, - ) -> (Vec, BTreeMap>) { - let mut input_map: BTreeMap> = bmap!(); - let mut seals = vec![]; - for (opid, transition) in &bundle.known_transitions { - let opid = *opid; - - if !self.validated_op_seals.borrow_mut().insert(opid) { - self.status - .borrow_mut() - .add_failure(Failure::CyclicGraph(opid)); - } - - // Checking that witness transaction closes seals defined by transition previous - // outputs. - for input in &transition.inputs { - let Opout { op, ty, no } = input.prev_out; - - let Some(prev_op) = self.consignment.operation(op) else { - // Node, referenced as the ancestor, was not found in the consignment. - // Usually this means that the consignment data are broken - self.status - .borrow_mut() - .add_failure(Failure::OperationAbsent(op)); - continue; - }; - - let Some(variant) = prev_op.assignments_by_type(ty) else { - self.status.borrow_mut().add_failure(Failure::NoPrevState { - opid, - prev_id: op, - state_type: ty, - }); - continue; - }; - - let Ok(seal) = variant.revealed_seal_at(no) else { - self.status - .borrow_mut() - .add_failure(Failure::NoPrevOut(opid, input.prev_out)); - continue; - }; - let Some(seal) = seal else { - // Everything is ok, but we have incomplete data (confidential), thus can't do a - // full verification and have to report the failure - self.status - .borrow_mut() - .add_failure(Failure::ConfidentialSeal(input.prev_out)); - continue; - }; - - if seal.layer1() != layer1 { - self.status - .borrow_mut() - .add_failure(Failure::SealWitnessLayer1Mismatch { - seal: seal.layer1(), - anchor: layer1, - }); - continue; - } - if !self.layers1.contains(&seal.layer1()) { - self.status - .borrow_mut() - .add_failure(Failure::SealLayerMismatch(seal.layer1(), seal)); - continue; - } - - let seal = if prev_op.op_type() == OpType::StateTransition { - let Some(witness_id) = self.consignment.op_witness_id(op) else { - self.status - .borrow_mut() - .add_failure(Failure::OperationAbsent(op)); - continue; - }; - - match seal.try_to_output_seal(witness_id) { - Ok(seal) => seal, - Err(_) => { - self.status.borrow_mut().add_failure( - Failure::SealWitnessLayer1Mismatch { - seal: seal.layer1(), - anchor: witness_id.layer1(), - }, - ); - continue; - } - } - } else { - seal.to_output_seal() - .expect("genesis and state extensions must have explicit seals") - }; - - seals.push(seal); - input_map - .entry(opid) - .or_default() - .insert(seal.map(|seal| Outpoint::new(seal.txid, seal.vout)).into()); - } - } - (seals, input_map) - } - - /// Single-use-seal closing validation. - /// - /// Checks that the set of seals is closed over the message, which is - /// multi-protocol commitment, by utilizing witness, consisting of - /// transaction with deterministic bitcoin commitments (defined by - /// generic type `Dbc`) and extra-transaction data, which are taken from - /// anchor's DBC proof. - /// - /// Additionally, checks that the provided message contains commitment to - /// the bundle under the current contract. - fn validate_seal_closing<'seal, Seal: 'seal, Dbc: dbc::Proof>( - &self, - seals: impl IntoIterator, - bundle_id: BundleId, - witness: XChain>, - mpc_proof: mpc::MerkleProof, - ) where - XChain>: SealWitness, - { - let message = mpc::Message::from(bundle_id); - let witness_id = witness.witness_id(); - let anchor = Anchor::new(mpc_proof, witness.as_reduced_unsafe().proof.clone()); - // [VALIDATION]: Checking anchor MPC commitment - match anchor.convolve(self.contract_id, message) { - Err(err) => { - // The operation is not committed to bitcoin transaction graph! - // Ultimate failure. But continuing to detect the rest (after reporting it). - self.status - .borrow_mut() - .add_failure(Failure::MpcInvalid(bundle_id, witness_id, err)); - } - Ok(commitment) => { - // [VALIDATION]: CHECKING SINGLE-USE-SEALS - witness - .verify_many_seals(seals, &commitment) - .map_err(|err| { - self.status.borrow_mut().add_failure(Failure::SealsInvalid( - bundle_id, - witness_id, - err.to_string(), - )); - }) - .ok(); - } - } - } -} diff --git a/src/verify.rs b/src/verify.rs new file mode 100644 index 00000000..fc57f828 --- /dev/null +++ b/src/verify.rs @@ -0,0 +1,243 @@ +// RGB Core Library: consensus layer for RGB smart contracts. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Designed in 2019-2025 by Dr Maxim Orlovsky +// Written in 2024-2025 by Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland. +// Copyright (C) 2024-2025 LNP/BP Laboratories, +// Institute for Distributed and Cognitive Systems (InDCS), Switzerland. +// Copyright (C) 2025 RGB Consortium, Switzerland. +// Copyright (C) 2019-2025 Dr Maxim Orlovsky. +// All rights under the above copyrights are reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software distributed under the License +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +// or implied. See the License for the specific language governing permissions and limitations under +// the License. + +use alloc::collections::{BTreeMap, BTreeSet}; +use alloc::vec::Vec; + +use amplify::confinement::SmallOrdMap; +use amplify::ByteArray; +use single_use_seals::{PublishedWitness, SealError, SealWitness}; +use ultrasonic::{AuthToken, CallError, CellAddr, Codex, ContractId, LibRepo, Memory, Operation, Opid}; + +use crate::{RgbSealDef, RgbSealSrc, LIB_NAME_RGB_CORE}; + +// TODO: Move to amplify crate +pub enum Step { + Next(A), + Complete(B), +} + +#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CORE)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase", bound = "Seal: serde::Serialize + for<'d> serde::Deserialize<'d>") +)] +pub struct OperationSeals { + pub operation: Operation, + /// Operation itself contains only AuthToken's, which are a commitments to the seals. Hence, we + /// have to separately include a full seal definitions next to the operation data. + pub defined_seals: SmallOrdMap, +} + +pub trait ReadOperation: Sized { + type SealDef: RgbSealDef; + type WitnessReader: ReadWitness; + fn read_operation(self) -> Option<(OperationSeals, Self::WitnessReader)>; +} + +pub trait ReadWitness: Sized { + type SealDef: RgbSealDef; + type OperationReader: ReadOperation; + #[allow(clippy::type_complexity)] + fn read_witness(self) -> Step<(SealWitness<::Src>, Self), Self::OperationReader>; +} + +/// API exposed by the contract required for evaluating and verifying the contract state (see +/// [`ContractVerify`]). +/// +/// NB: `apply_operation` is called only after `apply_witness`. +pub trait ContractApi { + fn contract_id(&self) -> ContractId; + fn codex(&self) -> &Codex; + fn repo(&self) -> &impl LibRepo; + fn memory(&self) -> &impl Memory; + fn is_known(&self, opid: Opid) -> bool; + fn apply_operation(&mut self, header: OperationSeals); + fn apply_witness(&mut self, opid: Opid, witness: SealWitness); +} + +// We use dedicated trait here in order to prevent overriding of the implementation in client +// libraries +pub trait ContractVerify: ContractApi { + // TODO: Support multi-thread mode for parallel processing of unrelated operations + fn evaluate>( + &mut self, + mut reader: R, + ) -> Result<(), VerificationError> { + let contract_id = self.contract_id(); + let codex_id = self.codex().codex_id(); + + let mut first = true; + let mut seals = BTreeMap::::new(); + + while let Some((mut header, mut witness_reader)) = reader.read_operation() { + // Genesis can't commit to the contract id since the contract doesn't exist yet; thus, we have to + // apply this little trick + if first { + if header.operation.contract_id.to_byte_array() != codex_id.to_byte_array() { + return Err(VerificationError::NoCodexCommitment); + } + header.operation.contract_id = contract_id; + } + let opid = header.operation.opid(); + + // We need to check that all seal definitions strictly match operation-defined destructible cells + let defined = header + .operation + .destructible + .iter() + .map(|cell| cell.auth) + .collect::>(); + let reported = header + .defined_seals + .values() + .map(|seal| seal.auth_token()) + .collect::>(); + // It is a subset and not equal set since some of the seals might be unknown to us: we know their + // commitment auth token, but do not know definition. + if !reported.is_subset(&defined) { + let sources = header + .defined_seals + .iter() + .map(|(pos, seal)| (*pos, seal.to_string())) + .collect(); + return Err(VerificationError::SealsDefinitionMismatch { opid, reported, defined, sources }); + } + + // If the operation was validated before, we need to skip its validation, since its inputs are not a + // part of the state anymore. + let op_known = self.is_known(opid); + if !op_known { + // Verify the operation + self.codex() + .verify(contract_id, &header.operation, self.memory(), self.repo())?; + } + + // Next we verify single-use seal closings by the operation + let mut closed_seals = Vec::::new(); + for input in &header.operation.destroying { + let seal = seals + .remove(&input.addr) + .ok_or(VerificationError::SealUnknown(input.addr))?; + closed_seals.push(seal); + } + + // This convoluted logic happens since we use a state machine which ensures the client can't lie to + // the verifier + let mut witness_count = 0usize; + // Now we can add operation-defined seals to the set of known seals + let mut seal_sources: BTreeSet<_> = header + .defined_seals + .iter() + .filter_map(|(pos, seal)| seal.to_src().map(|seal| (CellAddr::new(opid, *pos), seal))) + .collect(); + + loop { + // An operation may have multiple witnesses (like multiple commitment transactions in lightning + // channel). + match witness_reader.read_witness() { + Step::Next((witness, w)) => { + let msg = opid.to_byte_array(); + witness + .verify_seals_closing(&closed_seals, msg.into()) + .map_err(|e| VerificationError::SealsNotClosed(witness.published.pub_id(), opid, e))?; + + // Each witness actually produces its own set of witness-output based seal sources. + let pub_id = witness.published.pub_id(); + let iter = header + .defined_seals + .iter() + .filter(|(_, seal)| seal.to_src().is_none()) + .map(|(pos, seal)| (CellAddr::new(opid, *pos), seal.resolve(pub_id))); + seal_sources.extend(iter); + + self.apply_witness(opid, witness); + witness_reader = w; + } + Step::Complete(r) => { + reader = r; + break; + } + } + witness_count += 1; + } + + if !closed_seals.is_empty() && witness_count == 0 { + return Err(VerificationError::NoWitness(opid)); + } + + seals.extend(seal_sources); + if first { + first = false + } else if !op_known { + self.apply_operation(header); + } + } + + Ok(()) + } +} + +impl> ContractVerify for C {} + +// TODO: Find a way to do Debug and Clone implementation +#[derive(Debug, Display, From)] +#[display(doc_comments)] +pub enum VerificationError { + /// genesis does not commit to the codex id; a wrong contract genesis is used. + NoCodexCommitment, + + /// no witness known for the operation {0}. + NoWitness(Opid), + + /// single-use seals are not closed properly with witness {0} for operation {1}. + /// + /// Details: {2} + SealsNotClosed(>::PubId, Opid, SealError), + + /// unknown seal definition for cell address {0}. + SealUnknown(CellAddr), + + /// seals, reported to be defined by the operation {opid}, do match the assignments in the + /// operation. + /// + /// Actual operation seals from the assignments: {defined:#?} + /// + /// Reported seals: {reported:#?} + /// + /// Sources for the reported seals: {sources:#?} + SealsDefinitionMismatch { + opid: Opid, + reported: BTreeSet, + defined: BTreeSet, + sources: BTreeMap, + }, + + #[from] + #[display(inner)] + Vm(CallError), +} diff --git a/src/vm/contract.rs b/src/vm/contract.rs deleted file mode 100644 index 633c3492..00000000 --- a/src/vm/contract.rs +++ /dev/null @@ -1,770 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::borrow::Borrow; -use std::cell::RefCell; -use std::cmp::Ordering; -use std::fmt::{self, Debug, Display, Formatter}; -use std::num::NonZeroU32; -use std::rc::Rc; - -use amplify::confinement; -use amplify::num::u24; -use bp::seals::txout::{CloseMethod, ExplicitSeal, VerifyError, Witness}; -use bp::{dbc, Tx, Txid}; -use chrono::{MappedLocalTime, TimeZone, Utc}; -use commit_verify::mpc; -use single_use_seals::SealWitness; -use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; - -use crate::{ - AssetTags, AssignmentType, Assignments, AssignmentsRef, AttachState, ContractId, DataState, - ExposedSeal, Extension, ExtensionType, FungibleState, Genesis, GlobalState, GlobalStateType, - GraphSeal, Impossible, Inputs, Layer1, Metadata, OpFullType, OpId, OpType, Operation, - Transition, TransitionType, TxoSeal, TypedAssigns, Valencies, XChain, XOutpoint, XOutputSeal, - LIB_NAME_RGB_LOGIC, -}; - -pub type XWitnessId = XChain; - -pub type XWitnessTx = XChain; - -impl XWitnessTx { - pub fn witness_id(&self) -> XWitnessId { - match self { - Self::Bitcoin(tx) => XWitnessId::Bitcoin(tx.txid()), - Self::Liquid(tx) => XWitnessId::Liquid(tx.txid()), - Self::Other(_) => unreachable!(), - } - } -} - -impl XChain> { - pub fn witness_id(&self) -> XWitnessId { - match self { - Self::Bitcoin(w) => XWitnessId::Bitcoin(w.txid), - Self::Liquid(w) => XWitnessId::Liquid(w.txid), - Self::Other(_) => unreachable!(), - } - } -} - -impl SealWitness for XChain> { - type Message = mpc::Commitment; - type Error = VerifyError; - - fn verify_seal(&self, seal: &Seal, msg: &Self::Message) -> Result<(), Self::Error> { - match self { - Self::Bitcoin(witness) | Self::Liquid(witness) => witness.verify_seal(seal, msg), - Self::Other(_) => unreachable!(), - } - } - - fn verify_many_seals<'seal>( - &self, - seals: impl IntoIterator, - msg: &Self::Message, - ) -> Result<(), Self::Error> - where - Seal: 'seal, - { - match self { - Self::Bitcoin(witness) | Self::Liquid(witness) => witness.verify_many_seals(seals, msg), - Self::Other(_) => unreachable!(), - } - } -} - -impl XChain { - pub fn method(self) -> CloseMethod - where U: TxoSeal { - match self { - XChain::Bitcoin(seal) => seal.method(), - XChain::Liquid(seal) => seal.method(), - XChain::Other(_) => unreachable!(), - } - } - - #[inline] - pub fn to_output_seal(self) -> Option - where U: TxoSeal { - Some(match self { - XChain::Bitcoin(seal) => { - let outpoint = seal.outpoint()?; - XChain::Bitcoin(ExplicitSeal::new(seal.method(), outpoint)) - } - XChain::Liquid(seal) => { - let outpoint = seal.outpoint()?; - XChain::Liquid(ExplicitSeal::new(seal.method(), outpoint)) - } - XChain::Other(_) => unreachable!(), - }) - } - - pub fn try_to_output_seal(self, witness_id: XWitnessId) -> Result - where U: TxoSeal { - self.to_output_seal() - .or(match (self, witness_id) { - (XChain::Bitcoin(seal), XWitnessId::Bitcoin(txid)) => { - Some(XChain::Bitcoin(ExplicitSeal::new(seal.method(), seal.outpoint_or(txid)))) - } - (XChain::Liquid(seal), XWitnessId::Liquid(txid)) => { - Some(XChain::Liquid(ExplicitSeal::new(seal.method(), seal.outpoint_or(txid)))) - } - _ => None, - }) - .ok_or(self) - } -} - -/// The type is used during validation and computing a contract state. It -/// combines both the operation with the information required for its ordering -/// in the contract history (via construction of [`OpOrd`]) according to the -/// consensus rules. -#[derive(Copy, Clone, PartialEq, Eq, Debug, From)] -pub enum OrdOpRef<'op> { - #[from] - Genesis(&'op Genesis), - Transition(&'op Transition, XWitnessId, WitnessOrd), - Extension(&'op Extension, XWitnessId, WitnessOrd), -} - -impl<'op> PartialOrd for OrdOpRef<'op> { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl<'op> Ord for OrdOpRef<'op> { - fn cmp(&self, other: &Self) -> Ordering { self.op_ord().cmp(&other.op_ord()) } -} - -impl<'op> OrdOpRef<'op> { - pub fn witness_id(&self) -> Option { - match self { - OrdOpRef::Genesis(_) => None, - OrdOpRef::Transition(_, witness_id, ..) | OrdOpRef::Extension(_, witness_id, ..) => { - Some(*witness_id) - } - } - } - - pub fn op_ord(&self) -> OpOrd { - match self { - OrdOpRef::Genesis(_) => OpOrd::Genesis, - OrdOpRef::Transition(op, _, witness_ord) => OpOrd::Transition { - witness: *witness_ord, - ty: op.transition_type, - nonce: op.nonce, - opid: op.id(), - }, - OrdOpRef::Extension(op, _, witness_ord) => OpOrd::Extension { - witness: *witness_ord, - ty: op.extension_type, - nonce: op.nonce, - opid: op.id(), - }, - } - } -} - -impl<'op> Operation for OrdOpRef<'op> { - fn op_type(&self) -> OpType { - match self { - OrdOpRef::Genesis(op) => op.op_type(), - OrdOpRef::Transition(op, ..) => op.op_type(), - OrdOpRef::Extension(op, ..) => op.op_type(), - } - } - - fn full_type(&self) -> OpFullType { - match self { - OrdOpRef::Genesis(op) => op.full_type(), - OrdOpRef::Transition(op, ..) => op.full_type(), - OrdOpRef::Extension(op, ..) => op.full_type(), - } - } - - fn id(&self) -> OpId { - match self { - OrdOpRef::Genesis(op) => op.id(), - OrdOpRef::Transition(op, ..) => op.id(), - OrdOpRef::Extension(op, ..) => op.id(), - } - } - - fn contract_id(&self) -> ContractId { - match self { - OrdOpRef::Genesis(op) => op.contract_id(), - OrdOpRef::Transition(op, ..) => op.contract_id(), - OrdOpRef::Extension(op, ..) => op.contract_id(), - } - } - - fn nonce(&self) -> u64 { - match self { - OrdOpRef::Genesis(op) => op.nonce(), - OrdOpRef::Transition(op, ..) => op.nonce(), - OrdOpRef::Extension(op, ..) => op.nonce(), - } - } - - fn transition_type(&self) -> Option { - match self { - OrdOpRef::Genesis(op) => op.transition_type(), - OrdOpRef::Transition(op, ..) => op.transition_type(), - OrdOpRef::Extension(op, ..) => op.transition_type(), - } - } - - fn extension_type(&self) -> Option { - match self { - OrdOpRef::Genesis(op) => op.extension_type(), - OrdOpRef::Transition(op, ..) => op.extension_type(), - OrdOpRef::Extension(op, ..) => op.extension_type(), - } - } - - fn metadata(&self) -> &Metadata { - match self { - OrdOpRef::Genesis(op) => op.metadata(), - OrdOpRef::Transition(op, ..) => op.metadata(), - OrdOpRef::Extension(op, ..) => op.metadata(), - } - } - - fn globals(&self) -> &GlobalState { - match self { - OrdOpRef::Genesis(op) => op.globals(), - OrdOpRef::Transition(op, ..) => op.globals(), - OrdOpRef::Extension(op, ..) => op.globals(), - } - } - - fn valencies(&self) -> &Valencies { - match self { - OrdOpRef::Genesis(op) => op.valencies(), - OrdOpRef::Transition(op, ..) => op.valencies(), - OrdOpRef::Extension(op, ..) => op.valencies(), - } - } - - fn assignments(&self) -> AssignmentsRef<'op> { - match self { - OrdOpRef::Genesis(op) => (&op.assignments).into(), - OrdOpRef::Transition(op, ..) => (&op.assignments).into(), - OrdOpRef::Extension(op, ..) => (&op.assignments).into(), - } - } - - fn assignments_by_type(&self, t: AssignmentType) -> Option> { - match self { - OrdOpRef::Genesis(op) => op.assignments_by_type(t), - OrdOpRef::Transition(op, ..) => op.assignments_by_type(t), - OrdOpRef::Extension(op, ..) => op.assignments_by_type(t), - } - } - - fn inputs(&self) -> Inputs { - match self { - OrdOpRef::Genesis(op) => op.inputs(), - OrdOpRef::Transition(op, ..) => op.inputs(), - OrdOpRef::Extension(op, ..) => op.inputs(), - } - } -} - -#[derive(Getters, Copy, Clone, PartialEq, Eq, Hash, Debug)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_LOGIC)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct WitnessPos { - #[getter(as_copy)] - layer1: Layer1, - - // TODO: Move BlockHeight from bp-wallet to bp-consensus and use it here - #[getter(as_copy)] - height: NonZeroU32, - - #[getter(as_copy)] - timestamp: i64, -} - -impl StrictDumb for WitnessPos { - fn strict_dumb() -> Self { - Self { - layer1: Layer1::Bitcoin, - height: NonZeroU32::MIN, - timestamp: 1231006505, - } - } -} - -// Sat Jan 03 18:15:05 2009 UTC -const BITCOIN_GENESIS_TIMESTAMP: i64 = 1231006505; - -// Sat Jan 03 18:15:05 2009 UTC -const LIQUID_GENESIS_TIMESTAMP: i64 = 1296692202; - -impl WitnessPos { - #[deprecated( - since = "0.11.0-beta.9", - note = "please use `WitnessPos::bitcoin` or `WitnessPos::liquid` instead" - )] - pub fn new(height: NonZeroU32, timestamp: i64) -> Option { - Self::bitcoin(height, timestamp) - } - - pub fn bitcoin(height: NonZeroU32, timestamp: i64) -> Option { - if timestamp < BITCOIN_GENESIS_TIMESTAMP { - return None; - } - Some(WitnessPos { - layer1: Layer1::Bitcoin, - height, - timestamp, - }) - } - - pub fn liquid(height: NonZeroU32, timestamp: i64) -> Option { - if timestamp < LIQUID_GENESIS_TIMESTAMP { - return None; - } - Some(WitnessPos { - layer1: Layer1::Liquid, - height, - timestamp, - }) - } -} - -impl PartialOrd for WitnessPos { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl Ord for WitnessPos { - /// Since we support multiple layer 1, we have to order basing on the - /// timestamp information and not height. The timestamp data are consistent - /// across multiple blockchains, while height evolves with a different - /// speed and can't be used in comparisons. - fn cmp(&self, other: &Self) -> Ordering { - assert!(self.timestamp > 0); - assert!(other.timestamp > 0); - const BLOCK_TIME: i64 = 10 /*min*/ * 60 /*secs*/; - match (self.layer1, other.layer1) { - (a, b) if a == b => self.height.cmp(&other.height), - (Layer1::Bitcoin, Layer1::Liquid) - if (self.timestamp - other.timestamp).abs() >= BLOCK_TIME => - { - Ordering::Greater - } - (Layer1::Liquid, Layer1::Bitcoin) - if (other.timestamp - self.timestamp).abs() >= BLOCK_TIME => - { - Ordering::Less - } - _ => self.timestamp.cmp(&other.timestamp), - } - } -} - -impl Display for WitnessPos { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}:{}, ", self.layer1, self.height)?; - match Utc.timestamp_opt(self.timestamp, 0) { - MappedLocalTime::Single(time) => write!(f, "{}", time.format("%Y-%m-%d %H:%M:%S")), - _ => f.write_str("invalid timestamp"), - } - } -} - -/// RGB consensus information about the status of a witness transaction. This -/// information is used in ordering state transition and state extension -/// processing in the AluVM during the validation, as well as consensus ordering -/// of the contract global state data, as they are presented to all contract -/// users. -#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, Display, From)] -#[display(lowercase)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_LOGIC, tags = order)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum WitnessOrd { - /// Witness transaction must be excluded from the state processing. - /// - /// Cases for the exclusion: - /// - transaction was removed from blockchain after a re-org and its inputs were spent by other - /// transaction; - /// - previous transaction(s) after RBF replacement, once it is excluded from the mempool and - /// replaced by RBFed successors; - /// - past state channel transactions once a new channel state is signed (and until they may - /// become valid once again due to an uncooperative channel closing). - #[strict_type(dumb)] - Archived, - - /// Transaction is included into layer 1 blockchain at a specific height and - /// timestamp. - /// - /// NB: only timestamp is used in consensus ordering though, see - /// [`WitnessPos::cmp`] for the details. - #[from] - #[display(inner)] - Mined(WitnessPos), - - /// Valid witness transaction which commits the most recent RGB state, but - /// is not (yet) included into a layer 1 blockchain. Such transactions have - /// a higher priority over onchain transactions (i.e. they are processed by - /// the VM at the very end, and their global state becomes at the top of the - /// contract state). - /// - /// NB: not each and every signed offchain transaction should have this - /// status; all offchain cases which fall under [`Self::Archived`] must be - /// excluded. Valid cases for assigning [`Self::Tentative`] status are: - /// - transaction is present in the memepool; - /// - transaction is a part of transaction graph inside a state channel (only actual channel - /// state is accounted for; all previous channel state must have corresponding transactions - /// set to [`Self::Archived`]); - /// - transaction is an RBF replacement prepared to be broadcast (with the previous transaction - /// set to [`Self::Archived`] at the same moment). - Tentative, -} - -impl WitnessOrd { - #[inline] - pub fn is_valid(self) -> bool { self != Self::Archived } -} - -/// Operation ordering priority for contract state computation according to -/// [RCP-240731A]. -/// -/// The ordering is the following: -/// - Genesis is processed first. -/// - Other operations are ordered according to their witness transactions (see [`WitnessOrd`] for -/// the details). -/// - Extensions share witness transaction with the state transition which first to close one of the -/// seals defined in the extension, but are processed before that state transition. -/// - If two or more operations share the same witness transaction ordering, they are first ordered -/// basing on their `nonce` value, and if it is also the same, basing on their operation id value. -/// -/// [RCP-240731A]: https://github.com/RGB-WG/RFC/issues/10 -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_LOGIC, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum OpOrd { - #[strict_type(tag = 0x00, dumb)] - Genesis, - #[strict_type(tag = 0x01)] - Extension { - witness: WitnessOrd, - ty: ExtensionType, - nonce: u64, - opid: OpId, - }, - #[strict_type(tag = 0xFF)] - Transition { - witness: WitnessOrd, - ty: TransitionType, - nonce: u64, - opid: OpId, - }, -} - -impl OpOrd { - #[inline] - pub fn is_archived(&self) -> bool { - matches!( - self, - Self::Extension { - witness: WitnessOrd::Archived, - .. - } | Self::Transition { - witness: WitnessOrd::Archived, - .. - } - ) - } -} - -/// Consensus ordering of global state -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_LOGIC)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct GlobalOrd { - pub op_ord: OpOrd, - pub idx: u16, -} - -impl GlobalOrd { - pub fn genesis(idx: u16) -> Self { - Self { - op_ord: OpOrd::Genesis, - idx, - } - } - pub fn transition( - opid: OpId, - idx: u16, - ty: TransitionType, - nonce: u64, - witness: WitnessOrd, - ) -> Self { - Self { - op_ord: OpOrd::Transition { - witness, - ty, - nonce, - opid, - }, - idx, - } - } - pub fn extension( - opid: OpId, - idx: u16, - ty: ExtensionType, - nonce: u64, - witness: WitnessOrd, - ) -> Self { - Self { - op_ord: OpOrd::Extension { - witness, - ty, - nonce, - opid, - }, - idx, - } - } -} - -pub trait GlobalStateIter { - type Data: Borrow; - fn size(&mut self) -> u24; - fn prev(&mut self) -> Option<(GlobalOrd, Self::Data)>; - fn last(&mut self) -> Option<(GlobalOrd, Self::Data)>; - fn reset(&mut self, depth: u24); -} - -impl GlobalStateIter for &mut I { - type Data = I::Data; - - #[inline] - fn size(&mut self) -> u24 { GlobalStateIter::size(*self) } - - #[inline] - fn prev(&mut self) -> Option<(GlobalOrd, Self::Data)> { (*self).prev() } - - #[inline] - fn last(&mut self) -> Option<(GlobalOrd, Self::Data)> { (*self).last() } - - #[inline] - fn reset(&mut self, depth: u24) { (*self).reset(depth) } -} - -pub struct GlobalContractState { - checked_depth: u24, - last_ord: Option, - iter: I, -} - -impl GlobalContractState { - #[inline] - pub fn new(iter: I) -> Self { - Self { - iter, - checked_depth: u24::ONE, - last_ord: None, - } - } - - #[inline] - pub fn size(&mut self) -> u24 { self.iter.size() } - - fn prev_checked(&mut self) -> Option<(GlobalOrd, I::Data)> { - let (ord, item) = self.iter.prev()?; - if self.last_ord.map(|last| ord <= last).unwrap_or_default() { - panic!( - "global contract state iterator has invalid implementation: it fails to order \ - global state according to the consensus ordering" - ); - } - if ord.op_ord.is_archived() { - panic!("invalid GlobalStateIter implementation returning WitnessOrd::Archived") - } - self.checked_depth += u24::ONE; - self.last_ord = Some(ord); - Some((ord, item)) - } - - /// Retrieves global state data located `depth` items back from the most - /// recent global state value. Ensures that the global state ordering is - /// consensus-based. - pub fn nth(&mut self, depth: u24) -> Option + '_> { - if depth >= self.iter.size() { - return None; - } - if depth >= self.checked_depth { - self.iter.reset(depth); - } else { - self.iter.reset(self.checked_depth); - let size = self.iter.size(); - let to = (depth - self.checked_depth).to_u32(); - for inc in 0..to { - if self.prev_checked().is_none() { - panic!( - "global contract state iterator has invalid implementation: it reports \ - more global state items {size} than the contract has ({})", - self.checked_depth + inc - ); - } - } - } - self.iter.last().map(|(_, item)| item) - } -} - -impl Iterator for GlobalContractState { - type Item = I::Data; - - #[inline] - fn next(&mut self) -> Option { Some(self.prev_checked()?.1) } -} - -#[derive(Copy, Clone, Debug, Display, Error)] -#[display("unknown global state type {0} requested from the contract")] -pub struct UnknownGlobalStateType(pub GlobalStateType); - -pub trait ContractStateAccess: Debug { - fn global( - &self, - ty: GlobalStateType, - ) -> Result, UnknownGlobalStateType>; - - fn rights(&self, outpoint: XOutpoint, ty: AssignmentType) -> u32; - - fn fungible( - &self, - outpoint: XOutpoint, - ty: AssignmentType, - ) -> impl DoubleEndedIterator; - - fn data( - &self, - outpoint: XOutpoint, - ty: AssignmentType, - ) -> impl DoubleEndedIterator>; - - fn attach( - &self, - outpoint: XOutpoint, - ty: AssignmentType, - ) -> impl DoubleEndedIterator>; -} - -pub trait ContractStateEvolve { - type Context<'ctx>; - fn init(context: Self::Context<'_>) -> Self; - // TODO: distinguish contract validation failure errors from connectivity - // errors. Allow custom error types here. - fn evolve_state(&mut self, op: OrdOpRef) -> Result<(), confinement::Error>; -} - -pub struct VmContext<'op, S: ContractStateAccess> { - pub contract_id: ContractId, - pub asset_tags: &'op AssetTags, - pub op_info: OpInfo<'op>, - pub contract_state: Rc>, -} - -pub struct OpInfo<'op> { - pub id: OpId, - pub ty: OpFullType, - pub metadata: &'op Metadata, - pub prev_state: &'op Assignments, - pub owned_state: AssignmentsRef<'op>, - pub redeemed: &'op Valencies, - pub valencies: &'op Valencies, - pub global: &'op GlobalState, -} - -impl<'op> OpInfo<'op> { - pub fn with( - id: OpId, - op: &'op OrdOpRef<'op>, - prev_state: &'op Assignments, - redeemed: &'op Valencies, - ) -> Self { - OpInfo { - id, - ty: op.full_type(), - metadata: op.metadata(), - prev_state, - owned_state: op.assignments(), - redeemed, - valencies: op.valencies(), - global: op.globals(), - } - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn witness_post_timestamp() { - assert_eq!(WitnessPos::bitcoin(NonZeroU32::MIN, BITCOIN_GENESIS_TIMESTAMP - 1), None); - assert_eq!(WitnessPos::liquid(NonZeroU32::MIN, LIQUID_GENESIS_TIMESTAMP - 1), None); - assert_eq!(WitnessPos::liquid(NonZeroU32::MIN, BITCOIN_GENESIS_TIMESTAMP), None); - assert!(WitnessPos::bitcoin(NonZeroU32::MIN, BITCOIN_GENESIS_TIMESTAMP).is_some()); - assert!(WitnessPos::liquid(NonZeroU32::MIN, LIQUID_GENESIS_TIMESTAMP).is_some()); - assert!(WitnessPos::bitcoin(NonZeroU32::MIN, LIQUID_GENESIS_TIMESTAMP).is_some()); - } - - #[test] - fn witness_pos_getters() { - let pos = WitnessPos::bitcoin(NonZeroU32::MIN, BITCOIN_GENESIS_TIMESTAMP).unwrap(); - assert_eq!(pos.height(), NonZeroU32::MIN); - assert_eq!(pos.timestamp(), BITCOIN_GENESIS_TIMESTAMP); - assert_eq!(pos.layer1(), Layer1::Bitcoin); - - let pos = WitnessPos::liquid(NonZeroU32::MIN, LIQUID_GENESIS_TIMESTAMP).unwrap(); - assert_eq!(pos.height(), NonZeroU32::MIN); - assert_eq!(pos.timestamp(), LIQUID_GENESIS_TIMESTAMP); - assert_eq!(pos.layer1(), Layer1::Liquid); - } -} diff --git a/src/vm/isa.rs b/src/vm/isa.rs deleted file mode 100644 index 8148b5ef..00000000 --- a/src/vm/isa.rs +++ /dev/null @@ -1,124 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::collections::BTreeSet; -use std::ops::RangeInclusive; - -use aluvm::isa; -use aluvm::isa::{Bytecode, BytecodeError, ExecStep, InstructionSet}; -use aluvm::library::{CodeEofError, IsaSeg, LibSite, Read, Write}; -use aluvm::reg::{CoreRegs, Reg}; - -use super::opcodes::{INSTR_RGBISA_FROM, INSTR_RGBISA_TO}; -use super::{ContractOp, ContractStateAccess, TimechainOp, VmContext}; - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -#[display(inner)] -#[non_exhaustive] -pub enum RgbIsa { - Contract(ContractOp), - - Timechain(TimechainOp), - - /// All other future unsupported operations, which must set `st0` to - /// `false`. - Fail(u8), -} - -impl InstructionSet for RgbIsa { - type Context<'ctx> = VmContext<'ctx, S>; - - fn isa_ids() -> IsaSeg { IsaSeg::with("RGB") } - - fn src_regs(&self) -> BTreeSet { - match self { - RgbIsa::Contract(op) => op.src_regs(), - RgbIsa::Timechain(op) => op.src_regs(), - RgbIsa::Fail(_) => bset![], - } - } - - fn dst_regs(&self) -> BTreeSet { - match self { - RgbIsa::Contract(op) => op.dst_regs(), - RgbIsa::Timechain(op) => op.dst_regs(), - RgbIsa::Fail(_) => bset![], - } - } - - fn complexity(&self) -> u64 { - match self { - RgbIsa::Contract(op) => op.complexity(), - RgbIsa::Timechain(op) => op.complexity(), - RgbIsa::Fail(_) => u64::MAX, - } - } - - fn exec(&self, regs: &mut CoreRegs, site: LibSite, context: &Self::Context<'_>) -> ExecStep { - match self { - RgbIsa::Contract(op) => op.exec(regs, site, context), - RgbIsa::Timechain(op) => op.exec(regs, site, &()), - RgbIsa::Fail(_) => { - isa::ControlFlowOp::Fail.exec(regs, site, &()); - ExecStep::Stop - } - } - } -} - -impl Bytecode for RgbIsa { - fn instr_range() -> RangeInclusive { INSTR_RGBISA_FROM..=INSTR_RGBISA_TO } - - fn instr_byte(&self) -> u8 { - match self { - RgbIsa::Contract(op) => op.instr_byte(), - RgbIsa::Timechain(op) => op.instr_byte(), - RgbIsa::Fail(code) => *code, - } - } - - fn encode_args(&self, writer: &mut W) -> Result<(), BytecodeError> - where W: Write { - match self { - RgbIsa::Contract(op) => op.encode_args(writer), - RgbIsa::Timechain(op) => op.encode_args(writer), - RgbIsa::Fail(_) => Ok(()), - } - } - - fn decode(reader: &mut R) -> Result - where - Self: Sized, - R: Read, - { - let instr = reader.peek_u8()?; - Ok(match instr { - instr if ContractOp::::instr_range().contains(&instr) => { - RgbIsa::Contract(ContractOp::decode(reader)?) - } - instr if TimechainOp::instr_range().contains(&instr) => { - RgbIsa::Timechain(TimechainOp::decode(reader)?) - } - x => RgbIsa::Fail(x), - }) - } -} diff --git a/src/vm/macroasm.rs b/src/vm/macroasm.rs deleted file mode 100644 index 0422e4a0..00000000 --- a/src/vm/macroasm.rs +++ /dev/null @@ -1,66 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#[macro_export] -macro_rules! rgbasm { - ($( $tt:tt )+) => {{ #[allow(unused_imports)] { - use amplify::num::{u4, u5}; - use $crate::vm::{RgbIsa, ContractOp, TimechainOp}; - use $crate::vm::aluasm_isa; - use $crate::isa_instr; - aluasm_isa! { RgbIsa<_> => $( $tt )+ } - } }}; -} - -#[macro_export] -macro_rules! isa_instr { - (pcvs $no:ident) => {{ - RgbIsa::Contract(ContractOp::Pcvs($no)) - }}; - (pcas $no:ident) => {{ - RgbIsa::Contract(ContractOp::Pcas($no)) - }}; - (pcps $no:ident) => {{ - RgbIsa::Contract(ContractOp::Pcps($no)) - }}; - (cng $t:ident,a8[$a_idx:literal]) => {{ - RgbIsa::Contract(ContractOp::CnG($t, Reg32::from(u5::with($a_idx)))) - }}; - (cnc $t:ident,a16[$a_idx:literal]) => {{ - RgbIsa::Contract(ContractOp::CnC($t, Reg32::from(u5::with($a_idx)))) - }}; - (ldm $t:ident,s16[$s_idx:literal]) => {{ - RgbIsa::Contract(ContractOp::LdM($t, RegS::from($s_idx))) - }}; - (ldg $t:ident,a8[$a_idx:literal],s16[$s_idx:literal]) => {{ - RgbIsa::Contract(ContractOp::LdG($t, Reg16::from(u4::with($a_idx)), RegS::from($s_idx))) - }}; - (ldp $t:ident,a16[$a_idx:literal],s16[$s_idx:literal]) => {{ - RgbIsa::Contract(ContractOp::LdP($t, Reg16::from(u4::with($a_idx)), RegS::from($s_idx))) - }}; - (lds $t:ident,a16[$a_idx:literal],s16[$s_idx:literal]) => {{ - RgbIsa::Contract(ContractOp::LdS($t, Reg16::from(u4::with($a_idx)), RegS::from($s_idx))) - }}; - ($op:ident $($tt:tt)+) => {{ - compile_error!(concat!("unknown RGB assembly opcode `", stringify!($op), "`")) - }}; -} diff --git a/src/vm/mod.rs b/src/vm/mod.rs deleted file mode 100644 index 89ccf6ad..00000000 --- a/src/vm/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! API for interfacing different virtual machines -//! -//! Concrete virtual machine implementations must be wrapped into this API - -pub mod opcodes; -mod isa; -mod op_contract; -mod op_timechain; -#[macro_use] -mod macroasm; -mod contract; - -pub use aluvm::aluasm_isa; -pub use contract::{ - ContractStateAccess, ContractStateEvolve, GlobalContractState, GlobalOrd, GlobalStateIter, - OpOrd, OrdOpRef, UnknownGlobalStateType, WitnessOrd, WitnessPos, XWitnessId, XWitnessTx, -}; -pub(crate) use contract::{OpInfo, VmContext}; -pub use isa::RgbIsa; -pub use op_contract::ContractOp; -pub use op_timechain::TimechainOp; diff --git a/src/vm/op_contract.rs b/src/vm/op_contract.rs deleted file mode 100644 index 5d971ff9..00000000 --- a/src/vm/op_contract.rs +++ /dev/null @@ -1,673 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::unusual_byte_groupings)] - -use std::borrow::Borrow; -use std::cell::RefCell; -use std::collections::BTreeSet; -use std::marker::PhantomData; -use std::ops::RangeInclusive; - -use aluvm::isa::{Bytecode, BytecodeError, ExecStep, InstructionSet}; -use aluvm::library::{CodeEofError, IsaSeg, LibSite, Read, Write}; -use aluvm::reg::{CoreRegs, Reg, Reg16, Reg32, RegA, RegS}; -use amplify::num::{u24, u3, u4}; -use amplify::Wrapper; -use commit_verify::CommitVerify; - -use super::opcodes::*; -use super::{ContractStateAccess, VmContext}; -use crate::{ - Assign, AssignmentType, BlindingFactor, GlobalStateType, MetaType, PedersenCommitment, - RevealedValue, TypedAssigns, -}; - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -pub enum ContractOp { - /// Counts number of inputs (previous state entries) of the provided type - /// and puts the number to the destination `a16` register. - /// - /// If the operation doesn't contain inputs with a given assignment type, - /// sets destination index to zero. Does not change `st0` register. - #[display("cnp {0},a16{1}")] - CnP(AssignmentType, Reg32), - - /// Counts number of outputs (owned state entries) of the provided type - /// and puts the number to the destination `a16` register. - /// - /// If the operation doesn't contain inputs with a given assignment type, - /// sets destination index to zero. Does not change `st0` register. - #[display("cns {0},a16{1}")] - CnS(AssignmentType, Reg32), - - /// Counts number of global state items of the provided type affected by the - /// current operation and puts the number to the destination `a8` register. - /// - /// If the operation doesn't contain inputs with a given assignment type, - /// sets destination index to zero. Does not change `st0` register. - #[display("cng {0},a8{1}")] - CnG(GlobalStateType, Reg32), - - /// Counts number of global state items of the provided type in the contract - /// state and puts the number to the destination `a32` register. - /// - /// If the operation doesn't contain inputs with a given assignment type, - /// sets destination index to zero. Does not change `st0` register. - #[display("cnc {0},a32{1}")] - CnC(GlobalStateType, Reg32), - - /// Loads input (previous) structured state with type id from the first - /// argument and index from the second argument `a16` register into a - /// register provided in the third argument. - /// - /// If the state is absent or is not a structured state sets `st0` to - /// `false` and terminates the program. - /// - /// If the state at the index is concealed, sets destination to `None`. - #[display("ldp {0},a16{1},{2}")] - LdP(AssignmentType, Reg16, RegS), - - /// Loads owned structured state with type id from the first argument and - /// index from the second argument `a16` register into a register provided - /// in the third argument. - /// - /// If the state is absent or is not a structured state sets `st0` to - /// `false` and terminates the program. - /// - /// If the state at the index is concealed, sets destination to `None`. - #[display("lds {0},a16{1},{2}")] - LdS(AssignmentType, Reg16, RegS), - - /// Loads owned fungible state with type id from the first argument and - /// index from the second argument `a16` register into `a64` register - /// provided in the third argument. - /// - /// If the state is absent or is not a fungible state sets `st0` to - /// `false` and terminates the program. - /// - /// If the state at the index is concealed, sets destination to `None`. - #[display("ldf {0},a16{1},a64{2}")] - LdF(AssignmentType, Reg16, Reg16), - - /// Loads global state from the current operation with type id from the - /// first argument and index from the second argument `a8` register into a - /// register provided in the third argument. - /// - /// If the state is absent sets `st0` to `false` and terminates the program. - #[display("ldg {0},a8{1},{2}")] - LdG(GlobalStateType, Reg16, RegS), - - /// Loads part of the contract global state with type id from the first - /// argument at the depth from the second argument `a32` register into a - /// register provided in the third argument. - /// - /// If the contract doesn't have the provided global state type, or it - /// doesn't contain a value at the requested index, sets `st0` - /// to fail state and terminates the program. The value of the - /// destination register is not changed. - #[display("ldc {0},a32{1},{2}")] - LdC(GlobalStateType, Reg16, RegS), - - /// Loads operation metadata with a type id from the first argument into a - /// register provided in the second argument. - /// - /// If the operation doesn't have metadata, sets `st0` to fail state and - /// terminates the program. The value of the destination register is not - /// changed. - #[display("ldm {0},{1}")] - LdM(MetaType, RegS), - - /// Verify sum of pedersen commitments from inputs and outputs. - /// - /// The only argument specifies owned state type for the sum operation. If - /// this state does not exist, or either inputs or outputs does not have - /// any data for the state, the verification fails. - /// - /// If verification succeeds, doesn't change `st0` value; otherwise sets it - /// to `false` and stops execution. - #[display("pcvs {0}")] - Pcvs(AssignmentType), - - /// Verifies equivalence of a sum of pedersen commitments for the list of - /// assignment outputs to a value from `a64[0]` register. - /// - /// The first argument specifies owned state type for the sum operation. If - /// this state does not exist, or either inputs or outputs does not have - /// any data for the state, the verification fails. - /// - /// If `a64[0]` register does not contain value, the verification fails. - /// - /// If verification succeeds, doesn't change `st0` value; otherwise sets it - /// to `false` and stops execution. - #[display("pcas {0}")] - Pcas(/** owned state type */ AssignmentType), - - /// Verifies equivalence of a sum of pedersen commitments for the list of - /// inputs to a value from `a64[0]` register. - /// - /// The first argument specifies owned state type for the sum operation. If - /// this state does not exist, or either inputs or outputs does not have - /// any data for the state, the verification fails. - /// - /// If `a64[0]` register does not contain value, the verification fails. - /// - /// If verification succeeds, doesn't change `st0` value; otherwise sets it - /// to `false` and stops execution. - #[display("pcps {0}")] - Pcps(/** owned state type */ AssignmentType), - - /// All other future unsupported operations, which must set `st0` to - /// `false` and stop the execution. - #[display("fail {0}")] - Fail(u8, PhantomData), -} - -impl InstructionSet for ContractOp { - type Context<'ctx> = VmContext<'ctx, S>; - - fn isa_ids() -> IsaSeg { IsaSeg::with("RGB") } - - fn src_regs(&self) -> BTreeSet { - match self { - ContractOp::LdP(_, reg, _) - | ContractOp::LdF(_, reg, _) - | ContractOp::LdS(_, reg, _) => bset![Reg::A(RegA::A16, (*reg).into())], - ContractOp::LdG(_, reg, _) => bset![Reg::A(RegA::A8, (*reg).into())], - ContractOp::LdC(_, reg, _) => bset![Reg::A(RegA::A32, (*reg).into())], - - ContractOp::CnP(_, _) - | ContractOp::CnS(_, _) - | ContractOp::CnG(_, _) - | ContractOp::CnC(_, _) - | ContractOp::LdM(_, _) => bset![], - ContractOp::Pcvs(_) => bset![], - ContractOp::Pcas(_) | ContractOp::Pcps(_) => bset![Reg::A(RegA::A64, Reg32::Reg0)], - ContractOp::Fail(_, _) => bset![], - } - } - - fn dst_regs(&self) -> BTreeSet { - match self { - ContractOp::CnG(_, reg) => { - bset![Reg::A(RegA::A8, *reg)] - } - ContractOp::CnP(_, reg) | ContractOp::CnS(_, reg) | ContractOp::CnC(_, reg) => { - bset![Reg::A(RegA::A16, *reg)] - } - ContractOp::LdF(_, _, reg) => { - bset![Reg::A(RegA::A64, (*reg).into())] - } - ContractOp::LdG(_, _, reg) - | ContractOp::LdS(_, _, reg) - | ContractOp::LdP(_, _, reg) - | ContractOp::LdC(_, _, reg) - | ContractOp::LdM(_, reg) => { - bset![Reg::S(*reg)] - } - ContractOp::Pcvs(_) | ContractOp::Pcas(_) | ContractOp::Pcps(_) => { - bset![] - } - ContractOp::Fail(_, _) => bset![], - } - } - - fn complexity(&self) -> u64 { - match self { - ContractOp::CnP(_, _) - | ContractOp::CnS(_, _) - | ContractOp::CnG(_, _) - | ContractOp::CnC(_, _) => 2, - ContractOp::LdP(_, _, _) - | ContractOp::LdS(_, _, _) - | ContractOp::LdF(_, _, _) - | ContractOp::LdG(_, _, _) - | ContractOp::LdC(_, _, _) => 8, - ContractOp::LdM(_, _) => 6, - ContractOp::Pcvs(_) => 1024, - ContractOp::Pcas(_) | ContractOp::Pcps(_) => 512, - ContractOp::Fail(_, _) => u64::MAX, - } - } - - fn exec(&self, regs: &mut CoreRegs, _site: LibSite, context: &Self::Context<'_>) -> ExecStep { - macro_rules! fail { - () => {{ - regs.set_failure(); - return ExecStep::Stop; - }}; - } - macro_rules! load_inputs { - ($state_type:ident) => {{ - let Some(prev_state) = context.op_info.prev_state.get($state_type) else { - fail!() - }; - match prev_state { - TypedAssigns::Fungible(state) => state - .iter() - .map(Assign::to_confidential_state) - .map(|s| s.commitment.into_inner()) - .collect::>(), - _ => fail!(), - } - }}; - } - macro_rules! load_outputs { - ($state_type:ident) => {{ - let Some(new_state) = context.op_info.owned_state.get(*$state_type) else { - fail!() - }; - match new_state { - TypedAssigns::Fungible(state) => state - .iter() - .map(Assign::to_confidential_state) - .map(|s| s.commitment.into_inner()) - .collect::>(), - _ => fail!(), - } - }}; - } - - match self { - ContractOp::CnP(state_type, reg) => { - regs.set_n( - RegA::A16, - *reg, - context - .op_info - .prev_state - .get(state_type) - .map(|a| a.len_u16()), - ); - } - ContractOp::CnS(state_type, reg) => { - regs.set_n( - RegA::A16, - *reg, - context - .op_info - .owned_state - .get(*state_type) - .map(|a| a.len_u16()), - ); - } - ContractOp::CnG(state_type, reg) => { - regs.set_n( - RegA::A8, - *reg, - context.op_info.global.get(state_type).map(|a| a.len_u16()), - ); - } - ContractOp::CnC(state_type, reg) => { - if let Ok(mut global) = RefCell::borrow(&context.contract_state).global(*state_type) - { - regs.set_n(RegA::A32, *reg, global.size().to_u32()); - } else { - regs.set_n(RegA::A32, *reg, None::); - } - } - ContractOp::LdP(state_type, reg_32, reg) => { - let Some(reg_32) = *regs.get_n(RegA::A16, *reg_32) else { - fail!() - }; - let index: u16 = reg_32.into(); - - let Some(Ok(state)) = context - .op_info - .prev_state - .get(state_type) - .map(|a| a.as_structured_state_at(index)) - else { - fail!() - }; - let state = state.map(|s| s.value.as_inner()); - regs.set_s(*reg, state); - } - ContractOp::LdS(state_type, reg_32, reg) => { - let Some(reg_32) = *regs.get_n(RegA::A16, *reg_32) else { - fail!() - }; - let index: u16 = reg_32.into(); - - let Some(Ok(state)) = context - .op_info - .owned_state - .get(*state_type) - .map(|a| a.into_structured_state_at(index)) - else { - fail!() - }; - let state = state.map(|s| s.value.into_inner()); - regs.set_s(*reg, state); - } - ContractOp::LdF(state_type, reg_32, reg) => { - let Some(reg_32) = *regs.get_n(RegA::A16, *reg_32) else { - fail!() - }; - let index: u16 = reg_32.into(); - - let Some(Ok(state)) = context - .op_info - .owned_state - .get(*state_type) - .map(|a| a.into_fungible_state_at(index)) - else { - fail!() - }; - regs.set_n(RegA::A64, *reg, state.map(|s| s.value.as_u64())); - } - ContractOp::LdG(state_type, reg_8, reg_s) => { - let Some(reg_32) = *regs.get_n(RegA::A8, *reg_8) else { - fail!() - }; - let index: u8 = reg_32.into(); - - let Some(state) = context - .op_info - .global - .get(state_type) - .and_then(|a| a.get(index as usize)) - else { - fail!() - }; - regs.set_s(*reg_s, Some(state.as_inner())); - } - - ContractOp::LdC(state_type, reg_32, reg_s) => { - let state = RefCell::borrow(&context.contract_state); - let Ok(mut global) = state.global(*state_type) else { - fail!() - }; - let Some(reg_32) = *regs.get_n(RegA::A32, *reg_32) else { - fail!() - }; - let index: u32 = reg_32.into(); - let Ok(index) = u24::try_from(index) else { - fail!() - }; - let Some(state) = global.nth(index) else { - fail!() - }; - regs.set_s(*reg_s, Some(state.borrow().as_inner())); - } - ContractOp::LdM(type_id, reg) => { - let Some(meta) = context.op_info.metadata.get(type_id) else { - fail!() - }; - regs.set_s(*reg, Some(meta.to_inner())); - } - - ContractOp::Pcvs(state_type) => { - let inputs = load_inputs!(state_type); - let outputs = load_outputs!(state_type); - if !secp256k1_zkp::verify_commitments_sum_to_equal( - secp256k1_zkp::SECP256K1, - &inputs, - &outputs, - ) { - fail!() - } - } - - ContractOp::Pcas(owned_state) => { - let Some(sum) = *regs.get_n(RegA::A64, Reg32::Reg0) else { - fail!() - }; - let sum = u64::from(sum); - - let Some(tag) = context.asset_tags.get(owned_state) else { - fail!() - }; - let sum = RevealedValue::with_blinding(sum, BlindingFactor::EMPTY, *tag); - - let inputs = [PedersenCommitment::commit(&sum).into_inner()]; - let outputs = load_outputs!(owned_state); - - if !secp256k1_zkp::verify_commitments_sum_to_equal( - secp256k1_zkp::SECP256K1, - &inputs, - &outputs, - ) { - fail!() - } - } - - ContractOp::Pcps(owned_state) => { - let Some(sum) = *regs.get_n(RegA::A64, Reg32::Reg0) else { - fail!() - }; - let sum = u64::from(sum); - - let Some(tag) = context.asset_tags.get(owned_state) else { - fail!() - }; - let sum = RevealedValue::with_blinding(sum, BlindingFactor::EMPTY, *tag); - - let inputs = [PedersenCommitment::commit(&sum).into_inner()]; - let outputs = load_inputs!(owned_state); - - if !secp256k1_zkp::verify_commitments_sum_to_equal( - secp256k1_zkp::SECP256K1, - &inputs, - &outputs, - ) { - fail!() - } - } - // All other future unsupported operations, which must set `st0` to `false`. - _ => fail!(), - } - ExecStep::Next - } -} - -impl Bytecode for ContractOp { - fn instr_range() -> RangeInclusive { INSTR_CONTRACT_FROM..=INSTR_CONTRACT_TO } - - fn instr_byte(&self) -> u8 { - match self { - ContractOp::CnP(_, _) => INSTR_CNP, - ContractOp::CnS(_, _) => INSTR_CNS, - ContractOp::CnG(_, _) => INSTR_CNG, - ContractOp::CnC(_, _) => INSTR_CNC, - - ContractOp::LdG(_, _, _) => INSTR_LDG, - ContractOp::LdS(_, _, _) => INSTR_LDS, - ContractOp::LdP(_, _, _) => INSTR_LDP, - ContractOp::LdF(_, _, _) => INSTR_LDF, - ContractOp::LdC(_, _, _) => INSTR_LDC, - ContractOp::LdM(_, _) => INSTR_LDM, - - ContractOp::Pcvs(_) => INSTR_PCVS, - ContractOp::Pcas(_) => INSTR_PCAS, - ContractOp::Pcps(_) => INSTR_PCPS, - - ContractOp::Fail(other, _) => *other, - } - } - - fn encode_args(&self, writer: &mut W) -> Result<(), BytecodeError> - where W: Write { - match self { - ContractOp::CnP(state_type, reg) => { - writer.write_u16(*state_type)?; - writer.write_u5(reg)?; - writer.write_u3(u3::ZERO)?; - } - ContractOp::CnS(state_type, reg) => { - writer.write_u16(*state_type)?; - writer.write_u5(reg)?; - writer.write_u3(u3::ZERO)?; - } - ContractOp::CnG(state_type, reg) => { - writer.write_u16(*state_type)?; - writer.write_u5(reg)?; - writer.write_u3(u3::ZERO)?; - } - ContractOp::CnC(state_type, reg) => { - writer.write_u16(*state_type)?; - writer.write_u5(reg)?; - writer.write_u3(u3::ZERO)?; - } - ContractOp::LdP(state_type, reg_a, reg_s) => { - writer.write_u16(*state_type)?; - writer.write_u4(reg_a)?; - writer.write_u4(reg_s)?; - } - ContractOp::LdS(state_type, reg_a, reg_s) => { - writer.write_u16(*state_type)?; - writer.write_u4(reg_a)?; - writer.write_u4(reg_s)?; - } - ContractOp::LdF(state_type, reg_a, reg_dst) => { - writer.write_u16(*state_type)?; - writer.write_u4(reg_a)?; - writer.write_u4(reg_dst)?; - } - ContractOp::LdG(state_type, reg_a, reg_s) => { - writer.write_u16(*state_type)?; - writer.write_u4(reg_a)?; - writer.write_u4(reg_s)?; - } - ContractOp::LdC(state_type, reg_a, reg_s) => { - writer.write_u16(*state_type)?; - writer.write_u4(reg_a)?; - writer.write_u4(reg_s)?; - } - ContractOp::LdM(state_type, reg) => { - writer.write_u16(*state_type)?; - writer.write_u4(reg)?; - writer.write_u4(u4::ZERO)?; - } - - ContractOp::Pcvs(state_type) => writer.write_u16(*state_type)?, - ContractOp::Pcas(owned_type) => writer.write_u16(*owned_type)?, - ContractOp::Pcps(owned_type) => writer.write_u16(*owned_type)?, - - ContractOp::Fail(_, _) => {} - } - Ok(()) - } - - fn decode(reader: &mut R) -> Result - where - Self: Sized, - R: Read, - { - Ok(match reader.read_u8()? { - INSTR_CNP => { - let i = Self::CnP(reader.read_u16()?.into(), reader.read_u5()?.into()); - reader.read_u3()?; // Discard garbage bits - i - } - INSTR_CNS => { - let i = Self::CnS(reader.read_u16()?.into(), reader.read_u5()?.into()); - reader.read_u3()?; // Discard garbage bits - i - } - INSTR_CNG => { - let i = Self::CnG(reader.read_u16()?.into(), reader.read_u5()?.into()); - reader.read_u3()?; // Discard garbage bits - i - } - INSTR_CNC => { - let i = Self::CnC(reader.read_u16()?.into(), reader.read_u5()?.into()); - reader.read_u3()?; // Discard garbage bits - i - } - - INSTR_LDP => Self::LdP( - reader.read_u16()?.into(), - reader.read_u4()?.into(), - reader.read_u4()?.into(), - ), - INSTR_LDF => Self::LdF( - reader.read_u16()?.into(), - reader.read_u4()?.into(), - reader.read_u4()?.into(), - ), - INSTR_LDG => Self::LdG( - reader.read_u16()?.into(), - reader.read_u4()?.into(), - reader.read_u4()?.into(), - ), - INSTR_LDS => Self::LdS( - reader.read_u16()?.into(), - reader.read_u4()?.into(), - reader.read_u4()?.into(), - ), - INSTR_LDC => Self::LdC( - reader.read_u16()?.into(), - reader.read_u4()?.into(), - reader.read_u4()?.into(), - ), - INSTR_LDM => { - let i = Self::LdM(reader.read_u16()?.into(), reader.read_u4()?.into()); - reader.read_u4()?; // Discard garbage bits - i - } - - INSTR_PCVS => Self::Pcvs(reader.read_u16()?.into()), - INSTR_PCAS => Self::Pcas(reader.read_u16()?.into()), - INSTR_PCPS => Self::Pcps(reader.read_u16()?.into()), - - x => Self::Fail(x, PhantomData), - }) - } -} - -// TODO: Re-enable once we will have a test ContractState object -/* -#[cfg(test)] -mod test { - use aluvm::isa::Instr; - use aluvm::library::Lib; - use amplify::hex::ToHex; - use strict_encoding::StrictSerialize; - - use super::*; - use crate::vm::RgbIsa; - - #[test] - fn encoding() { - let code = - [Instr::ExtensionCodes(RgbIsa::Contract(ContractOp::Pcvs(AssignmentType::from(4000))))]; - let alu_lib = Lib::assemble(&code).unwrap(); - eprintln!("{alu_lib}"); - let alu_id = alu_lib.id(); - - assert_eq!( - alu_id.to_string(), - "alu:zI4PtPCR-Eut023!-Hqblf3X-N2J4GZb-TR2ZEsI-vQfhKOU#ruby-sherman-tonight" - ); - assert_eq!(alu_lib.code.as_ref().to_hex(), "d0a00f"); - assert_eq!( - alu_lib - .to_strict_serialized::<{ usize::MAX }>() - .unwrap() - .to_hex(), - "0303414c55084250444947455354035247420300d0a00f000000" - ); - assert_eq!(alu_lib.disassemble::>>().unwrap(), code); - } -} -*/ diff --git a/src/vm/op_timechain.rs b/src/vm/op_timechain.rs deleted file mode 100644 index d258f29d..00000000 --- a/src/vm/op_timechain.rs +++ /dev/null @@ -1,88 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::collections::BTreeSet; -use std::ops::RangeInclusive; - -use aluvm::isa::{Bytecode, BytecodeError, ExecStep, InstructionSet}; -use aluvm::library::{CodeEofError, IsaSeg, LibSite, Read, Write}; -use aluvm::reg::{CoreRegs, Reg}; - -use super::opcodes::{INSTR_TIMECHAIN_FROM, INSTR_TIMECHAIN_TO}; - -// TODO: Implement bitcoin blockchain introspection - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] -#[display(inner)] -#[non_exhaustive] -pub enum TimechainOp { - Fail, -} - -impl InstructionSet for TimechainOp { - type Context<'ctx> = (); - - fn isa_ids() -> IsaSeg { IsaSeg::with("RGB") } - - fn src_regs(&self) -> BTreeSet { bset![] } - - fn dst_regs(&self) -> BTreeSet { bset![] } - - fn complexity(&self) -> u64 { u64::MAX } - - fn exec(&self, regs: &mut CoreRegs, _site: LibSite, _context: &Self::Context<'_>) -> ExecStep { - match self { - TimechainOp::Fail => { - regs.set_failure(); - ExecStep::Stop - } - } - } -} - -impl Bytecode for TimechainOp { - fn instr_range() -> RangeInclusive { INSTR_TIMECHAIN_FROM..=INSTR_TIMECHAIN_TO } - - fn instr_byte(&self) -> u8 { - match self { - TimechainOp::Fail => INSTR_TIMECHAIN_FROM, - } - } - - fn encode_args(&self, _writer: &mut W) -> Result<(), BytecodeError> - where W: Write { - match self { - TimechainOp::Fail => Ok(()), - } - } - - fn decode(reader: &mut R) -> Result - where - Self: Sized, - R: Read, - { - match reader.read_u8()? { - INSTR_TIMECHAIN_FROM..=INSTR_TIMECHAIN_TO => Ok(Self::Fail), - _ => unreachable!(), - } - } -} diff --git a/src/vm/opcodes.rs b/src/vm/opcodes.rs deleted file mode 100644 index b1db3ea4..00000000 --- a/src/vm/opcodes.rs +++ /dev/null @@ -1,60 +0,0 @@ -// RGB Core Library: consensus layer for RGB smart contracts. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// Copyright (C) 2019-2024 Dr Maxim Orlovsky. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::unusual_byte_groupings)] - -use aluvm::isa::opcodes::INSTR_ISAE_TO; - -pub const INSTR_RGBISA_FROM: u8 = 0b10_010_000; -pub const INSTR_RGBISA_TO: u8 = INSTR_ISAE_TO; - -// CONTRACTS: -pub const INSTR_CNP: u8 = 0b11_000_000; -pub const INSTR_CNS: u8 = 0b11_000_001; -pub const INSTR_CNG: u8 = 0b11_000_010; -pub const INSTR_CNC: u8 = 0b11_000_011; - -pub const INSTR_LDP: u8 = 0b11_000_100; -pub const INSTR_LDS: u8 = 0b11_000_101; -pub const INSTR_LDF: u8 = 0b11_000_110; -// Reserved 0b11_000_111 - -pub const INSTR_LDG: u8 = 0b11_001_000; -pub const INSTR_LDC: u8 = 0b11_001_001; -pub const INSTR_LDM: u8 = 0b11_001_010; -// Reserved 0b11_001_111 - -pub const INSTR_PCVS: u8 = 0b11_010_000; -pub const INSTR_PCAS: u8 = 0b11_010_001; -pub const INSTR_PCPS: u8 = 0b11_010_010; -// Reserved 0b11_010_011 -pub const INSTR_CONTRACT_FROM: u8 = 0b11_000_000; -pub const INSTR_CONTRACT_TO: u8 = 0b11_010_011; - -// TIMECHAIN: -pub const INSTR_TIMECHAIN_FROM: u8 = 0b11_011_100; -pub const INSTR_TIMECHAIN_TO: u8 = 0b11_011_111; - -// Reserved 0b11_011_100 -// Reserved 0b11_011_101 -// Reserved 0b11_011_110 -// Reserved 0b11_011_111 diff --git a/stl/AnchoredBundle.vesper b/stl/AnchoredBundle.vesper deleted file mode 100644 index 70188880..00000000 --- a/stl/AnchoredBundle.vesper +++ /dev/null @@ -1,279 +0,0 @@ -{- - Description: RGB Anchored Bundles - Author: Dr Maxim Orlovsky - Copyright (C) 2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --} - -Bundles vesper lexicon=types+commitments - -BundleId commitment hasher=SHA256 tagged=urn:lnp-bp:rgb:bundle#2024-02-03 - Method serialized - InputMap serialized - -DbcProof union - tapret rec TapretProof wrapped tag=0 - pathProof rec TapretPathProof - some union TapretNodePartner option wrapped tag=1 - rightBranch rec TapretRightBranch wrapped tag=2 - nonce is U8 - opret is Unit wrapped aka=OpretProof tag=1 - -TransitionBundle rec - closeMethod enum Method opretFirst=0 tapretFirst=1 - inputMap map len=1..MAX16 aka=InputMap - key is U32 aka=Vout - value bytes len=32 aka=OpId - knownTransitions map len=1..MAX16 - key bytes len=32 aka=OpId - value rec Transition - ffv is U16 aka=Ffv - contractId bytes len=32 aka=ContractId - nonce is U64 - transitionType is U16 aka=TransitionType - metadata map len=0..MAX8 aka=Metadata - key is U16 aka=MetaType - value bytes len=0..MAX16 aka=MetaValue - globals map len=0..MAX8 aka=GlobalState - key is U16 aka=GlobalStateType - value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=DataState - inputs set len=0..MAX16 aka=Inputs - Input rec - prevOut rec Opout - op bytes len=32 aka=OpId - ty is U16 aka=AssignmentType - no is U16 - reserved bytes len=2 aka=ReservedBytes2 - assignments map len=0..MAX8 aka=AssignmentsBlindSealTxPtr - key is U16 aka=AssignmentType - value union TypedAssignsBlindSealTxPtr - declarative list len=0..MAX16 wrapped tag=0 - AssignVoidStateBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - fungible list len=0..MAX16 wrapped tag=1 - AssignRevealedValueBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - structured list len=0..MAX16 wrapped tag=2 - AssignRevealedDataBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - attachment list len=0..MAX16 wrapped tag=3 - AssignRevealedAttachBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 - valencies set len=0..MAX8 aka=Valencies - element is U16 aka=ValencyType - validator bytes len=1 aka=ReservedBytes1 - witness bytes len=2 aka=ReservedBytes2 - diff --git a/stl/RGBCommit@0.1.0.sta b/stl/RGBCommit@0.1.0.sta deleted file mode 100644 index 67979284..00000000 --- a/stl/RGBCommit@0.1.0.sta +++ /dev/null @@ -1,270 +0,0 @@ ------BEGIN STRICT TYPE LIB----- -Id: stl:IFcnrPeI-TANxLfZ-feJax6Q-1TUM4Hq-AjI161s-3tbmxak#harvest-person-orion -Name: RGBCommit -Dependencies: - StrictTypes#century-comrade-chess, - BPCore#austin-story-retro, - AluVM#congo-archive-folio, - CommitVerify#miller-pancake-elastic, - Std#ralph-blue-lucky, - Bitcoin#signal-color-cipher -Check-SHA256: 1d68b2a0bcfecf99effcecd7c9c35f870a1300e71a3ce3da8144587537895235 - -2~tNwLvL+uX>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI)Q*?4^V{}w`aAk8=6V}(%hjW>8 -uUwNXi!t*yd7K}=K!`A`1OPgv%fUznLQq3*a%Ez0HGd)H4E? -M+l67UG^w8*<_XZ#%uyqCj(P-Wc6$lVk7oBr%DNv+($;q`HHK!gIHa)*%m(-e#9sm3I{@IbYpL6ZUzNG -Y;{&m0sw9Ap(f$Hb>aU=OZ$bvG|>z)+>9PT;Au-7)~D;-++hbyX<}1pbY-V7RRS&fT*&Z=qeY@Wmfle* -z!SF)@h8|JkU^FEQwjx4X<|ua20~CnZ*pY?04}!>CAn^87TS9h9ibhaZ&^Bcn*B*;w|~I;-PD|t>jq6_ -bZBp6MklB)P_)|`Y=H7dO_e!^G2i>0SdC0NppV!6v|_i_4nk~cZe&wsVQf@*P;_!=8SA{&vly$FvzVnz -Hf7z~rv`86=_Ka^V5yX|y#`JSQ)OdvWpq?<6X>I}lA>%$n -#j0HLDJN5-IKgM_J7b(p+0MPGk2Gl)y2(Rz1Xgc#bfbbo^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1 -Rs>XdX=DsTZ*6U9bXH|@X=Zr^063mQh9?yTI7S;;e;>sZfv!yd427@;7veO2zMB=|GYU;*a%*g5NMUnm -ZLh7x^`{^P$fKg#%8c8X#<$(NgM!uni2C|Kr}onZ3R84)X=8LqVRLAc_h5K%L=laq&yA1JoJ^{7>oKLk -F4~iax8KK|47hp@Qe|^xa&~28LV0v$b1}=fEj#9D^K)f#Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RawDWpib6 -c4cHjd30rSGX8=VN#A(BKKz&v`r;e6DUv<<*U}cmb;*F>vukd; -=m`ygb@x#_>`RmOO$0)3Z)}yry~#}iVEJ)s5j^%uEnQ9{n2s|9Fa^ps+HG#`XS5DMY;b5{PIYZeZ)9O} -Xt{%a=RmHK6WZ%EWRm@*ULd%lgGoFTxUTU -76^nC$%1sKzB<;EQA|)S-x88IWKN#S$#@T&w`gPtRC#b^PGN0jYXqYdo~D%m7H6OD0<^0n_2##VWXRdj -y=DB@qgYOj1yf~hNn}O<2|;XhOksItaxnt|25f0@b!lV)3_)ykOksItaxqh7bOiwb2?5A!f_n>Eea4Xl -By!~v3=AX`3Ri0000000000{{R3000000B0+O=X=iRyWp-s@Y-MCYbaY{3XhLjhZe&wsVQf@*P;_zx1ONKtpQ8M_qJyiO1VIUJ=H=)@ii_1#@&^bY%hjG)3KC -&kYOztQDksx&yAAHY;R+00(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@O -Cd;@jJLYKfb7gWS-+`&{Sr=ykNJ#YFTr_BQwWqKF0Ra(XZ*FF3WMyu2X<=+rbYXO500sjDb7f&{0gt=F -=tr7PJW4?*h+3X!X@fjr@d0IimUQ-Q1Z;0(YXW)$9p7nv%krpqNJW4?*h+3X! -X@fjr@d0IimUQ-Q1Z;0(YXW)$9p7nv%krpqNc;WdH^P1aoC!YypA{4XEgn0epQk*PX+nL>xOm%pK>soMo}bYXO50sJ&Y-CxfQ3;(PYq10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)y -umJ%A5Mys{W@%()Zggp3Y*S@nYybuW1aoC!YysPfS{i~B5OpZ>_>4e9YQ#rfba;u!+d5tm#=h2RwFCuo -bYXO50p}%){+CCYqok=CI6O*0D2Q5~XK8~xVetWFewK9hZ3Jv@V`~C>10COKearHwcS=7M7YzYaI8*bv -hMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%B2y$h1WnpY(WB>*O1aoC!YypA{ -4XEgn0epQk*PX+nL>xOm%pK>soMo}bYXO50p}%){+CCYqok=CI6O*0D2Q5~XK8~xVetWF -ewK9hZ3Jv@V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^ -^xj-FXm+)yumJ%eL349yXKqquc4c8~Wn@HQbYVhlX>MdwWnpYocu;h51OxyKV{dL|X=G(?bZKF100sjD -b7f&{0o#gN8iEuMbtv-qj6g$b#7A9pc!|f`I$jaRzSe2A1O;<+VRU5ya1CV;vVwtcAGbZ_5@VACR|ut2 -VXXq-)V^B9&!_4M1Z;0(YXW)$9p7nv%krpqNc;WdH^P1aoC!YypqE!sthuPUKDEU2%WC`V+X+ -(UG)mk--2W1{>juaWw^VbYXO50dNgv5VC@SZy&ck10COK -earHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%A5Mys{ -W@%()Zggp3Y*S@nYybuW1aoC!YysPfS{i~B5OpZ>_>4e9YQ#rfba;u!+d5tm#=h2RwFCuobYXO50sm-Y -z<5%CY59k^g5#W{6D&GDo53%OaP0&iRq10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC -#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%B2y$h1WnpY(WB>*O1aoC!YypqE!sthuPUKDE -U2%WC`V+X+(UG)mk--2W1{>juaWw^VbYXO50sm-Yz<5%CY59k^g5#W{6D&GDo53%OaP0&iRq10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)y -umJ%dL349yXKqquc4c8~Wn@HQbYVhlX>MdwWnpYocxhw=1ONKtpQ8M_qJyiO1VIUJ=H=)@ii_1#@&^bY%f>4P_9rf`M-zw>{+&W0M0{2&GbCtpecGzFNi4 -r|Jm=Y;R+00(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCd;@jJLYKfb7gWS-+`&{Sr=ykNJ#YF -Tr_BQwWqKF0Ra(XZ*FF3WMyu2X<=+rbYXO500sjDb7f&{0fGz-uWS7@0e2{fI -fIMdwWnpYocu;h51OxyKV{dL|X=G(?bZKF100sjDb7f&{0o#gN8iEuMbtv-q -j6g$b#7A9pc!|f`I$jaRzSe2A1O;<+VRU5yN@#iqkT|?l*=bx{^0c**fmF&H)l(b`S3$sb4!MK-1Z;0( -YXW)$9p7nv%krpqNc;WdH^P1aoC!YypqE!sthuPUKDEU2%WC`V+X+(UG)mk--2W1{>juaWw^V -bYXO50ZM3k2aq_tRM}}10COKearHwcS=7M7YzYaI8*bv -hMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%A5Mys{W@%()Zggp3Y*S@nYybuW -1aoC!YysPfS{i~B5OpZ>_>4e9YQ#rfba;u!+d5tm#=h2RwFCuobYXO50c}La^e<`!Iztr?rsl#d#OQkE -ER^^L)C{HEhxT=ipag7hV`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_ -sqk4BX8}k^^xj-FXm+)yumJ%B2y$h1WnpY(WB>*O1aoC!YypqE!sthuPUKDEU2%WC`V+X+(UG)mk--2W -1{>juaWw^VbYXO50c}La^e<`!Iztr?rsl#d#OQkEER^^L)C{HEhxT=ipag7hV`~C>10COKearHwcS=7M -7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%eL349yXKqquc4c8~ -Wn@-iY;|QqY-w&}Q)OXnRCsA*1OxyKV{dL|X=G(?bZKF100sjDb7f&{0o#gN8iEuMbtv-qj6g$b#7A9p -c!|f`I$jaRzSe2A1O;<+VRU5yN@#iqkT|?l*=bx{^0c**fmF&H)l(b`S3$sb4!MK-1Z;0(YXW)$9p7nv -%krpqNc;WdH^P1aoC!YypA{4XEgn0epQk*PX+nL>xOm%pK>soMo}bYXO50ZM3k -2aq_tRM}}10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC -#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%A5Mys{W@%()Zggp3Y*S@nYybuW1aoC!YysPf -S{i~B5OpZ>_>4e9YQ#rfba;u!+d5tm#=h2RwFCuobYXO50c}La^e<`!Iztr?rsl#d#OQkEER^^L)C{HE -hxT=ipag7hV`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^ -^xj-FXm+)yumJ%B2y$h1WnpY(WB>*O1aoC!YypA{4XEgn0epQk*PX+nL>xOm%pK>soMo} -bYXO50c}La^e<`!Iztr?rsl#d#OQkEER^^L)C{HEhxT=ipag7hV`~C>10COKearHwcS=7M7YzYaI8*bv -hMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%bL349yXKq$+X=GD$VRU6eY-w&} -Q)OXnRCrKyas&hb3}bI@W@%()Zggp3YybuW1aoC!YysPfS{i~B5OpZ>_>4e9YQ#rfba;u!+d5tm#=h2R -wFCuobYXO50WPwo{ujV7L@=1(T$>wOY}Ov_b`4?P%YY`+Wb+o`y98`+V`~C>10COKearHwcS=7M7YzYa -I8*bvhMOc?)(rkC#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%95o2#|W@%()Zggp3Y*Tb$ -bY%br0|awrVQc}9yTa&4noi_R;$3lnz4{Zl)X|Z&ZIQtMA_g1big7gsb97;JWdSa-rT!PdFhnqz;9Q#< -T5Q%H?RE`e-pha{(`54&;kyKEZ)0l$dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Th_>4e9YQ#rfba;u!+d5tm#=h2RwFCuobYXO50WPwo -{ujV7L@=1(T$>wOY}Ov_b`4?P%YY`+Wb+o`y98`+V`~C>10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC -#nUFsxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%95o2#|W@%()Zggp3Y*Tb$bY%br0|awrVQc|{ -3=OYq{WJl0D5$WZob97;JWdSa-rT!PdFhnqz;9Q#WZob97;JWdSa-rT!PdFhnqz;9Q#<~nFGwl#> -J&iiT&+eT*0000000000{{R30000007(sJ$X=iS2Wo~qHLTqVnWK(5fY*ct@WCZ~L3IT`y;$>KfZ0H=m -hJ>?uVc;Wd;HQX=DL}aSf9!PV~dK2uo>;u!nFdemP_$ -e?^hl+JkM;eY!XaZDnL>VN`i=WdTAkVTFju)T~Wpi|4 -ZEyepNCs(hb9H5M0(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCT*{+#r3Bk2FRnL+RBXEn8vr= -x`Tq%|A_kfK&ST81_yLyb98QHbOOpO9&dx0-7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3~AEBGG%U@MZ$v -=XJ?|;InIPy66cFfOYp#JM2r7_Du?5Y;;Uvd1Z2QF#>u69p7nv%krpqNMd`Zf8beV{~tF1pxpD -002NB01rcNZewL(Y-MCYbaY{3XaxZP2LJ#-AOHD -0Z6?XZWsH8I~II?C0;dW+k!*yDqgzlqQwf$39g<|8VW;iZgg^CV{}Pm1pxpD002NB00~54bYW9;VRU5$ -0RRX906+i$000000096000000000R^cywiMb7^mG1`7jbW_AJEn^6;37FKqUhx?i3R+Mr!fY&(;2BFL( -m@EZk_srD_V{dMBa$#e1Nn`<^2rNlD$O59e#ogQsB77jPl+h5j^*S;IZf|a5WdHyO4P|(A -Wo~n6Z*Ek1aAg5xbsj>g6`?#s5rWnKhSeO?L~x^!;Y#eFP|P}0Z%EzBpbEf7FA*KKfDWJ -b8~5DZf#|5baMe=>KFFSbgda38zdDXQ0-0pHK5k@bh=O+>c= -6oKLk -F4~iax8KK|47hp+cWHEPWpi@^dIKHbX?@G`sCP;~6&DQwR5(-fxrUo0Thxis%Ku=2wF+7z(Wqt=tdZk`V^s(Ana000000093000000000Ma -Wn^V#ZF2w#0Y>fS!w4MxxaL=+DqP^k2!wz9AHH68xp8!<%Jqp^&Hw-a000000RI300000001IJrb7^O8 -ZDnqBa{vkfhyLPaScq)s9KMExvw34D6J>+NwrBxfixd_%u|$Wt0XD%jq57bK6Q|uUfIMEX^1}Vv6tLB! -)|10-o)0prc>n+a000000RI3000000010+sY-Mg^X=QT&2?0j!=EDda{kY~=q$*tC#t4Le{2#tvcDZqM -smk?aU=OZ$bvG|>z)+>9PT;Au-7)~D;-++htxcywiMb7^mG -RC#b^1pxp60s}^7b_D?d00Iq0b#7;AVr*qobYXO51OW&JVrg`9HZ%YQ0RR993`TWsXK7+=WmI`^Wdi{X -b#8NMXKrO=HZ($MbO;AWWo~72X>$e*17>D+0ot2U6Id2jc94hrndMfLayEe1ISdA&%p{mB1!VWk)d+KA -Xk~3-Nn`<(Qq$W5tE;F{pQrXd&=l*`O?@#x{Qdy?T_k!`1dtE~W^7?+a{_t;9p7nv%krpqNDb5bYX39002k^X>)UR -WpV+w=zxYCD0L!x4tB5Hm3vFbl?lapNXe%XU~*fKJ0+Y4bY*jNZe?@=$}AplgPGkh3_fq3Q7_j=2#kPT -_9!;lWR>~GYywm#VTK~nd#>BpbEf7FA*KKfDWJb8~5DZf#|5baMe=>KFFSbgda38zdDXQa{=9jW&m$tWDykZj`7#3_zANbB(SO{shhGe=&H{tM@n+a000000RI300000001IJrb7^O8ZDnqBa{vkfhyLPaScq)s9KMExvw34D -6J>+NwrBxfixd_%u|$Wt0XD%jq57bK6Q|uUfIMEX^1}Vv6tLB!)|10-o)0prc>n+a000000RI3000000 -010+sY-Mg^X=QT&2?0j!=EDda{kY~=q$*tC#t4Le{2#tvcDZqMsmk?aU=OZ$bvG|>z)+>9PT;Au-7)~D;-++hnxY;R&=Y*Tb$bY%qr015%s?vf5kh_h+&YE#h%O8d1V -_{UOl9{V;uR#^q%$8ES^HwOl>wiJc;WmI`^ -Wd#8M00In0Y;R&=Y*t}xb!Bq}0RRXAGM-jZ2Kh}DE2o;HYydTtf}Q!WH{}bI!u)W*#(e~Z0RR9100000 -|Nj60000002uWmRZggpMc?AIg1p)%fEFN!zncXl9K5w2;FV{y1jDTJCC^p$-mHEbO0#qkRz9SbZ=!8X@ -=Yuq$20sb<4l#S`iz7Vef}@Ca=a#qt2m;D19&dx0-7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3}KjBNr;@ -ghiU?gEXK9KMDE{F?;HZBRuDVqlk6qmbd@_000000093F00000000F^Zg6#U1_B3ga%FZ;b#wuf5WIk~ -G+K)5%bR49t5yk`^qQ9la%FR6a&~280(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D -{wl@OCd;@jJLYKfb7gWS-+`&{Sr=ykNJ#YFTr_BQwWqKF0SHNMaCLM|VQ>Wj015*2Y!hN5_Bp3Y36tDM -M#=e#tGI($UA5U3KNx<*C>jbO<32;hs$B9ZCsU(1!DsC|W1LOd&b_IRG-(&Q$wPGkmB{9L9(7`0)Rt93 -YLV-HLXe?vTA1;^Q1`ZqBog<<0RR9100000|Nj600000021#ykb#!wD0RRaB)s0^W44ZlVPs)+VFdvI3ITQGP59r=ivkR6Lh9EroO>_;0000000030000000000B -Ph(?sa&l#EV`Xy&0t0PnZU6uR18re=0006EPjEwTZEb0EZDnqB1`7jbW_AJEn^6;37FKqUhx?i3R+Mr! -fY&(;2BFL(m@EZk_srD=Zf|a5WdHyO25)dwd2nR`=kby$tK%HuPpRtMKe5+wDRP}k(QuARKUbDjTz^bE -2yJC_VPs)+VFG#s9p7nv%krpqNM?JbaMiF10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUD@oClv)aMjKgwAH@`bu1x<7g|G$};xvA~n-$_S2y$g)Wo2z;WCD5v9p7nv%krpqNv2!%ioJ -pYH;+t0eX2w~A!Q+0eaZ{MVycPK^T!VRUq1V`yzR000000RI3000000 -01i@Rc4c8~Wn@8gbYWv?1_A_TX>4Ty3ATR{-|K6Y3I$*BbiAvUS*tg{!Gb}P!O*^_P#qhP1ao0*bN~Pd -3{quwWnpY(WJFD+0ot2U6Id2jc94hrndMfLayEe1ISdA&%p{mB1!VWk)dgm3VP|s!dIKHb -X?@G`sCP;~6&DQwR5(-fxrUo0ThOi(W05|TJ%PM*ricn_Pm -Xk-a=X>Db5bYX39002k{WMy_`Y;SO7asjsJfQB3>bs~EXcCXx(drQcb3B`Fx$)^%va$Ar)C7cOuWprUw -d2nTO015$hC`}q*rYXqYdo~D%m7H6OD0<^0n_2##VWXRdjy=DB@qgYOj0000000000{{R30000003ukO^Vqt7l -d2nTO015%s?vf5kh_h+&YE#h%O8d1V_{UOl9{V;uR#^q%KfZ0H=mhJ>?uV9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNA700000000300000000007XJu|>b7^w{ -7)aIA#9XnshcC})U)TI#r3b0kyqD7}ejM+$yUGm(3T1e7Wo~n6Z*Fq{3ISww9zv-Vp*%wog4O?q)g04A -aHEjnO6;Ie%sNwVNZtVhXadZr-SPY!h`6Z9%SYt5l1;p3@00000000300000000008a%FR6a&~280(t`--)Viz@~C%8KNS}Z0aQ3s^SOqb -BwN-D{wl@OCjNpJN#A(BKKz&v`r;e6DUv<<*U}cD+0ot2U6Id2jc94hrndMfLayEe1ISdA&%p{mB1!VWk)e2*8Zgg^CV{}Pm0iOsgNjk^^ -qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G6imLZewKt00<6ra$#@6CZd7@2WdSr&53UoI8eY9A{1GER -g--GiI0S#x1is&)M%fmnGH3{GWprU=VRT^u^?FS>S$_F2)vN@Mb6UJ-F(lri_dqerx4lR4>iBsz2WM<= -Vqt7^0p25#Yo@G%*b#-tU^&3KX?w7l?~*Sh8@1jRRblZzyas7*aCLNZ0jZ*TSChz_$|Xx}eRkFNAr%^e -Ll(1e@}~9=0-ijXfD2)Bb7^O8ZDnqBa{)s3lIz?v1U>x&T2C;PAKlCCveQ{N4udSh#@3Dqj&%ukVQgh? -V`*h`0o{dW0B>Pr5ftu@@z<*O39}j`u&O7io3b$Is?RA$O$l~kY-wa+bZ>G3dIKHbX?@G`sCP;~6&DQw -R5(-fxrUo0Th$AHP6|FsuXsI;G3ONG`V!CAn^8 -7TS9h9ibhaZ&^Bcn*B*;w|~I;-PD|t>j-IXaCLM|VQ>KznP+6nwW~k}RP!NmuV?G015$>$mV(;bz)!CmQ_M(k?Vd!kfCo{nDM?)_qK{868FUc))-~W22H5+ -SDrhMohTRsfLT>C1dS{r3#^{o?N>fE0RR9100000|Nj60000005L9wuZgXjLX>V>*V`ybM?JbaMa-0f+wLWmt%8=p4R=gtK{LClh6Z#kObxUW*hKHnBv9xdAr8 -G@<&SffJ|QFn~N>u=2wF+7z(Wqt=tdZk`V^s(Ana000000093000000000YNb8~5DZf#|5baMa-0f+wL -Wmt%8=p4R=gtK{LClh6Z#kObxUW*hKHnBv9xdAr8G@<&SffJ|QFn~N>u=2wF+7z(Wqt=tdZk`V^s(Ana -000000093000000000SgVQgh?V`*h`00{v`?dHP>9R0ZFSEMRj;Km4qfBYZ5UUs>0bg9bqiCNA700000 -000300000000009c42I3WMOn~asUJZ00eGtZe;)f009JZZ*64&1pxwLa5aA+<>R2XhQO_4{AcS-HH^7A -VzASV8M4NYxyCka@1Z8)ymjIKNK5;L!8FkfGTe+FK;UUh9M-4n+}vRfRB~Z%b7^#GZ*Ek1aAgGn0006G -RC#b^LvL+uX>@I6Zgd0#00(DfZe??6a{vVa0W)M-Q2pM493%15wcJ8Z{z5k9VD)f0JnAj^7J5MZ9{~z< -a$#@6CZU6-W0iOsgNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G66JF53UoI8eY9A{1GERg--Gi -I0S#x1is&)M%fmnGH3z`Wq5RDZgXjGZU6-W0iOsgNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G67_D -9zv-Vp*%wog4O?q)g04AaHEjnO6;Ie%sNwVNZuM$d2nT9L349yXKr&sY-w&}Q)OXnRCrKyas&hb3uI+u -Y+-U?bZK^F00jX62mv`K^WREqS2tt~EBII@xVqZNcP`ond^UU-JbUWd$~FK100000009600000000039 -W_507X<}?;00jX62m#u~=^e=I{=p`1zMng|0+NmwUpUW`Z@54^_oW>WVpRYD0000000960000000006C -b98cbV{~&L00;qEk8=qnO(R<<%JIK< -1B78x*e6}1oxDzJ3ElvocGBqp0000000030{{R30000303So3~VPj}*Wo~o;1pxpE0aMUzRzj^*Tk1C) -pGbjYG7000000RR600000000~xMY-Mg^X=QT-0RRaBM(yUq2ps*m=2xUD -T;RqCgn#@WzFu~@adfH5^@&-|0000000000{{R30000003szxlWo~16RC#b^1pxp60tr@cX=GD$VRU5$ -0RR916j(!OVQFqcY-w&}Q)OXnRCrKyas&bZ2V!Y-V{d7000jX8Ruk6O)Q5AKbFW;JEQ>MoHhG*Mzd(pE -tONi$rOUxcMklB)P_)|`Y=H7dO_e!^G2i>0SdC0NppV!6v|_i_0S0Voadl~A00jX8Ruk6O)Q5AKbFW;J -EQ>MoHhG*Mzd(pEtONi$rOUxcMklB)P_)|`Y=H7dO_e!^G2i>0SdC0NppV!6v|_i_6IerNVQFqcY-w&} -Q)OXnRCsA*1OfmDVrg_^Z)t7-1pxw96V}(%hjW>8uUwNXi!t*yd7K}=K!`A`1OPgv%fU#n#&NEOd)wn+ -n#11fGQ~$X901P7x>0daZB@{PThHqO25f0@b!lV(1pxw96V}(%hjW>8uUwNXi!t*yd7K}=K!`A`1OPgv -%fU#n#&NEOd)wn+n#11fGQ~$X901P7x>0daZB@{PThHqdSVL%GX>L8uUwNXi!t*yd7K}=K!`A`1OPgv%fU!!8SA{&vly$FvzVnzHf7z~rv`86=_Ka^V5yX| -y#`JJ25f0@b!lV(1pxw96V}(%hjW>8uUwNXi!t*yd7K}=K!`A`1OPgv%fU!!8SA{&vly$FvzVnzHf7z~ -rv`86=_Ka^V5yX|y#`JSSVL%GX>L?_X=DTf00&}ebYpL6ZU6-V0`+VYVk7oBr%DNv+($;q`HHK!gIHa) -*%m(-e#9sm3ZsHT^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1RsjZVX>oOFWB>&L0`+VYVk7oBr%DNv -+($;q`HHK!gIHa)*%m(-e#9sm3ZsHT^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1Rs - ------END STRICT TYPE LIB----- - diff --git a/stl/RGBCommit@0.1.0.stl b/stl/RGBCommit@0.1.0.stl deleted file mode 100644 index 00268c22..00000000 Binary files a/stl/RGBCommit@0.1.0.stl and /dev/null differ diff --git a/stl/RGBCommit@0.1.0.sty b/stl/RGBCommit@0.1.0.sty deleted file mode 100644 index 4fbfa1e5..00000000 --- a/stl/RGBCommit@0.1.0.sty +++ /dev/null @@ -1,445 +0,0 @@ -{- - Id: stl:IFcnrPeI-TANxLfZ-feJax6Q-1TUM4Hq-AjI161s-3tbmxak#harvest-person-orion - Name: RGBCommit - Version: 0.1.0 - Description: Consensus commitment layer for RGB smart contracts - Author: Dr Maxim Orlovsky - Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --} - -@context -typelib RGBCommit - -import StrictTypes#century-comrade-chess - use TypeName#edgar-carol-mystery - use SemId#logic-absorb-hilton - -import BPCore#austin-story-retro - use Method#bali-boris-plasma - use BlindSealTxPtr#fortune-iron-salmon - use SecretSeal#dollar-iris-wizard - use BlindSealTxid#media-judge-anita - use TxPtr#italian-july-eddie - -import AluVM#congo-archive-folio - use LibSite#ultra-grace-message - use LibId#germany-culture-olivia - -import CommitVerify#miller-pancake-elastic - use MerkleHash#horse-popcorn-bundle - use StrictHash#pizza-sherman-sound - use ReservedBytes1#origin-roger-relax - use ReservedBytes2#florida-libra-circus - use ReservedBytes8#rudolf-tape-adrian - -import Std#ralph-blue-lucky - use AsciiPrintable#ultra-sunset-format - use Bool#oxygen-complex-duet - use AlphaNumLodash#percent-bingo-caesar - use AlphaCapsLodash#duet-hammer-labor - -import Bitcoin#signal-color-cipher - use Vout#brush-gloria-heroic - use Txid#shallow-light-reverse - - -@mnemonic(edison-survive-nitro) -data AltLayer1 : liquid#1 - - -@mnemonic(almond-office-pulse) -data AltLayer1Set : {AltLayer1 ^ ..0xff} - -@mnemonic(slang-amber-club) -data AssetTag : [Byte ^ 32] - -@mnemonic(crash-singer-corner) -data AssetTags : {AssignmentType -> ^ ..0xff AssetTag} - -@mnemonic(airport-ladder-joseph) -data AssignRevealedAttachBlindSealTxPtr : confidential (seal XChainSecretSeal - , state ConcealedAttach - , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxPtr - , state ConcealedAttach - , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal - , state RevealedAttach - , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxPtr - , state RevealedAttach - , lock CommitVerify.ReservedBytes2) - -@mnemonic(member-camera-parking) -data AssignRevealedAttachBlindSealTxid : confidential (seal XChainSecretSeal - , state ConcealedAttach - , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxid - , state ConcealedAttach - , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal - , state RevealedAttach - , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxid - , state RevealedAttach - , lock CommitVerify.ReservedBytes2) - -@mnemonic(genius-editor-formula) -data AssignRevealedDataBlindSealTxPtr : confidential (seal XChainSecretSeal - , state ConcealedData - , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxPtr - , state ConcealedData - , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal - , state RevealedData - , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxPtr - , state RevealedData - , lock CommitVerify.ReservedBytes2) - -@mnemonic(soda-edison-music) -data AssignRevealedDataBlindSealTxid : confidential (seal XChainSecretSeal - , state ConcealedData - , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxid - , state ConcealedData - , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal - , state RevealedData - , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxid - , state RevealedData - , lock CommitVerify.ReservedBytes2) - -@mnemonic(rachel-unique-logic) -data AssignRevealedValueBlindSealTxPtr : confidential (seal XChainSecretSeal - , state ConcealedFungible - , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxPtr - , state ConcealedFungible - , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal - , state RevealedFungible - , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxPtr - , state RevealedFungible - , lock CommitVerify.ReservedBytes2) - -@mnemonic(cadet-book-pablo) -data AssignRevealedValueBlindSealTxid : confidential (seal XChainSecretSeal - , state ConcealedFungible - , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxid - , state ConcealedFungible - , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal - , state RevealedFungible - , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxid - , state RevealedFungible - , lock CommitVerify.ReservedBytes2) - -@mnemonic(cycle-panther-cave) -data AssignVoidStateBlindSealTxPtr : confidential (seal XChainSecretSeal - , state VoidState - , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxPtr - , state VoidState - , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal - , state VoidState - , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxPtr - , state VoidState - , lock CommitVerify.ReservedBytes2) - -@mnemonic(dynasty-iron-athena) -data AssignVoidStateBlindSealTxid : confidential (seal XChainSecretSeal - , state VoidState - , lock CommitVerify.ReservedBytes2) - | confidentialState (seal XChainBlindSealTxid - , state VoidState - , lock CommitVerify.ReservedBytes2) - | confidentialSeal (seal XChainSecretSeal - , state VoidState - , lock CommitVerify.ReservedBytes2) - | revealed (seal XChainBlindSealTxid - , state VoidState - , lock CommitVerify.ReservedBytes2) - -@mnemonic(secret-penguin-limit) -data AssignmentType : U16 - -@mnemonic(target-valid-tiger) -data AssignmentsBlindSealTxPtr : {AssignmentType -> ^ ..0xff TypedAssignsBlindSealTxPtr} - -@mnemonic(baker-size-sonar) -data AssignmentsBlindSealTxid : {AssignmentType -> ^ ..0xff TypedAssignsBlindSealTxid} - -@mnemonic(factor-hair-everest) -data AttachId : [Byte ^ 32] - -@mnemonic(harvard-burma-bicycle) -data AttachState : id AttachId, mediaType MediaType - -@mnemonic(amadeus-sunday-casino) -data BaseCommitment : flags CommitVerify.ReservedBytes1 - , schemaId SchemaId - , timestamp I64 - , issuer CommitVerify.StrictHash - , testnet Std.Bool - , altLayers1 CommitVerify.StrictHash - , assetTags CommitVerify.StrictHash - -@mnemonic(animal-plume-minus) -data BlindingFactor : [Byte ^ 32] - -@mnemonic(meter-arizona-albino) -data ConcealedAttach : [Byte ^ 32] - -@mnemonic(ivan-tripod-young) -data ConcealedData : [Byte ^ 32] - -@mnemonic(arizona-basic-moment) -data ConcealedFungible : commitment PedersenCommitment, rangeProof PedersenCommitment - -@mnemonic(uniform-welcome-papa) -data ContractId : [Byte ^ 32] - -@mnemonic(short-noise-postal) -data DataState : [Byte] - -@mnemonic(reform-garden-ballet) -data Extension : ffv Ffv - , contractId ContractId - , nonce U64 - , extensionType ExtensionType - , metadata Metadata - , globals GlobalState - , assignments AssignmentsBlindSealTxid - , redeemed Redeemed - , valencies Valencies - , validator CommitVerify.ReservedBytes1 - , witness CommitVerify.ReservedBytes2 - -@mnemonic(delta-elastic-germany) -data ExtensionSchema : metadata {MetaType ^ ..0xff} - , globals {GlobalStateType -> ^ ..0xff Occurrences} - , redeems {ValencyType ^ ..0xff} - , assignments {AssignmentType -> ^ ..0xff Occurrences} - , valencies {ValencyType ^ ..0xff} - , validator AluVM.LibSite? - -@mnemonic(apropos-scoop-viva) -data ExtensionType : U16 - -@mnemonic(pigment-career-hippie) -data Ffv : U16 - -@mnemonic(guide-poker-coconut) -data FungibleState : bits64#8 U64 - -@mnemonic(matrix-optimal-sinatra) -data FungibleType : unsigned64Bit#8 - - -@mnemonic(fashion-delta-polka) -data Genesis : ffv Ffv - , schemaId SchemaId - , flags CommitVerify.ReservedBytes1 - , timestamp I64 - , issuer Identity - , testnet Std.Bool - , altLayers1 AltLayer1Set - , assetTags AssetTags - , metadata Metadata - , globals GlobalState - , assignments AssignmentsBlindSealTxid - , valencies Valencies - , validator CommitVerify.ReservedBytes1 - -@mnemonic(concept-gloria-shock) -data GenesisSchema : metadata {MetaType ^ ..0xff} - , globals {GlobalStateType -> ^ ..0xff Occurrences} - , assignments {AssignmentType -> ^ ..0xff Occurrences} - , valencies {ValencyType ^ ..0xff} - , validator AluVM.LibSite? - -@mnemonic(initial-malta-sierra) -data GlobalState : {GlobalStateType -> ^ ..0xff GlobalValues} - -@mnemonic(silk-college-august) -data GlobalStateSchema : reserved CommitVerify.ReservedBytes1 - , semId StrictTypes.SemId - , maxItems U24 - -@mnemonic(yoga-quick-jasmine) -data GlobalStateType : U16 - -@mnemonic(charter-fractal-maze) -data GlobalValues : [DataState ^ 1..] - -@mnemonic(smart-pioneer-nominal) -data Identity : Std.AsciiPrintable, [Std.AsciiPrintable ^ ..0xfff] - -@mnemonic(kevin-morgan-shrink) -data Input : prevOut Opout, reserved CommitVerify.ReservedBytes2 - -@mnemonic(tobacco-open-join) -data InputMap : {Bitcoin.Vout -> ^ 1.. OpId} - -@mnemonic(sector-charlie-diagram) -data Inputs : {Input} - -@mnemonic(isabel-heaven-north) -data MediaType : any#255 - - -@mnemonic(quebec-mission-quota) -data MetaType : U16 - -@mnemonic(split-package-recycle) -data MetaValue : [Byte] - -@mnemonic(retro-mozart-formal) -data Metadata : {MetaType -> ^ ..0xff MetaValue} - -@mnemonic(source-olga-mirage) -data Occurrences : min U16, max U16 - -@mnemonic(survive-citizen-harris) -data OpCommitment : ffv Ffv - , nonce U64 - , opType TypeCommitment - , metadata CommitVerify.StrictHash - , globals CommitVerify.MerkleHash - , inputs CommitVerify.MerkleHash - , assignments CommitVerify.MerkleHash - , redeemed CommitVerify.StrictHash - , valencies CommitVerify.StrictHash - , witness CommitVerify.MerkleHash - , validator CommitVerify.StrictHash - -@mnemonic(picnic-single-gloria) -data OpId : [Byte ^ 32] - -@mnemonic(child-morning-compare) -data Opout : op OpId - , ty AssignmentType - , no U16 - -@mnemonic(neutral-mixer-visual) -data OwnedStateSchema : declarative () - | fungible FungibleType - | structured StrictTypes.SemId - | attachment MediaType - -@mnemonic(pupil-scale-jerome) -data PedersenCommitment : [Byte ^ 33] - -@mnemonic(anita-vega-pirate) -data Redeemed : {ValencyType -> ^ ..0xff OpId} - -@mnemonic(simple-bombay-salute) -data RevealedAttach : file AttachState, salt U64 - -@mnemonic(sleep-source-figure) -data RevealedData : value DataState, salt U128 - -@mnemonic(source-contact-member) -data RevealedFungible : value FungibleState - , blinding BlindingFactor - , tag AssetTag - -@mnemonic(corona-igloo-sierra) -data Schema : ffv Ffv - , flags CommitVerify.ReservedBytes1 - , name StrictTypes.TypeName - , timestamp I64 - , developer Identity - , metaTypes {MetaType -> ^ ..0xff StrictTypes.SemId} - , globalTypes {GlobalStateType -> ^ ..0xff GlobalStateSchema} - , ownedTypes {AssignmentType -> ^ ..0xff OwnedStateSchema} - , valencyTypes {ValencyType ^ ..0xff} - , genesis GenesisSchema - , extensions {ExtensionType -> ^ ..0xff ExtensionSchema} - , transitions {TransitionType -> ^ ..0xff TransitionSchema} - , reserved CommitVerify.ReservedBytes8 - -@mnemonic(ramirez-patron-simon) -data SchemaId : [Byte ^ 32] - -@mnemonic(michael-exact-eric) -data Transition : ffv Ffv - , contractId ContractId - , nonce U64 - , transitionType TransitionType - , metadata Metadata - , globals GlobalState - , inputs Inputs - , assignments AssignmentsBlindSealTxPtr - , valencies Valencies - , validator CommitVerify.ReservedBytes1 - , witness CommitVerify.ReservedBytes2 - -@mnemonic(antonio-adios-analyze) -data TransitionBundle : closeMethod BPCore.Method - , inputMap InputMap - , knownTransitions {OpId -> ^ 1.. Transition} - -@mnemonic(pirate-lithium-side) -data TransitionSchema : metadata {MetaType ^ ..0xff} - , globals {GlobalStateType -> ^ ..0xff Occurrences} - , inputs {AssignmentType -> ^ ..0xff Occurrences} - , assignments {AssignmentType -> ^ ..0xff Occurrences} - , valencies {ValencyType ^ ..0xff} - , validator AluVM.LibSite? - -@mnemonic(picture-reflex-brigade) -data TransitionType : U16 - -@mnemonic(biscuit-pandora-bagel) -data TypeCommitment : genesis BaseCommitment - | transition (ContractId, TransitionType) - | extension (ContractId, ExtensionType) - -@mnemonic(giant-trinity-lagoon) -data TypedAssignsBlindSealTxPtr : declarative [AssignVoidStateBlindSealTxPtr] - | fungible [AssignRevealedValueBlindSealTxPtr] - | structured [AssignRevealedDataBlindSealTxPtr] - | attachment#255 [AssignRevealedAttachBlindSealTxPtr] - -@mnemonic(penguin-raja-machine) -data TypedAssignsBlindSealTxid : declarative [AssignVoidStateBlindSealTxid] - | fungible [AssignRevealedValueBlindSealTxid] - | structured [AssignRevealedDataBlindSealTxid] - | attachment#255 [AssignRevealedAttachBlindSealTxid] - -@mnemonic(shock-jester-orion) -data Valencies : {ValencyType ^ ..0xff} - -@mnemonic(aloha-dublin-brush) -data ValencyType : U16 - -@mnemonic(email-snow-safari) -data VoidState : () - -@mnemonic(senator-limbo-raymond) -data XChainBlindSealTxPtr : bitcoin BPCore.BlindSealTxPtr - | liquid BPCore.BlindSealTxPtr - -@mnemonic(dynamic-life-brown) -data XChainBlindSealTxid : bitcoin BPCore.BlindSealTxid - | liquid BPCore.BlindSealTxid - -@mnemonic(alex-griffin-left) -data XChainSecretSeal : bitcoin BPCore.SecretSeal - | liquid BPCore.SecretSeal - -@mnemonic(liquid-river-absorb) -data XChainTxid : bitcoin Bitcoin.Txid - | liquid Bitcoin.Txid - - diff --git a/stl/RGBLogic@0.1.0.sta b/stl/RGBLogic@0.1.0.sta deleted file mode 100644 index b84bc9fd..00000000 --- a/stl/RGBLogic@0.1.0.sta +++ /dev/null @@ -1,38 +0,0 @@ ------BEGIN STRICT TYPE LIB----- -Id: stl:mqltqlPk-O9$pYOd-BACRI70-DOMJ6cp-TFvhcK1-ibrOI9U#import-boxer-seminar -Name: RGBLogic -Dependencies: - RGBCommit#harvest-person-orion, - BPCore#austin-story-retro, - Bitcoin#signal-color-cipher -Check-SHA256: 1c7df052c1790167b3a2f4748d4a8d602f3c8473195826c02efa6efc43b7f396 - -2vSEvOmAmtV*?;pC#?5~OapN(_Fs6GvFQy{P|gRa2*}s1Y~I%9#iMoHhG*Mzd(pEtONi$rOUxc20~CnZ*pbzY!hN5_Bp3Y36tDMM#=e#tGI($UA5U3KNx<*C>ja}LTPkk -Z)t7=20~CnZ*pY?00DdlT>wB!7L}MA7sFvK#<=RP4S#T1Vv-hhTICs&5fM~jaB^jIPH$voP+@X(Ze?;0 -wjY>38tto&d&=eG4cRAF#( -Wpq+$XJ~Xna$#;`Xh%-ZT+rxDK6vW;JU&?LxLM72H?wDC1Zo}=N}D)4mkLjCa%FT-a&K>D2SRCdV{d70 -1^^|i^|=xh7rLW4)L(lQb*FJl;d*r#UC=Q#deq4+>4pnaV{&P5bV7M_WpgpRuIPk`cg3&=F>*1@lJ+pR -DJ{*3f84s>#k$1lf7uIEVQ@}wWMxQUb7)_z*=^-NPQ?`2v5jYd+6t@dEhY>7H!Y*UdZb-BpG^u(WnpGh -V{&P5bg6}ecT=8d`>?<6$C@F;S3|*6`1-v+nBdcqJ?FPKcnV2wbY*gGVQf%qwlfK-7{9iX4Q|L-q$GzU -Mp|h#f#{Gz8SzLEaTf~c{WkYggkPIjuQHS#3Ua|L6d7%qre2Ut&TYs@(?%#f7ArN-=Rj?7Ns(14peesZgXjLX>V>+d2nT9bsj>g -6`?#s5rWnKhSeO?L~x^!;Y#eFP|P}0Z%Ez^MR;^&ZgXjGZd7@2WqHKdNeFB= -iRT*14O40w5C%+Pd1Z1jmB{9L9(7`0)Rt93YLV-HLXe?vTA1;^Q1`ZqBog<<1W#~DWCZ{SL}Fu5a&K>D -1OfpDbYXCEWpn@q0RmPN*4NaBbD49mT$3z|G4nQgoFBhHh%l@K06L}1!AK9bADBNH?W>M^%H|xc>sh|D -n*!v8^Ea7rh?dzC2n+%RZ*X#DbN~eb0#*~&*VKn|nRBmPlPrrd^EP>$AHP6|FsuXsI;G3ONJmc3T+rxD -K6vW;JU&?LxLM72H?wDC1Zo}=N}D)4mkCE~Z(?C=PjX}i0tIhyPjX}d{&9|4h)I8ST&b@+9Xb*9;C#?5~OapN(_Fs6GvFQy{P|gRa2*}s1Y~I%9 -#i?X<9zv-Vp*%wog4O?q)g04AaHEjnO6;Ie%sNwVNZti*Z*F5{000OCZ*Xa30w7l>toMja192_(UwD?W -=?zm*&IhOn$k(lG-qz;Dsg=m)dLDIRU(}XWLTZugenOC;Z(5k~zEJnJiX;;E#s3O)a$#@6CZU6=Z -2X|?7Ze??G0dl)S$QV;yG0%+u`Lqfm#|FpRuujhTP8r)T_J?np;R1Ad0w7l>toMja192_(UwD?W=?zm* -&IhOn$k(lG-qz;DsWeg#t`n9TUcD*&5hFi^PVx{q1b@^7zTcrn*%qZTXa#O>ZewKt00;zcaA{-$AXg`> -_lQgbaV_>=c$Ts04O39g2dD_h*R5>c*5<{jmB{9L9(7`0)Rt93YLV-HLXe?vTA1;^Q1`ZqBog<<3Rh`# -Ze??GPjX}g0{{qNa${&|c4cG$00036ZE0?0WB>&L0bJY;BNZ=sBHM?<`J6+Fr=A_lQgbaV_>=c$Ts04O39g2dD_h*R5>c -*5<{jdBoUB2y8Zom7+;NN8Xgkb3WeV)QDb*=NiflQ)(Iz254nzXJ~W)00aqiX>Db5bYX39002k - ------END STRICT TYPE LIB----- - diff --git a/stl/RGBLogic@0.1.0.stl b/stl/RGBLogic@0.1.0.stl deleted file mode 100644 index 24ed32dc..00000000 Binary files a/stl/RGBLogic@0.1.0.stl and /dev/null differ diff --git a/stl/RGBLogic@0.1.0.sty b/stl/RGBLogic@0.1.0.sty deleted file mode 100644 index 9d370b08..00000000 --- a/stl/RGBLogic@0.1.0.sty +++ /dev/null @@ -1,64 +0,0 @@ -{- - Id: stl:mqltqlPk-O9$pYOd-BACRI70-DOMJ6cp-TFvhcK1-ibrOI9U#import-boxer-seminar - Name: RGBLogic - Version: 0.1.0 - Description: Consensus logic layer for RGB smart contracts - Author: Dr Maxim Orlovsky - Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --} - -@context -typelib RGBLogic - -import RGBCommit#harvest-person-orion - use TransitionType#picture-reflex-brigade - use ExtensionType#apropos-scoop-viva - use Layer1#camilla-basket-justin - use OpId#picnic-single-gloria - -import BPCore#austin-story-retro - use TapretNodePartner#roger-member-educate - use TapretProof#marco-border-sample - use TapretPathProof#kiwi-mirror-paris - use TapretRightBranch#miracle-patriot-touch - use OpretProof#good-village-flex - -import Bitcoin#signal-color-cipher - use ScriptBytes#equator-cockpit-gong - use TapNodeHash#paprika-amanda-hunter - use LeafScript#bison-doctor-oscar - use InternalPk#habitat-paprika-oliver - use LeafVer#benefit-carbon-africa - use XOnlyPk#clever-swim-carpet - - -@mnemonic(needle-change-forest) -data DbcProof : tapret#1 BPCore.TapretProof - | opret BPCore.OpretProof - -@mnemonic(east-sunset-extra) -data GlobalOrd : opOrd OpOrd, idx U16 - -@mnemonic(combat-henry-flood) -data OpOrd : genesis () - | extension (witness WitnessOrd - , ty RGBCommit.ExtensionType - , nonce U64 - , opid RGBCommit.OpId) - | transition#255 (witness WitnessOrd - , ty RGBCommit.TransitionType - , nonce U64 - , opid RGBCommit.OpId) - -@mnemonic(orange-john-cyclone) -data WitnessOrd : archived () - | mined WitnessPos - | tentative () - -@mnemonic(cliff-enrico-nominal) -data WitnessPos : layer1 RGBCommit.Layer1 - , height U32 - , timestamp I64 - - diff --git a/stl/Schema.vesper b/stl/Schema.vesper deleted file mode 100644 index 21aae701..00000000 --- a/stl/Schema.vesper +++ /dev/null @@ -1,125 +0,0 @@ -{- - Description: RGB Schema - Author: Dr Maxim Orlovsky - Copyright (C) 2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --} - -Schema vesper lexicon=types+commitments - -SchemaId commitment hasher=SHA256 tagged=urn:lnp-bp:rgb:schema#2024-02-03 - Ffv serialized - ReservedBytes1 serialized - TypeName serialized - I64 serialized - Identity serialized - SemId map len=0..MAX8 - MetaType mapKey - SemId mapValue - GlobalStateSchema map len=0..MAX8 - GlobalStateType mapKey - GlobalStateSchema mapValue - OwnedStateSchema map len=0..MAX8 - AssignmentType mapKey - OwnedStateSchema mapValue - ValencyType set len=0..MAX8 - ValencyType element - GenesisSchema serialized - ExtensionSchema map len=0..MAX8 - ExtensionType mapKey - ExtensionSchema mapValue - TransitionSchema map len=0..MAX8 - TransitionType mapKey - TransitionSchema mapValue - ReservedBytes8 serialized - -Schema rec - ffv is U16 aka=Ffv - flags bytes len=1 aka=ReservedBytes1 - name ascii aka=TypeName first=AlphaCapsLodash rest=AlphaNumLodash len=1..100 - timestamp is I64 - developer ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 - metaTypes map len=0..MAX8 - key is U16 aka=MetaType - value bytes len=32 aka=SemId - globalTypes map len=0..MAX8 - key is U16 aka=GlobalStateType - value rec GlobalStateSchema - reserved bytes len=1 aka=ReservedBytes1 - semId bytes len=32 aka=SemId - maxItems is U24 - ownedTypes map len=0..MAX8 - key is U16 aka=AssignmentType - value union OwnedStateSchema - declarative is Unit tag=0 - fungible enum FungibleType wrapped unsigned64Bit=8 tag=1 - structured bytes len=32 wrapped aka=SemId tag=2 - attachment enum MediaType wrapped any=255 tag=3 - valencyTypes set len=0..MAX8 - element is U16 aka=ValencyType - genesis rec GenesisSchema - metadata set len=0..MAX8 - element is U16 aka=MetaType - globals map len=0..MAX8 - key is U16 aka=GlobalStateType - value rec Occurrences - min is U16 - max is U16 - assignments map len=0..MAX8 - key is U16 aka=AssignmentType - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element is U16 aka=ValencyType - some rec LibSite option wrapped tag=1 - lib bytes len=32 aka=LibId - pos is U16 - extensions map len=0..MAX8 - key is U16 aka=ExtensionType - value rec ExtensionSchema - metadata set len=0..MAX8 - element is U16 aka=MetaType - globals map len=0..MAX8 - key is U16 aka=GlobalStateType - value rec Occurrences - min is U16 - max is U16 - redeems set len=0..MAX8 - element is U16 aka=ValencyType - assignments map len=0..MAX8 - key is U16 aka=AssignmentType - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element is U16 aka=ValencyType - some rec LibSite option wrapped tag=1 - lib bytes len=32 aka=LibId - pos is U16 - transitions map len=0..MAX8 - key is U16 aka=TransitionType - value rec TransitionSchema - metadata set len=0..MAX8 - element is U16 aka=MetaType - globals map len=0..MAX8 - key is U16 aka=GlobalStateType - value rec Occurrences - min is U16 - max is U16 - inputs map len=0..MAX8 - key is U16 aka=AssignmentType - value rec Occurrences - min is U16 - max is U16 - assignments map len=0..MAX8 - key is U16 aka=AssignmentType - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element is U16 aka=ValencyType - some rec LibSite option wrapped tag=1 - lib bytes len=32 aka=LibId - pos is U16 - diff --git a/stl/Transition.vesper b/stl/Transition.vesper deleted file mode 100644 index a612053c..00000000 --- a/stl/Transition.vesper +++ /dev/null @@ -1,290 +0,0 @@ -{- - Description: RGB Transition - Author: Dr Maxim Orlovsky - Copyright (C) 2024 LNP/BP Standards Association. All rights reserved. - License: Apache-2.0 --} - -Transition vesper lexicon=types+commitments - -OpId commitment hasher=SHA256 tagged=urn:lnp-bp:rgb:operation#2024-02-03 - OpCommitment serialized - -OpCommitment rec - ffv is U16 aka=Ffv - nonce is U64 - opType union TypeCommitment - genesis rec BaseCommitment wrapped tag=0 - flags bytes len=1 aka=ReservedBytes1 - schemaId bytes len=32 aka=SchemaId - timestamp is I64 - issuer bytes len=32 aka=StrictHash - testnet enum Bool false=0 true=1 - altLayers1 bytes len=32 aka=StrictHash - assetTags bytes len=32 aka=StrictHash - transition tuple tag=1 - _ bytes len=32 aka=ContractId - _ is U16 aka=TransitionType - extension tuple tag=2 - _ bytes len=32 aka=ContractId - _ is U16 aka=ExtensionType - metadata bytes len=32 aka=StrictHash - globals bytes len=32 aka=MerkleHash - inputs bytes len=32 aka=MerkleHash - assignments bytes len=32 aka=MerkleHash - redeemed bytes len=32 aka=StrictHash - valencies bytes len=32 aka=StrictHash - witness bytes len=32 aka=MerkleHash - validator bytes len=32 aka=StrictHash - -Transition rec - ffv is U16 aka=Ffv - contractId bytes len=32 aka=ContractId - nonce is U64 - transitionType is U16 aka=TransitionType - metadata map len=0..MAX8 aka=Metadata - key is U16 aka=MetaType - value bytes len=0..MAX16 aka=MetaValue - globals map len=0..MAX8 aka=GlobalState - key is U16 aka=GlobalStateType - value list len=1..MAX16 aka=GlobalValues - element bytes len=0..MAX16 aka=DataState - inputs set len=0..MAX16 aka=Inputs - Input rec - prevOut rec Opout - op bytes len=32 aka=OpId - ty is U16 aka=AssignmentType - no is U16 - reserved bytes len=2 aka=ReservedBytes2 - assignments map len=0..MAX8 aka=AssignmentsBlindSealTxPtr - key is U16 aka=AssignmentType - value union TypedAssignsBlindSealTxPtr - declarative list len=0..MAX16 wrapped tag=0 - AssignVoidStateBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - fungible list len=0..MAX16 wrapped tag=1 - AssignRevealedValueBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec ConcealedFungible - commitment bytes len=33 aka=PedersenCommitment - rangeProof bytes len=33 aka=PedersenCommitment - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - blinding bytes len=32 aka=BlindingFactor - tag bytes len=32 aka=AssetTag - lock bytes len=2 aka=ReservedBytes2 - structured list len=0..MAX16 wrapped tag=2 - AssignRevealedDataBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - attachment list len=0..MAX16 wrapped tag=3 - AssignRevealedAttachBlindSealTxPtr union - confidential rec tag=0 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal union XChainSecretSeal - bitcoin bytes len=32 wrapped aka=SecretSeal tag=0 - liquid bytes len=32 wrapped aka=SecretSeal tag=1 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal union XChainBlindSealTxPtr - bitcoin rec BlindSealTxPtr wrapped tag=0 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - liquid rec BlindSealTxPtr wrapped tag=1 - method enum Method opretFirst=0 tapretFirst=1 - txid union TxPtr - witnessTx is Unit tag=0 - txid bytes len=32 wrapped aka=Txid tag=1 - vout is U32 aka=Vout - blinding is U64 - state rec RevealedAttach - file rec AttachState - id bytes len=32 aka=AttachId - mediaType enum MediaType any=255 - salt is U64 - lock bytes len=2 aka=ReservedBytes2 - valencies set len=0..MAX8 aka=Valencies - element is U16 aka=ValencyType - validator bytes len=1 aka=ReservedBytes1 - witness bytes len=2 aka=ReservedBytes2 -