diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0662fcb8..28e04107 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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/test.yml b/.github/workflows/test.yml index 9821d00e..b56e1765 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,4 +36,4 @@ jobs: - name: Add wasm32 target run: rustup target add wasm32-unknown-unknown - name: Test in headless Chrome - run: wasm-pack test --headless --chrome + run: RUSTFLAGS='--cfg getrandom_backend="wasm_js"' wasm-pack test --headless --chrome diff --git a/Cargo.lock b/Cargo.lock index 7c0dcd8b..dc6f1641 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,17 +2,26 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "aluvm" -version = "0.11.0-beta.9" +version = "0.11.1-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2a6767842958f458dc7010a2a1005db96dfaceadd366d07532c5045bbc81f24" +checksum = "6035110db4d2f0a0e6df87e7b61f1c397828ed127ed97d46896371a258888403" dependencies = [ "amplify", "ascii-armor", "baid64", "blake3", - "getrandom", + "getrandom 0.3.2", "half", "paste", "ripemd", @@ -25,16 +34,16 @@ dependencies = [ [[package]] name = "amplify" -version = "4.7.1" +version = "4.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2090b9b79b61d4047a307a46de043d0ee5ec406d99a7d652341b96d48ed5567" +checksum = "3a9d7cb29f1d4c6ec8650abbee35948b8bdefb7f0750a26445ff593eb9bf7fcf" dependencies = [ "amplify_apfloat", "amplify_derive", "amplify_num", "amplify_syn", "ascii", - "rand", + "rand 0.8.5", "serde", "stringly_conversions", "wasm-bindgen", @@ -47,7 +56,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "695e433882668b55b3d7fb0ba22bf9be66a91abe30d7ca1f1a774f8b90b4db4c" dependencies = [ "amplify_num", - "bitflags 2.6.0", + "bitflags", "wasm-bindgen", ] @@ -122,9 +131,9 @@ dependencies = [ [[package]] name = "ascii-armor" -version = "0.7.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4966ac403dc4a666d8131dfe4df684f45acc68d4c7e768db89c463aa5617910" +checksum = "0269eb842ec952b027df0fc33184b6a0dea5ea473160b36992274eb53758461e" dependencies = [ "amplify", "baid64", @@ -139,11 +148,34 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "aws-lc-rs" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b756939cb2f8dc900aa6dcd505e6e2428e9cae7ff7b028c49e3946efa70878" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa9b6986f250236c27e5a204062434a773a13243d2ffc2955f37bdba4c5c6a1" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[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", @@ -172,11 +204,34 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.101", + "which", +] + [[package]] name = "bitcoin-io" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" [[package]] name = "bitcoin_hashes" @@ -190,21 +245,15 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "blake3" -version = "1.5.4" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" dependencies = [ "arrayref", "arrayvec", @@ -222,11 +271,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "borrow-or-share" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" + [[package]] name = "bp-consensus" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40f227ce25d185bc5fc9109ca83dfa8bd0e745f219e320f3da658aaf4fd7e0c5" +checksum = "2d473a0cea358746ab5ef820b62f2530ce6516cb59226c9a3736a8e60c4943d9" dependencies = [ "amplify", "chrono", @@ -239,16 +294,17 @@ dependencies = [ [[package]] name = "bp-core" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c6b213ada98fe5e78a978e67a7044d16d2571edb3f85fcdb4246324ec9514a" +checksum = "d248df4e1ab41de97556bb092891c8c5208604f471a20c4129dc357fd9eade39" dependencies = [ "amplify", "bp-consensus", "bp-dbc", "bp-seals", "commit_verify", - "getrandom", + "getrandom 0.2.16", + "getrandom 0.3.2", "serde", "single_use_seals", "strict_encoding", @@ -258,9 +314,9 @@ dependencies = [ [[package]] name = "bp-dbc" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d33d4cc345a595236441fc2b8726ca7eb693947914b278849d1e2c1923dcb314" +checksum = "2670bd384743ba75ca6d8cf821bcdcb74bfd5715e8798e545331dc00652f612c" dependencies = [ "amplify", "base85", @@ -271,11 +327,46 @@ dependencies = [ "strict_encoding", ] +[[package]] +name = "bp-electrum" +version = "0.11.1-alpha.2+unreviewed" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "752903a7ec4bd5a2dc7709f4eb9fc86abe52a702a0f6699bebb79f021f506ec7" +dependencies = [ + "amplify", + "bp-core", + "byteorder", + "libc", + "log", + "rustls 0.23.26", + "serde", + "serde_json", + "sha2", + "webpki-roots 0.26.10", + "winapi", +] + +[[package]] +name = "bp-esplora" +version = "0.11.1-alpha.2+unreviewed" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faa310a99982cd5e5a51c070a0a0a4fb9ad4db85767febd476e10bbaf4b52ad1" +dependencies = [ + "amplify", + "bp-core", + "bp-invoice", + "log", + "minreq", + "serde", + "serde_with", + "sha2", +] + [[package]] name = "bp-invoice" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6955d67eec75b22532edb859f1f4d7d4ba4af1db304abc511530f4e1a827b7" +checksum = "d2a2365fc099e265705f31f018d4fb9309546cc3fdb6f855da6d2a81e9700bd2" dependencies = [ "amplify", "bech32", @@ -285,16 +376,16 @@ dependencies = [ [[package]] name = "bp-seals" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a7a009fbf7e71be7ab5f43e032c69927f58cd7f59a6a822af64f84d3e8d41c5" +checksum = "3aab0c94862b08721f7a60eb0d13502605147ebc2fc3cfe0ceacdb6d58aeb43c" dependencies = [ "amplify", "baid64", "bp-consensus", "bp-dbc", "commit_verify", - "rand", + "rand 0.9.1", "serde", "single_use_seals", "strict_encoding", @@ -302,9 +393,9 @@ dependencies = [ [[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" @@ -314,13 +405,24 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.31" +version = "1.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" dependencies = [ + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -329,9 +431,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -339,14 +441,34 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets", + "windows-link", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", ] [[package]] name = "commit_encoding_derive" -version = "0.11.0" +version = "0.11.1-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc09678c15e9280cc6eaf29bf437a2cf18fadedd8bf78c369b8ac15fa217dbe5" +checksum = "d12f2e05ae7d81bc49d9f0856ff97968da750bf09f145043155e9c7f13ce4ace" dependencies = [ "amplify", "amplify_syn", @@ -357,13 +479,13 @@ dependencies = [ [[package]] name = "commit_verify" -version = "0.11.0" +version = "0.11.1-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcf5f557e112c684f2458f20c66bab865c01cab56d6a318f64243cba9b163a7" +checksum = "171940b95b456f7c8906c78cd548c1dcf30310c4dc2e2a5ba352ac183bf163b3" dependencies = [ "amplify", "commit_encoding_derive", - "rand", + "rand 0.9.1", "ripemd", "serde", "sha2", @@ -372,16 +494,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" @@ -396,18 +508,18 @@ 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" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-common" @@ -419,6 +531,51 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.101", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "digest" version = "0.10.7" @@ -429,11 +586,33 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] [[package]] name = "fast32" @@ -443,13 +622,26 @@ checksum = "a35a73237400bde66c82e38387343f90d7182a2f2f22729e096a2abd57d75db9" [[package]] name = "fluent-uri" -version = "0.1.4" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" +checksum = "1918b65d96df47d3591bed19c5cca17e3fa5d0707318e4b5ef2eae01764df7e5" dependencies = [ - "bitflags 1.3.2", + "borrow-or-share", + "ref-cast", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "generic-array" version = "0.14.7" @@ -462,22 +654,42 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + [[package]] name = "half" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", @@ -485,9 +697,15 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" [[package]] name = "heck" @@ -495,6 +713,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hex-conservative" version = "0.2.1" @@ -504,16 +728,26 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -527,43 +761,108 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "indexmap" -version = "2.6.0" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.3", "serde", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jobserver" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.2", + "libc", +] [[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 = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" -version = "0.2.161" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" @@ -579,29 +878,66 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minicov" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def6d99771d7c499c26ad4d40eb6645eafd3a1553b35fc26ea5a489a45e82d9a" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" dependencies = [ "cc", "walkdir", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "minreq" +version = "2.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d2aaba477837b46ec1289588180fabfccf0c3b1d1a0c6b1866240cd6cd5ce9" +dependencies = [ + "base64", + "log", + "rustls 0.21.12", + "rustls-webpki 0.101.7", + "serde", + "serde_json", + "webpki-roots 0.25.4", +] + [[package]] name = "mnemonic" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b8f3a258db515d5e91a904ce4ae3f73e091149b90cadbdb93d210bee07f63b" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nonasync" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b1005555d351f593bf72ffc3a89a0d42e243df004d2c4ded17699f10b562b98" +checksum = "d81f7335a3fa37124e24461d6164485760d4c056dd92a81a70c23fc28c2b63c8" dependencies = [ "amplify", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" version = "0.2.19" @@ -613,9 +949,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "paste" @@ -629,33 +965,55 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +dependencies = [ + "proc-macro2", + "syn 2.0.101", +] + [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rand" version = "0.8.5" @@ -663,8 +1021,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -674,7 +1042,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -683,14 +1061,72 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.2", +] + +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", ] +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "rgb-core" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae7debf4fc13bbf2d217f71d29a0233fddf5fc5b148ded64175df36c3635029" +checksum = "eba005ded4929a2d7a6e4cb97103858b9e0d47e9fe7a378ca2b2f1595451d659" dependencies = [ "aluvm", "amplify", @@ -698,7 +1134,7 @@ dependencies = [ "bp-core", "chrono", "commit_verify", - "getrandom", + "getrandom 0.3.2", "mime", "secp256k1", "serde", @@ -710,7 +1146,7 @@ dependencies = [ [[package]] name = "rgb-invoice" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" dependencies = [ "amplify", "baid64", @@ -718,9 +1154,9 @@ dependencies = [ "bp-invoice", "fast32", "fluent-uri", - "indexmap", + "indexmap 2.9.0", "percent-encoding", - "rand", + "rand 0.9.1", "rgb-core", "serde", "strict_encoding", @@ -729,7 +1165,7 @@ dependencies = [ [[package]] name = "rgb-std" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" dependencies = [ "aluvm", "amplify", @@ -737,12 +1173,14 @@ dependencies = [ "baid64", "base85", "bp-core", + "bp-electrum", + "bp-esplora", "chrono", "commit_verify", - "getrandom", - "indexmap", + "getrandom 0.3.2", + "indexmap 2.9.0", "nonasync", - "rand", + "rand 0.9.1", "rgb-core", "rgb-invoice", "serde", @@ -754,7 +1192,7 @@ dependencies = [ [[package]] name = "rgb-stl" -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" dependencies = [ "amplify", "commit_verify", @@ -762,6 +1200,20 @@ dependencies = [ "strict_types", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "ripemd" version = "0.1.3" @@ -771,11 +1223,91 @@ dependencies = [ "digest", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.23.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.103.1", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -787,10 +1319,14 @@ dependencies = [ ] [[package]] -name = "scoped-tls" -version = "1.0.1" +name = "sct" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] [[package]] name = "secp256k1" @@ -799,7 +1335,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", - "rand", + "rand 0.8.5", "secp256k1-sys", "serde", ] @@ -815,29 +1351,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.214" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.101", ] [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -864,13 +1400,43 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_with" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.9.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "serde_yaml" version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap", + "indexmap 2.9.0", "itoa", "ryu", "serde", @@ -879,9 +1445,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -896,21 +1462,20 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "single_use_seals" -version = "0.11.0" +version = "0.11.1-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01aad2d785dc858c4f652d1e18d0c815cd10aa8f15ac7accd2b12b894d7c367" +checksum = "8c36139c6f642d05f2d74501a8f84ccfb5833caeb7c8cde1e6b811261cd526bd" dependencies = [ "amplify_derive", ] [[package]] name = "strict_encoding" -version = "2.7.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d69b4893cf054e129d5288a565102124520d7b94eb9589d1e78202abc7e2092d" +checksum = "8553c0321466c11aa1e33f082c9190194f380efd8824bf5ce4fa56b64b875be9" dependencies = [ "amplify", - "half", "serde", "strict_encoding_derive", "wasm-bindgen", @@ -918,9 +1483,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", @@ -931,15 +1496,14 @@ dependencies = [ [[package]] name = "strict_types" -version = "2.7.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bae7475fc901144d8a35d25e36d76aa020b840f233d60532d6d52318718781b" +checksum = "07dd1bdf4bfce0a1ff3eec041e7d4d20b06d22ca2aaf71338726dd9609e57a5e" dependencies = [ "amplify", "ascii-armor", "baid64", - "half", - "indexmap", + "indexmap 2.9.0", "serde", "serde_json", "serde_yaml", @@ -960,6 +1524,18 @@ dependencies = [ "serde_str_helpers", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "1.0.109" @@ -973,9 +1549,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.85" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -984,29 +1560,60 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.65" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.65" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.101", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", ] [[package]] name = "toml" -version = "0.8.19" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -1016,37 +1623,44 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ - "indexmap", + "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unsafe-libyaml" @@ -1054,6 +1668,12 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "version_check" version = "0.9.5" @@ -1062,9 +1682,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", @@ -1086,49 +1706,59 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[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.85", + "syn 2.0.101", "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", @@ -1136,33 +1766,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.85", + "syn 2.0.101", "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", @@ -1170,39 +1801,147 @@ 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.85", + "syn 2.0.101", ] [[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", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "webpki-roots" +version = "0.26.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37493cadf42a2a939ed404698ded7fb378bf301b5011f973361779a3a74f8c93" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] @@ -1282,30 +2021,44 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.20" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "9e27d6ad3dac991091e4d35de9ba2d2d00647c5d0fc26c5496dee55984ae111b" dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.101", ] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index 709b5bf5..f753b718 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,27 +11,29 @@ default-members = [ resolver = "2" [workspace.package] -version = "0.11.1-alpha.1" +version = "0.11.1-alpha.2+unreviewed" authors = ["Dr Maxim Orlovsky "] homepage = "https://github.com/RGB-WG" repository = "https://github.com/RGB-WG/rgb-std" keywords = ["bitcoin", "lightning", "rgb", "smart-contracts", "lnp-bp"] categories = ["cryptography::cryptocurrencies"] -rust-version = "1.77.0" # Due to use of `rustfix` +rust-version = "1.81.0" edition = "2021" license = "Apache-2.0" [workspace.dependencies] -amplify = "4.7.0" +amplify = "4.8.0" nonasync = "0.1.0" -ascii-armor = "0.7.2" -baid64 = "0.2.2" -strict_encoding = "2.7.0" -strict_types = "2.7.2" -commit_verify = { version = "0.11.0-beta.9", features = ["stl"] } -bp-core = { version = "0.11.1-alpha.1", features = ["stl"] } -bp-invoice = { version = "0.11.1-alpha.1" } -rgb-core = { version = "0.11.1-alpha.1", features = ["stl"] } +ascii-armor = "0.9.0" +baid64 = "0.4.1" +bp-electrum = "0.11.1-alpha.2" +bp-esplora = { version = "0.11.1-alpha.2", default-features = false } +strict_encoding = "2.8.2" +strict_types = "2.8.3" +commit_verify = { version = "0.11.1-alpha.2", features = ["stl"] } +bp-core = { version = "0.11.1-alpha.2", features = ["stl"] } +bp-invoice = { version = "0.11.1-alpha.2" } +rgb-core = { version = "0.11.1-alpha.2", features = ["stl"] } indexmap = "2.4.0" serde_crate = { package = "serde", version = "1", features = ["derive"] } @@ -58,22 +60,28 @@ amplify = { workspace = true } nonasync = { workspace = true } ascii-armor = { workspace = true } baid64 = { workspace = true } +bp-electrum = { workspace = true, optional = true } +bp-esplora = { workspace = true, optional = true } strict_encoding = { workspace = true } strict_types = { workspace = true } commit_verify = { workspace = true } bp-core = { workspace = true } rgb-core = { workspace = true } -rgb-invoice = { version = "0.11.1-alpha.1", path = "invoice" } -aluvm = "0.11.0-beta.9" +rgb-invoice = { version = "0.11.1-alpha.2", path = "invoice" } +aluvm = "0.11.1-alpha.2" base85 = "=2.0.0" chrono = "0.4.38" indexmap = { workspace = true } serde_crate = { workspace = true, optional = true } -rand = "0.8.5" +rand = "0.9.1" [features] default = [] -all = ["fs", "serde"] +all = ["esplora_blocking", "electrum_blocking", "mempool_blocking", "fs", "serde"] +esplora_blocking = ["bp-esplora", "bp-esplora/blocking", "bp-esplora/blocking-https"] +esplora_blocking-wasm = ["bp-esplora", "bp-esplora/blocking-wasm"] +electrum_blocking = ["bp-electrum"] +mempool_blocking = ["esplora_blocking"] serde = [ "serde_crate", "chrono/serde", @@ -89,8 +97,8 @@ fs = [] [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2" -rand = { version = "0.8.4", optional = true } -getrandom = { version = "0.2", features = ["js"] } +rand = { version = "0.9.1", optional = true } +getrandom = { version = "0.3", features = ["wasm_js"] } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = "0.3" diff --git a/MANIFEST.yml b/MANIFEST.yml index 6e84d0f4..aa9bf5b9 100644 --- a/MANIFEST.yml +++ b/MANIFEST.yml @@ -3,7 +3,7 @@ Type: Library Kind: Free software License: Apache-2.0 Language: Rust -Compiler: 1.77 +Compiler: 1.81 Author: Maxim Orlovsky Maintained: LNP/BP Standards Association, Switzerland Maintainers: diff --git a/asset/armored_contract.default b/asset/armored_contract.default index 0b3fb68e..fcf76d6e 100644 --- a/asset/armored_contract.default +++ b/asset/armored_contract.default @@ -1,13 +1,12 @@ -----BEGIN RGB CONSIGNMENT----- -Id: rgb:csg:wxvP60ui-p$xdsn$-Zym51Qu-MW4pBOw-QTDxCI3-wMN2QlE#bread-kansas-yankee -Version: 2 +Id: rgb:csg:7EPeHd3A-SpVC4OT-DQqNfRq-XQJlWQQ-SSZh7ZL-RNjGI8A#monkey-chemist-join +Version: 0 Type: contract -Contract: rgb:dzueA1gq-gVtNGbP-YNB0DCs-tz9SpYl-xEctaAA-yO6UFaI -Schema: rgb:sch:CyqM42yAdM1moWyNZPQedAYt73BM$k9z$dKLUXY1voA#cello-global-deluxe -Check-SHA256: def11f7fb29f94cbf0618caeaad77e65ec1b986e7e6799155c0623a5a9c34120 +Contract: rgb:ekxv8ZNU-206FIlW-XN6ZxMq-OcOErkI-Qu3w06i-~4JCKxQ +Schema: rgb:sch:jF0BoXFm8GGMSV0q9CsY0jmpVkwn811VmU2o7m0lKGo#hammer-citrus-time +Check-SHA256: 753ab0d7bee40de37936bf5e60cebfb15f57627d86cd509f1f82869b9775fce1 -0ssI2000000000000000000000000000000000000000000000000000000D0CRI`I$>^aZh38Qb#np$ -00000000000000000004PGN0j00000000004FGdSW +000000000000d59ZDjxe000000000000000 -----END RGB CONSIGNMENT----- diff --git a/asset/armored_kit.default b/asset/armored_kit.default index 7a10425d..0ad40729 100644 --- a/asset/armored_kit.default +++ b/asset/armored_kit.default @@ -1,9 +1,9 @@ -----BEGIN RGB KIT----- -Id: rgb:kit:e1jW6Rgc-2$JzXDg-XmR8XRJ-v!q$Dzf-yImkPjD-t8EjfvI -Version: 2 -Type-System: sts:8Vb$sM1F-5MsQc20-HEixf55-gJR37FM-0zRKfpY-SwIp35w#design-farmer-camel -Check-SHA256: 5563cc1568e244183804e0db3cec6ff9bf577f4a403924096177bf4a586160da +Id: rgb:kit:jXOeJYkD-NlOgJoP-_zT1Hvl-0fP71Zo-b2mAh2C-i5ISROo +Version: 0 +Type-System: sts:8Vb~sM1F-5MsQc20-HEixf55-gJR37FM-0zRKfpY-SwIp35w#design-farmer-camel +Check-SHA256: 837885c8f8091aeaeb9ec3c3f85a6ff470a415e610b8ba3e49f9b33c9cf9d619 -0ssI2000000000 +000000000 -----END RGB KIT----- diff --git a/asset/armored_transfer.default b/asset/armored_transfer.default index beecbd78..863d7a1e 100644 --- a/asset/armored_transfer.default +++ b/asset/armored_transfer.default @@ -1,13 +1,12 @@ -----BEGIN RGB CONSIGNMENT----- -Id: rgb:csg:MOMZuU7j-SQQCMyX-VDkmCxA-cEnheMc-uAjAHz9-TwRdl0M#lava-byte-manager -Version: 2 +Id: rgb:csg:lBZui4Kc-TXlFr5L-~s7hdIj-VT7hOG_-8vs2vkr-Sfoey1I#blonde-pandora-public +Version: 0 Type: transfer -Contract: rgb:dzueA1gq-gVtNGbP-YNB0DCs-tz9SpYl-xEctaAA-yO6UFaI -Schema: rgb:sch:CyqM42yAdM1moWyNZPQedAYt73BM$k9z$dKLUXY1voA#cello-global-deluxe -Check-SHA256: ff35ed1a54dc95fe75bd4ec1bb00d9ba1ceb8925ae73eab294c1c7c4fc8f09ed +Contract: rgb:ekxv8ZNU-206FIlW-XN6ZxMq-OcOErkI-Qu3w06i-~4JCKxQ +Schema: rgb:sch:jF0BoXFm8GGMSV0q9CsY0jmpVkwn811VmU2o7m0lKGo#hammer-citrus-time +Check-SHA256: 0906488190013e3373e9a4dd53fc62f3b25d51e5378154830f657e9bfff25079 -0s#O3000000000000000000000000000000000000000000000000000000D0CRI`I$>^aZh38Qb#np$ -00000000000000000004PGN0j00000000004FGdSW +000000000000d59ZDjxe000000000000000 -----END RGB CONSIGNMENT----- diff --git a/asset/contract.default b/asset/contract.default index 982e1d1d..18f3e14f 100644 Binary files a/asset/contract.default and b/asset/contract.default differ diff --git a/asset/kit.default b/asset/kit.default index 67d729f7..e19e3f90 100644 Binary files a/asset/kit.default and b/asset/kit.default differ diff --git a/asset/transfer.default b/asset/transfer.default index f1a01edb..f3fe4bef 100644 Binary files a/asset/transfer.default and b/asset/transfer.default differ diff --git a/invoice/Cargo.toml b/invoice/Cargo.toml index 05673093..11b00883 100644 --- a/invoice/Cargo.toml +++ b/invoice/Cargo.toml @@ -25,12 +25,11 @@ bp-core = { workspace = true } bp-invoice = { workspace = true } rgb-core = { workspace = true } indexmap = { workspace = true } -fluent-uri = "0.1.4" +fluent-uri = "0.3.2" percent-encoding = "2.3.1" serde_crate = { workspace = true, optional = true } -rand = "0.8.5" +rand = "0.9.1" [features] default = [] serde = ["serde_crate"] -# TODO: Separate URL with a feature gate diff --git a/invoice/src/amount.rs b/invoice/src/amount.rs index 9007f085..b065e620 100644 --- a/invoice/src/amount.rs +++ b/invoice/src/amount.rs @@ -63,7 +63,7 @@ impl StrictSerialize for Amount {} impl StrictDeserialize for Amount {} impl From for Amount { - fn from(value: RevealedValue) -> Self { Amount(value.value.as_u64()) } + fn from(value: RevealedValue) -> Self { Amount(value.as_u64()) } } impl From for Amount { @@ -74,6 +74,10 @@ impl From for FungibleState { fn from(amount: Amount) -> Self { FungibleState::Bits64(amount.0) } } +impl From for RevealedValue { + fn from(amount: Amount) -> Self { RevealedValue::from(FungibleState::Bits64(amount.0)) } +} + impl Amount { pub const ZERO: Self = Amount(0); diff --git a/invoice/src/builder.rs b/invoice/src/builder.rs index 17f2da31..7af5fc56 100644 --- a/invoice/src/builder.rs +++ b/invoice/src/builder.rs @@ -21,8 +21,8 @@ use std::str::FromStr; -use rgb::ContractId; -use strict_encoding::{FieldName, TypeName}; +use rgb::{ContractId, SchemaId}; +use strict_types::FieldName; use crate::invoice::{Beneficiary, InvoiceState, RgbInvoice, RgbTransport, XChainNet}; use crate::{Allocation, Amount, CoinAmount, NonFungible, Precision, TransportParseError}; @@ -36,11 +36,10 @@ impl RgbInvoiceBuilder { Self(RgbInvoice { transports: vec![RgbTransport::UnspecifiedMeans], contract: None, - iface: None, - operation: None, - assignment: None, + schema: None, + assignment_name: None, + assignment_state: None, beneficiary: beneficiary.into(), - owned_state: InvoiceState::Void, expiry: None, unknown_query: none!(), }) @@ -50,36 +49,28 @@ impl RgbInvoiceBuilder { Self::new(beneficiary).set_contract(contract_id) } - pub fn rgb20(contract_id: ContractId, beneficiary: impl Into>) -> Self { - Self::with(contract_id, beneficiary).set_interface("RGB20") - } - - pub fn rgb20_anything(beneficiary: impl Into>) -> Self { - Self::new(beneficiary).set_interface("RGB20") - } - pub fn set_contract(mut self, contract_id: ContractId) -> Self { self.0.contract = Some(contract_id); self } - pub fn set_interface(mut self, name: impl Into) -> Self { - self.0.iface = Some(name.into()); + pub fn set_schema(mut self, schema_id: SchemaId) -> Self { + self.0.schema = Some(schema_id); self } - pub fn set_operation(mut self, name: impl Into) -> Self { - self.0.operation = Some(name.into()); + pub fn set_assignment_name(mut self, assignment_name: impl Into) -> Self { + self.0.assignment_name = Some(assignment_name.into()); self } - pub fn set_assignment(mut self, name: impl Into) -> Self { - self.0.assignment = Some(name.into()); + pub fn set_void(mut self) -> Self { + self.0.assignment_state = Some(InvoiceState::Void); self } pub fn set_amount_raw(mut self, amount: impl Into) -> Self { - self.0.owned_state = InvoiceState::Amount(amount.into()); + self.0.assignment_state = Some(InvoiceState::Amount(amount.into())); self } @@ -94,12 +85,13 @@ impl RgbInvoiceBuilder { Err(_) => return Err(self), } .to_amount_unchecked(); - self.0.owned_state = InvoiceState::Amount(amount); + self.0.assignment_state = Some(InvoiceState::Amount(amount)); Ok(self) } pub fn set_allocation_raw(mut self, allocation: impl Into) -> Self { - self.0.owned_state = InvoiceState::Data(NonFungible::RGB21(allocation.into())); + self.0.assignment_state = + Some(InvoiceState::Data(NonFungible::FractionedToken(allocation.into()))); self } diff --git a/invoice/src/data.rs b/invoice/src/data.rs index 7eaa93f7..0022efc8 100644 --- a/invoice/src/data.rs +++ b/invoice/src/data.rs @@ -21,7 +21,7 @@ use std::str::FromStr; -use rgb::{DataState, RevealedData}; +use rgb::RevealedData; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use strict_encoding::{StrictDeserialize, StrictSerialize}; @@ -37,14 +37,14 @@ use crate::LIB_NAME_RGB_CONTRACT; )] pub enum NonFungible { #[display(inner)] - RGB21(Allocation), + FractionedToken(Allocation), } impl FromStr for NonFungible { type Err = AllocationParseError; fn from_str(s: &str) -> Result { let allocation = Allocation::from_str(s)?; - Ok(NonFungible::RGB21(allocation)) + Ok(NonFungible::FractionedToken(allocation)) } } @@ -158,19 +158,13 @@ impl StrictDeserialize for Allocation {} impl From for Allocation { fn from(data: RevealedData) -> Self { - Allocation::from_strict_serialized(data.value.into()).expect("invalid allocation data") + Allocation::from_strict_serialized(data.into()).expect("invalid allocation data") } } -impl From for Allocation { - fn from(state: DataState) -> Self { - Allocation::from_strict_serialized(state.into()).expect("invalid allocation data") - } -} - -impl From for DataState { +impl From for RevealedData { fn from(allocation: Allocation) -> Self { - DataState::from( + RevealedData::from( allocation .to_strict_serialized() .expect("invalid allocation data"), diff --git a/invoice/src/invoice.rs b/invoice/src/invoice.rs index fed09de4..3cee7e28 100644 --- a/invoice/src/invoice.rs +++ b/invoice/src/invoice.rs @@ -23,11 +23,11 @@ use std::ops::Deref; use std::str::FromStr; use amplify::{ByteArray, Bytes32}; -use bp::{InvalidPubkey, OutputPk, PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash}; +use bp::{InternalPk, InvalidPubkey, OutputPk, PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash}; use indexmap::IndexMap; use invoice::{AddressNetwork, AddressPayload, Network}; -use rgb::{AttachId, ChainNet, ContractId, Layer1, SecretSeal}; -use strict_encoding::{FieldName, TypeName}; +use rgb::{ChainNet, ContractId, Layer1, SchemaId, SecretSeal, StateType}; +use strict_types::FieldName; use crate::{Amount, NonFungible}; @@ -57,8 +57,6 @@ pub enum InvoiceState { Amount(Amount), #[display(inner)] Data(NonFungible), - #[display(inner)] - Attach(AttachId), } impl FromStr for InvoiceState { @@ -70,14 +68,22 @@ impl FromStr for InvoiceState { Ok(InvoiceState::Amount(amount)) } else if let Ok(data) = NonFungible::from_str(s) { Ok(InvoiceState::Data(data)) - } else if let Ok(attach) = AttachId::from_str(s) { - Ok(InvoiceState::Attach(attach)) } else { Err(InvoiceStateError::ParseError(s.to_owned())) } } } +impl From for StateType { + fn from(val: InvoiceState) -> Self { + match val { + InvoiceState::Void => StateType::Void, + InvoiceState::Amount(_) => StateType::Fungible, + InvoiceState::Data(_) => StateType::Structured, + } + } +} + #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] #[non_exhaustive] pub enum XChainNet { @@ -205,8 +211,7 @@ impl TryFrom<[u8; 33]> for Pay2Vout { pub enum Beneficiary { #[from] BlindedSeal(SecretSeal), - #[from] - WitnessVout(Pay2Vout), + WitnessVout(Pay2Vout, Option), } #[derive(Clone, Eq, PartialEq, Debug)] @@ -214,11 +219,10 @@ pub enum Beneficiary { pub struct RgbInvoice { pub transports: Vec, pub contract: Option, - pub iface: Option, - pub operation: Option, - pub assignment: Option, + pub schema: Option, + pub assignment_name: Option, + pub assignment_state: Option, pub beneficiary: XChainNet, - pub owned_state: InvoiceState, /// UTC unix timestamp pub expiry: Option, pub unknown_query: IndexMap, diff --git a/invoice/src/parse.rs b/invoice/src/parse.rs index c9cb19c0..c4d66370 100644 --- a/invoice/src/parse.rs +++ b/invoice/src/parse.rs @@ -25,17 +25,20 @@ use std::num::ParseIntError; use std::str::FromStr; use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use fluent_uri::enc::EStr; +use bp::InternalPk; +use fluent_uri::encoding::encoder::Query; +use fluent_uri::encoding::EStr; use fluent_uri::Uri; use indexmap::IndexMap; use invoice::{AddressPayload, UnknownNetwork}; use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; -use rgb::{ChainNet, ContractId, SecretSeal}; -use strict_encoding::{InvalidRString, TypeName}; +use rgb::{ChainNet, ContractId, SchemaId, SecretSeal}; +use strict_types::FieldName; use crate::invoice::{Beneficiary, InvoiceState, Pay2Vout, RgbInvoice, RgbTransport, XChainNet}; const OMITTED: &str = "~"; +const ASSIGNMENT: &str = "assignment_name"; const EXPIRY: &str = "expiry"; const ENDPOINTS: &str = "endpoints"; const TRANSPORT_SEP: char = ','; @@ -66,10 +69,6 @@ pub enum TransportParseError { #[derive(Debug, Display, Error, From)] #[display(doc_comments)] pub enum InvoiceParseError { - #[from] - #[display(inner)] - Uri(fluent_uri::ParseError), - /// invalid invoice. Invalid, @@ -77,14 +76,17 @@ pub enum InvoiceParseError { /// one. Authority, - /// contract id is missed from the invoice. - ContractMissed, + /// contract id is missing from the invoice. + ContractMissing, + + /// schema information is missing from the invoice. + SchemaMissing, - /// interface information is missed from the invoice. - IfaceMissed, + /// assignment state is missing from the invoice. + AssignmentStateMissing, - /// assignment data is missed from the invoice. - AssignmentMissed, + /// beneficiary is missing from the invoice. + BeneficiaryMissing, /// invalid invoice scheme {0}. InvalidScheme(String), @@ -92,14 +94,17 @@ pub enum InvoiceParseError { /// no invoice transport has been provided. NoTransport, - /// invalid invoice: contract ID present but no contract interface provided. - ContractIdNoIface, - /// invalid contract ID. InvalidContractId(String), - /// invalid interface {0}. - InvalidIface(String), + /// invalid schema {0}. + InvalidSchemaId(String), + + /// invalid assignment state {0}. + InvalidAssignmentState(String), + + /// invalid assignment name {0}. + InvalidAssignmentName(String), /// invalid expiration timestamp {0}. InvalidExpiration(String), @@ -111,10 +116,6 @@ pub enum InvoiceParseError { /// invalid query parameter {0}. InvalidQueryParam(String), - #[from] - #[display(inner)] - Id(baid64::Baid64ParseError), - /// can't recognize beneficiary "{0}": it should be either a bitcoin address /// or a blinded UTXO seal. Beneficiary(String), @@ -123,24 +124,23 @@ pub enum InvoiceParseError { #[display(inner)] Num(ParseIntError), - /// can't recognize amount "{0}": it should be valid rgb21 allocation - /// data. + /// can't recognize amount "{0}": it should be valid allocation data. Data(String), - - #[from] - /// invalid interface name. - IfaceName(InvalidRString), } impl RgbInvoice { fn has_params(&self) -> bool { self.expiry.is_some() + || self.assignment_name.is_some() || self.transports != vec![RgbTransport::UnspecifiedMeans] || !self.unknown_query.is_empty() } fn query_params(&self) -> IndexMap { let mut query_params: IndexMap = IndexMap::new(); + if let Some(ref assignment) = self.assignment_name { + query_params.insert(ASSIGNMENT.to_string(), assignment.to_string()); + } if let Some(expiry) = self.expiry { query_params.insert(EXPIRY.to_string(), expiry.to_string()); } @@ -212,7 +212,14 @@ impl Display for XChainNet { write!(f, "{}:", self.chain_network().prefix())?; match self.into_inner() { Beneficiary::BlindedSeal(seal) => Display::fmt(&seal, f), - Beneficiary::WitnessVout(payload) => payload.fmt_baid64(f), + Beneficiary::WitnessVout(pay2vout, internal_pk) => { + write!( + f, + "{}{}", + pay2vout.to_baid64_string(), + if let Some(ipk) = internal_pk { format!("+{ipk}") } else { s!("") } + ) + } } } } @@ -260,22 +267,41 @@ impl FromStr for XChainNet { fn from_str(s: &str) -> Result { let Some((cn, beneficiary)) = s.split_once(':') else { - return Err(InvoiceParseError::Beneficiary(s.to_owned())); + return Err(InvoiceParseError::Beneficiary(s!("missing beneficiary HRI"))); }; let cn = - ChainNet::from_str(cn).map_err(|_| InvoiceParseError::Beneficiary(s.to_owned()))?; + ChainNet::from_str(cn).map_err(|e| InvoiceParseError::Beneficiary(e.to_string()))?; if let Ok(seal) = SecretSeal::from_str(beneficiary) { return Ok(XChainNet::with(cn, Beneficiary::BlindedSeal(seal))); } - let payload = Pay2Vout::from_str(beneficiary)?; - Ok(XChainNet::with(cn, Beneficiary::WitnessVout(payload))) + let (pay2vout, internal_pk) = beneficiary + .split_once("+") + .map(|(p, i)| (p, Some(i))) + .unwrap_or((beneficiary, None)); + + let pay2vout = Pay2Vout::from_str(pay2vout) + .map_err(|e| InvoiceParseError::Beneficiary(e.to_string()))?; + + let internal_pk = match internal_pk { + None => None, + Some(i) => { + if i.is_empty() { + return Err(InvoiceParseError::Beneficiary(s!("missing internal pk"))); + } + Some( + InternalPk::from_str(i) + .map_err(|_| InvoiceParseError::Beneficiary(s!("invalid internal pk")))?, + ) + } + }; + + Ok(XChainNet::with(cn, Beneficiary::WitnessVout(pay2vout, internal_pk))) } } impl Display for RgbInvoice { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let amt = self.owned_state.to_string(); if let Some(contract) = self.contract { let id = if f.alternate() { contract.to_string().replace('-', "") @@ -286,19 +312,17 @@ impl Display for RgbInvoice { } else { write!(f, "rgb:{OMITTED}/")?; } - if let Some(iface) = self.iface.clone() { - write!(f, "{iface}/")?; + if let Some(schema) = self.schema { + let schema_str = format!("{schema:-#}"); + let id = if f.alternate() { schema_str.replace('-', "") } else { schema_str }; + write!(f, "{id}/")?; } else { write!(f, "{OMITTED}/")?; } - if let Some(ref op) = self.operation { - write!(f, "{op}/")?; - } - if let Some(ref assignment_name) = self.assignment { - write!(f, "{assignment_name}/")?; - } - if !amt.is_empty() { - write!(f, "{amt}+")?; + if let Some(ref assignment_state) = self.assignment_state { + write!(f, "{assignment_state}/")?; + } else { + write!(f, "{OMITTED}/")?; } let beneficiary = if f.alternate() { self.beneficiary.to_string().replace('-', "") @@ -334,9 +358,9 @@ impl FromStr for RgbInvoice { type Err = InvoiceParseError; fn from_str(s: &str) -> Result { - let uri = Uri::parse(s)?; + let uri = Uri::parse(s).map_err(|_| InvoiceParseError::Invalid)?; - let scheme = uri.scheme().ok_or(InvoiceParseError::Invalid)?; + let scheme = uri.scheme(); if scheme.as_str() != "rgb" { return Err(InvoiceParseError::InvalidScheme(scheme.to_string())); } @@ -346,10 +370,10 @@ impl FromStr for RgbInvoice { return Err(InvoiceParseError::Authority); } - let mut path = path.segments(); + let mut path = path.split('/'); let Some(contract_id_str) = path.next() else { - return Err(InvoiceParseError::ContractMissed); + return Err(InvoiceParseError::ContractMissing); }; let contract = match ContractId::from_str(contract_id_str.as_str()) { Ok(cid) => Some(cid), @@ -359,37 +383,30 @@ impl FromStr for RgbInvoice { } }; - let Some(iface_str) = path.next() else { - return Err(InvoiceParseError::IfaceMissed); + let Some(schema_str) = path.next() else { + return Err(InvoiceParseError::SchemaMissing); }; - let iface = match TypeName::try_from(iface_str.to_string()) { + let schema = match SchemaId::from_str(schema_str.as_ref()) { Ok(i) => Some(i), - Err(_) if iface_str.as_str() == OMITTED => None, - Err(_) => return Err(InvoiceParseError::InvalidIface(iface_str.to_string())), + Err(_) if schema_str.as_str() == OMITTED => None, + Err(_) => return Err(InvoiceParseError::InvalidSchemaId(schema_str.to_string())), }; - if contract.is_some() && iface.is_none() { - return Err(InvoiceParseError::ContractIdNoIface); - } - let Some(assignment) = path.next() else { - return Err(InvoiceParseError::AssignmentMissed); + let Some(assignment_str) = path.next() else { + return Err(InvoiceParseError::AssignmentStateMissing); }; - let (amount, beneficiary) = assignment - .as_str() - .split_once('+') - .map(|(a, b)| (Some(a), Some(b))) - .unwrap_or((Some(assignment.as_str()), None)); - // TODO: support other state types - let (beneficiary_str, value) = match (beneficiary, amount) { - (Some(b), Some(a)) => ( - b, - InvoiceState::from_str(a).map_err(|_| InvoiceParseError::Data(a.to_string()))?, - ), - (None, Some(b)) => (b, InvoiceState::Void), - _ => unreachable!(), + let assignment_state = match InvoiceState::from_str(assignment_str.as_ref()) { + Ok(i) => Some(i), + Err(_) if assignment_str.as_str() == OMITTED => None, + Err(_) => { + return Err(InvoiceParseError::InvalidAssignmentState(assignment_str.to_string())) + } }; - let beneficiary = XChainNet::::from_str(beneficiary_str)?; + let Some(beneficiary_str) = path.next() else { + return Err(InvoiceParseError::BeneficiaryMissing); + }; + let beneficiary = XChainNet::::from_str(beneficiary_str.as_ref())?; let mut query_params = map_query_params(&uri)?; let transports = if let Some(endpoints) = query_params.shift_remove(ENDPOINTS) { @@ -406,6 +423,13 @@ impl FromStr for RgbInvoice { vec![RgbTransport::UnspecifiedMeans] }; + let mut assignment_name = None; + if let Some(assignment) = query_params.shift_remove(ASSIGNMENT) { + let name = FieldName::try_from(assignment.clone()) + .map_err(|_| InvoiceParseError::InvalidAssignmentName(assignment))?; + assignment_name = Some(name); + } + let mut expiry = None; if let Some(exp) = query_params.shift_remove(EXPIRY) { let timestamp = exp @@ -417,18 +441,17 @@ impl FromStr for RgbInvoice { Ok(RgbInvoice { transports, contract, - iface, - operation: None, - assignment: None, + schema, + assignment_name, beneficiary, - owned_state: value, + assignment_state, expiry, unknown_query: query_params, }) } } -fn percent_decode(estr: &EStr) -> Result { +fn percent_decode(estr: &EStr) -> Result { Ok(estr .decode() .into_string() @@ -454,106 +477,160 @@ fn map_query_params(uri: &Uri<&str>) -> Result, Invoice #[cfg(test)] mod test { use super::*; - use crate::Amount; + use crate::{Allocation, Amount, NonFungible}; #[test] fn parse() { - // rgb20/rgb25 parameters - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; + // nia parameters + let invoice_str = "rgb:eIbQx5Am-XRDjj01-RM~5eo7-rv2nluD-OnBJRAy-S9~Yfts/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); - assert_eq!(invoice.owned_state, InvoiceState::Amount(Amount::from(100u64))); + assert_eq!(invoice.assignment_state, Some(InvoiceState::Amount(Amount::from(100u64)))); assert_eq!(invoice.to_string(), invoice_str); assert_eq!(format!("{invoice:#}"), invoice_str.replace('-', "")); - // rgb21 parameters - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB21/1@1+bc:\ - utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; + // uda parameters + let invoice_str = "rgb:tx8NOyGe-NkPZex~-U0J_1om-CfrOeoO-7di9xZb-vT3nxyo/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/1@0/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); + assert_eq!( + invoice.assignment_state, + Some(InvoiceState::Data(NonFungible::FractionedToken(Allocation::with(0, 1)))) + ); assert_eq!(invoice.to_string(), invoice_str); assert_eq!(format!("{invoice:#}"), invoice_str.replace('-', "")); + // witness vout without internal pk + let invoice_str = "rgb:eIbQx5Am-XRDjj01-RM~5eo7-rv2nluD-OnBJRAy-S9~Yfts/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/Sa/bc:wvout:\ + A8cJ7Ww3-NIzADo3-Tzp_5aD-7CTBWmA-AAAAAAA-AAAAAAA-ALSQkcw"; + let invoice = RgbInvoice::from_str(invoice_str).unwrap(); + assert_eq!(invoice.to_string(), invoice_str); + + // witness vout with internal pk + let invoice_str = "rgb:eIbQx5Am-XRDjj01-RM~5eo7-rv2nluD-OnBJRAy-S9~Yfts/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/Sa/bc:wvout:\ + A8cJ7Ww3-NIzADo3-Tzp_5aD-7CTBWmA-AAAAAAA-AAAAAAA-ALSQkcw\ + +750f58bcca0fdb11891e7979d829b8c56e0963dba08c44f54a256cf7dbc09caf"; + let invoice = RgbInvoice::from_str(invoice_str).unwrap(); + assert_eq!(invoice.to_string(), invoice_str); + // no amount - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; + let invoice_str = "rgb:eIbQx5Am-XRDjj01-RM~5eo7-rv2nluD-OnBJRAy-S9~Yfts/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/~/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); + assert_eq!(invoice.assignment_state, None); assert_eq!(invoice.to_string(), invoice_str); // no allocation - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB21/bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; + let invoice_str = "rgb:eIbQx5Am-XRDjj01-RM~5eo7-rv2nluD-OnBJRAy-S9~Yfts/\ + V8ujLLtH2k2QSmaDpZI3o06ACIm2UNT0TZl11FiqRuY/~/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); + assert_eq!(invoice.assignment_state, None); assert_eq!(invoice.to_string(), invoice_str); // no contract ID - let invoice_str = - "rgb:~/RGB20/bc:utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; + let invoice_str = "rgb:~/XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/~/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.to_string(), invoice_str); - // no contract ID nor iface - let invoice_str = "rgb:~/~/bc:utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; + // no contract ID nor schema + let invoice_str = + "rgb:~/~/~/bc:utxob:4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.to_string(), invoice_str); - // contract ID provided but no iface - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/~/bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; - let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::ContractIdNoIface))); + // contract ID provided but no schema + let invoice_str = "rgb:eIbQx5Am-XRDjj01-RM~5eo7-rv2nluD-OnBJRAy-S9~Yfts/~/~/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa"; + let invoice = RgbInvoice::from_str(invoice_str).unwrap(); + assert_eq!(invoice.to_string(), invoice_str); // invalid contract ID let invalid_contract_id = "invalid"; let invoice_str = format!( - "rgb:{invalid_contract_id}/RGB20/bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F" + "rgb:{invalid_contract_id}/XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa" ); let result = RgbInvoice::from_str(&invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidContractId(c)) if c == invalid_contract_id)); + // with assignment name + let assignment_name = "assetOwner"; + let invoice_str = format!( + "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?{ASSIGNMENT}={assignment_name}" + ); + let invoice = RgbInvoice::from_str(&invoice_str).unwrap(); + assert_eq!(invoice.assignment_name, Some(FieldName::from(assignment_name))); + assert_eq!(invoice.to_string(), invoice_str); + + // bad assignment_name + let assignment_name = ""; + let invoice_str = format!( + "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?{ASSIGNMENT}={assignment_name}" + ); + let result = RgbInvoice::from_str(&invoice_str); + assert!(matches!(result, Err(InvoiceParseError::InvalidAssignmentName(_)))); + // with expiration - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?\ + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?\ expiry=1682086371"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.to_string(), invoice_str); // bad expiration - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?expiry=six"; + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?expiry=six"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidExpiration(_)))); // with bad query parameter - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?expiry"; + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?expiry"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); // with an unknown query parameter - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?unknown=new"; + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?unknown=new"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.to_string(), invoice_str); // with two unknown query parameters - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?unknown=new&\ + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?unknown=new&\ another=new"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.to_string(), invoice_str); // with expiration and an unknown query parameter - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?\ + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?\ expiry=1682086371&unknown=new"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.to_string(), invoice_str); // with an unknown query parameter containing percent-encoded text - let invoice_base = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:\ - utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?"; + let invoice_base = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?"; let query_key_encoded = ":@-%20%23"; let query_key_decoded = ":@- #"; let query_val_encoded = "?/.%26%3D"; @@ -569,39 +646,43 @@ mod test { ); // no scheme - let invoice_str = "2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX/~/bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; + let invoice_str = "eIbQx5Am-XRDjj01-RM~5eo7-rv2nluD-OnBJRAy-S9~Yfts/~/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::Invalid))); // invalid scheme let invoice_str = "bad:2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX/~/bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F"; + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidScheme(_)))); // empty transport endpoint specification - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints="; + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints="; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); // invalid transport endpoint specification - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=bad"; + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints=bad"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); // invalid transport variant - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpca:/\ + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints=rpca:/\ /host.example.com"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); // rgb-rpc variant - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc://\ + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints=rpc://\ host.example.com"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.transports, vec![RgbTransport::JsonRpc { @@ -611,8 +692,9 @@ mod test { assert_eq!(invoice.to_string(), invoice_str); // rgb-rpc variant, host containing authentication, "-" characters and port - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpcs:/\ + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints=rpcs:/\ /user:pass@host-1.ex-ample.com:1234"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.transports, vec![RgbTransport::JsonRpc { @@ -622,8 +704,9 @@ mod test { assert_eq!(invoice.to_string(), invoice_str); // rgb-rpc variant, IPv6 host - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpcs:/\ + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints=rpcs:/\ /%5B2001:db8::1%5D:1234"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); assert_eq!(invoice.transports, vec![RgbTransport::JsonRpc { @@ -633,29 +716,32 @@ mod test { assert_eq!(invoice.to_string(), invoice_str); // rgb-rpc variant with missing host - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc://"; + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints=rpc://"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); // rgb-rpc variant with invalid separator - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc/\ + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints=rpc/\ host.example.com"; let result = RgbInvoice::from_str(invoice_str); assert!(matches!(result, Err(InvoiceParseError::InvalidQueryParam(_)))); // rgb-rpc variant with invalid transport host specification - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpc://\ + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints=rpc://\ ho]t"; let result = RgbInvoice::from_str(invoice_str); - assert!(matches!(result, Err(InvoiceParseError::Uri(_)))); + assert!(matches!(result, Err(InvoiceParseError::Invalid))); // rgb+http variant let invoice_str = "rgb:\ - 11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - BF+bc:utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=https://\ + 3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/\ + BF/bc:utxob:4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints=https://\ host.example.com"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); let transports = vec![RgbTransport::RestHttp { @@ -666,8 +752,9 @@ mod test { assert_eq!(invoice.to_string(), invoice_str); // rgb+ws variant - let invoice_str = "rgb:11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/BF+bc:utxob:\ - zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=wss://\ + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints=wss://\ host.example.com"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); let transports = vec![RgbTransport::WebSockets { @@ -677,12 +764,20 @@ mod test { assert_eq!(invoice.transports, transports); assert_eq!(invoice.to_string(), invoice_str); - // TODO: rgb+storm variant + // rgb+storm variant + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:utxob:\ + 4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints=storm:\ + //_/"; + let invoice = RgbInvoice::from_str(invoice_str).unwrap(); + let transports = vec![RgbTransport::Storm {}]; + assert_eq!(invoice.transports, transports); + assert_eq!(invoice.to_string(), invoice_str); // multiple transports let invoice_str = "rgb:\ - 11Fa!$Dk-rUWXhy8-7H35qXm-pLGGLOo-txBWUgj-tbOaSbI/RGB20/\ - BF+bc:utxob:zlVS28Rb-amM5lih-ONXGACC-IUWD0Y$-0JXcnWZ-MQn8VEI-B39!F?endpoints=rpcs://\ + 3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/\ + BF/bc:utxob:4vm1CX2Z-K8hMo59-e7dgGBS-Jka7mYn-Xe~yP85-yUiHHxr-aVlYa?endpoints=rpcs://\ host1.example.com,http://host2.example.com,ws://host3.example.com"; let invoice = RgbInvoice::from_str(invoice_str).unwrap(); let transports = vec![ @@ -721,6 +816,42 @@ mod test { // rgb-rpc variant with invalid separator parse error let result = RgbTransport::from_str("rpc/host.example.com"); assert!(matches!(result, Err(TransportParseError::InvalidTransport(_)))); + + // invalid witness vout: invalid length of identifier wvout + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:wvout:\ + +750f58bcca0fdb11891e7979d829b8c56e0963dba08c44f54a256cf7dbc09caf"; + let result = RgbInvoice::from_str(invoice_str); + assert!(matches!(result, Err(InvoiceParseError::Beneficiary(_)))); + + // invalid witness vout: missing beneficiary HRI + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/\ + 750f58bcca0fdb11891e7979d829b8c56e0963dba08c44f54a256cf7dbc09caf"; + let result = RgbInvoice::from_str(invoice_str); + assert!(matches!(result, Err(InvoiceParseError::Beneficiary(_)))); + + // invalid witness vout: invalid chain-network pair + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/:\ + +750f58bcca0fdb11891e7979d829b8c56e0963dba08c44f54a256cf7dbc09caf"; + let result = RgbInvoice::from_str(invoice_str); + assert!(matches!(result, Err(InvoiceParseError::Beneficiary(_)))); + + // invalid witness vout: invalid internal pk + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:wvout:\ + BYWmQlmL-$i5Co3j-LtTvxSr-53!\ + Brv7-fc7ZntC-ha988ci-jqKOj4Q+750f58bcca0fdb11891e7979"; + let result = RgbInvoice::from_str(invoice_str); + assert!(matches!(result, Err(InvoiceParseError::Beneficiary(_)))); + + // invalid witness vout: missing internal pk + let invoice_str = "rgb:3NoxsLum-cRPebTV-gTZY8qY-KS20lx7-OqgtBls-t7muan4/\ + XvmU3d4_nQQ8S7oagbXi07x5vjMm7P~ERukQNX6SC4M/BF/bc:wvout:\ + BYWmQlmL-$i5Co3j-LtTvxSr-53!Brv7-fc7ZntC-ha988ci-jqKOj4Q+"; + let result = RgbInvoice::from_str(invoice_str); + assert!(matches!(result, Err(InvoiceParseError::Beneficiary(_)))); } #[test] diff --git a/src/containers/anchors.rs b/src/containers/anchors.rs index f2e9a458..490a68a2 100644 --- a/src/containers/anchors.rs +++ b/src/containers/anchors.rs @@ -22,28 +22,31 @@ use std::cmp::Ordering; use amplify::ByteArray; -use bp::dbc::opret::OpretProof; -use bp::dbc::tapret::TapretProof; -use bp::dbc::{anchor, Anchor}; +use bp::dbc::Anchor; use bp::{dbc, Tx, Txid}; use commit_verify::mpc; use rgb::validation::{DbcProof, EAnchor}; -use rgb::{BundleId, DiscloseHash, GraphSeal, OpId, Operation, Transition, TransitionBundle}; +use rgb::{BundleId, DiscloseHash, TransitionBundle}; use strict_encoding::StrictDumb; -use crate::{MergeReveal, MergeRevealError, TypedAssignsExt, LIB_NAME_RGB_STD}; +use crate::{MergeReveal, MergeRevealError, LIB_NAME_RGB_STD}; -#[derive(Clone, Eq, PartialEq, Debug, Display, Error)] -#[display("state transition {0} is not a part of the bundle.")] -pub struct UnrelatedTransition(OpId, Transition); - -#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)] +/// Error merging two [`SealWitness`]es. +#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From)] #[display(doc_comments)] -pub enum AnchoredBundleMismatch { - /// witness bundle for witness id {0} already has both opret and tapret information. - AlreadyDouble(Txid), - /// the combined anchored bundles for witness id {0} are of the same type. - SameBundleType(Txid), +pub enum SealWitnessMergeError { + /// Error merging two MPC proofs, which are unrelated. + #[display(inner)] + #[from] + MpcMismatch(mpc::MergeError), + + /// Error merging two witness proofs, which are unrelated. + #[display(inner)] + #[from] + WitnessMergeError(MergeRevealError), + + /// seal witnesses can't be merged since they have different DBC proofs. + DbcMismatch, } #[derive(Clone, Eq, PartialEq, Debug)] @@ -56,18 +59,36 @@ pub enum AnchoredBundleMismatch { )] pub struct SealWitness { pub public: PubWitness, - pub anchor: AnchorSet, + pub merkle_block: mpc::MerkleBlock, + pub dbc_proof: DbcProof, } impl SealWitness { - pub fn new(witness: PubWitness, anchor: AnchorSet) -> Self { + pub fn new(witness: PubWitness, merkle_block: mpc::MerkleBlock, dbc_proof: DbcProof) -> Self { SealWitness { public: witness, - anchor, + merkle_block, + dbc_proof, } } pub fn witness_id(&self) -> Txid { self.public.to_witness_id() } + + /// Merges two [`SealWitness`]es keeping revealed data. + pub fn merge_reveal(&mut self, other: &Self) -> Result<(), SealWitnessMergeError> { + if self.dbc_proof != other.dbc_proof { + return Err(SealWitnessMergeError::DbcMismatch); + } + self.public.merge_reveal(&other.public)?; + self.merkle_block.merge_reveal(&other.merkle_block)?; + Ok(()) + } + + pub fn known_bundle_ids(&self) -> impl Iterator { + let map = self.merkle_block.to_known_message_map().release(); + map.into_values() + .map(|msg| BundleId::from_byte_array(msg.to_byte_array())) + } } pub trait ToWitnessId { @@ -79,8 +100,35 @@ impl ToWitnessId for PubWitness { } impl MergeReveal for PubWitness { - fn merge_reveal(self, other: Self) -> Result { - self.merge_reveal(other) + fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> { + if self == other { + return Ok(()); + } + if self.txid() != other.txid() { + return Err(MergeRevealError::TxidMismatch(self.txid(), other.txid())); + } + if let Self::Tx(tx2) = other { + if let Self::Tx(tx1) = self { + // Replace each input in tx1 with the one from tx2 if it has more witness or + // sig_script data + for (input1, input2) in tx1.inputs.iter_mut().zip(tx2.inputs.iter()) { + let input1_witness_len: usize = input1.witness.iter().map(|w| w.len()).sum(); + let input2_witness_len: usize = input2.witness.iter().map(|w| w.len()).sum(); + match input1_witness_len.cmp(&input2_witness_len) { + std::cmp::Ordering::Less => *input1 = input2.clone(), + std::cmp::Ordering::Equal => { + if input2.sig_script.len() > input1.sig_script.len() { + *input1 = input2.clone(); + } + } + std::cmp::Ordering::Greater => {} + } + } + } else { + *self = other.clone(); + } + } + Ok(()) } } @@ -96,8 +144,7 @@ pub enum PubWitness { #[strict_type(tag = 0x00)] Txid(Txid), #[strict_type(tag = 0x01)] - Tx(Tx), /* TODO: Consider using `UnsignedTx` here - * TODO: Add SPV as an option here */ + Tx(Tx), } impl PartialEq for PubWitness { @@ -130,21 +177,6 @@ impl PubWitness { PubWitness::Tx(tx) => Some(tx), } } - - pub fn merge_reveal(self, other: Self) -> Result { - match (self, other) { - (Self::Txid(txid1), Self::Txid(txid2)) if txid1 == txid2 => Ok(Self::Txid(txid1)), - (Self::Txid(txid), Self::Tx(tx)) | (Self::Txid(txid), Self::Tx(tx)) - if txid == tx.txid() => - { - Ok(Self::Tx(tx)) - } - // TODO: tx1 and tx2 may differ on their witness data; take the one having most of the - // witness - (Self::Tx(tx1), Self::Tx(tx2)) if tx1.txid() == tx2.txid() => Ok(Self::Tx(tx1)), - (a, b) => Err(MergeRevealError::TxidMismatch(a.txid(), b.txid())), - } - } } #[derive(Clone, Eq, Debug)] @@ -157,210 +189,43 @@ impl PubWitness { )] #[derive(CommitEncode)] #[commit_encode(strategy = strict, id = DiscloseHash)] -pub struct WitnessBundle { +pub struct WitnessBundle { pub pub_witness: PubWitness, - pub anchored_bundle: AnchoredBundle, + pub anchor: Anchor, + pub bundle: TransitionBundle, } -impl PartialEq for WitnessBundle { +impl PartialEq for WitnessBundle { fn eq(&self, other: &Self) -> bool { self.pub_witness == other.pub_witness } } -impl Ord for WitnessBundle { +impl Ord for WitnessBundle { fn cmp(&self, other: &Self) -> Ordering { self.pub_witness.cmp(&other.pub_witness) } } -impl PartialOrd for WitnessBundle { +impl PartialOrd for WitnessBundle { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl WitnessBundle { +impl WitnessBundle +where DbcProof: From +{ #[inline] - pub fn with(pub_witness: PubWitness, anchored_bundle: ClientBundle) -> Self { + pub fn with(pub_witness: PubWitness, anchor: Anchor, bundle: TransitionBundle) -> Self { Self { pub_witness, - anchored_bundle: AnchoredBundle::from(anchored_bundle), - } - } - - pub fn witness_id(&self) -> Txid { self.pub_witness.to_witness_id() } - - pub fn reveal_seal(&mut self, bundle_id: BundleId, seal: GraphSeal) -> bool { - let bundle = match &mut self.anchored_bundle { - AnchoredBundle::Tapret(tapret) if tapret.bundle.bundle_id() == bundle_id => { - Some(&mut tapret.bundle) - } - AnchoredBundle::Opret(opret) if opret.bundle.bundle_id() == bundle_id => { - Some(&mut opret.bundle) - } - _ => None, - }; - let Some(bundle) = bundle else { - return false; - }; - bundle - .known_transitions - .values_mut() - .flat_map(|t| t.assignments.values_mut()) - .for_each(|a| a.reveal_seal(seal)); - - true - } - - pub fn anchored_bundle(&self) -> &AnchoredBundle { &self.anchored_bundle } - - pub fn bundle(&self) -> &TransitionBundle { self.anchored_bundle.bundle() } - - #[inline] - pub fn known_transitions(&self) -> impl Iterator { - self.anchored_bundle.bundle().known_transitions.values() - } -} - -/// Keeps client-side data - a combination of client-side witness (anchor) and state (transition -/// bundle). Ensures that transition bundle uses the same DBC close method as used by the -/// client-side witness (anchor). -#[derive(Clone, PartialEq, Eq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ClientBundle { - mpc_proof: mpc::MerkleProof, - dbc_proof: D, - bundle: TransitionBundle, -} - -impl ClientBundle { - /// # Panics - /// - /// Panics if DBC proof and bundle have different closing methods - pub fn new(mpc_proof: mpc::MerkleProof, dbc_proof: D, bundle: TransitionBundle) -> Self { - Self { - mpc_proof, - dbc_proof, + anchor, bundle, } } - #[inline] - pub fn bundle_id(&self) -> BundleId { self.bundle.bundle_id() } - - pub fn reveal_transition( - &mut self, - transition: Transition, - ) -> Result { - let opid = transition.id(); - if self.bundle.input_map.values().all(|id| *id != opid) { - return Err(UnrelatedTransition(opid, transition)); - } - if self.bundle.known_transitions.contains_key(&opid) { - return Ok(false); - } - self.bundle - .known_transitions - .insert(opid, transition) - .expect("same size as input map"); - Ok(true) - } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum AnchoredBundle { - #[strict_type(tag = 0x01)] - Tapret(ClientBundle), - #[strict_type(tag = 0x02)] - Opret(ClientBundle), -} - -impl StrictDumb for AnchoredBundle { - fn strict_dumb() -> Self { Self::Opret(strict_dumb!()) } -} - -impl From for AnchoredBundle { - fn from(ab: ClientBundle) -> Self { - match ab.dbc_proof { - DbcProof::Opret(proof) => { - Self::Opret(ClientBundle::::new(ab.mpc_proof, proof, ab.bundle)) - } - DbcProof::Tapret(proof) => { - Self::Tapret(ClientBundle::::new(ab.mpc_proof, proof, ab.bundle)) - } - } - } -} + pub fn witness_id(&self) -> Txid { self.pub_witness.to_witness_id() } -impl AnchoredBundle { - pub fn bundle(&self) -> &TransitionBundle { - match self { - AnchoredBundle::Tapret(tapret) => &tapret.bundle, - AnchoredBundle::Opret(opret) => &opret.bundle, - } - } + pub fn bundle(&self) -> &TransitionBundle { &self.bundle } - pub fn into_bundle(self) -> TransitionBundle { - match self { - AnchoredBundle::Tapret(tapret) => tapret.bundle, - AnchoredBundle::Opret(opret) => opret.bundle, - } - } + pub fn bundle_mut(&mut self) -> &mut TransitionBundle { &mut self.bundle } pub fn eanchor(&self) -> EAnchor { - match self { - AnchoredBundle::Tapret(tapret) => { - EAnchor::new(tapret.mpc_proof.clone(), tapret.dbc_proof.clone().into()) - } - AnchoredBundle::Opret(opret) => { - EAnchor::new(opret.mpc_proof.clone(), opret.dbc_proof.into()) - } - } - } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum AnchorSet { - #[strict_type(tag = 0x01)] - Tapret(Anchor), - #[strict_type(tag = 0x02)] - Opret(Anchor), -} - -impl StrictDumb for AnchorSet { - fn strict_dumb() -> Self { Self::Opret(strict_dumb!()) } -} - -impl AnchorSet { - pub fn known_bundle_ids(&self) -> impl Iterator { - let map = match self { - AnchorSet::Tapret(tapret) => tapret.mpc_proof.to_known_message_map().release(), - AnchorSet::Opret(opret) => opret.mpc_proof.to_known_message_map().release(), - }; - map.into_values() - .map(|msg| BundleId::from_byte_array(msg.to_byte_array())) - } - - pub fn merge_reveal(self, other: Self) -> Result { - match (self, other) { - (Self::Tapret(anchor), Self::Tapret(a)) => Ok(Self::Tapret(anchor.merge_reveal(a)?)), - (Self::Opret(anchor), Self::Opret(a)) => Ok(Self::Opret(anchor.merge_reveal(a)?)), - _ => Err(anchor::MergeError::DbcMismatch), - } + EAnchor::new(self.anchor.mpc_proof.clone(), self.anchor.dbc_proof.clone().into()) } } diff --git a/src/containers/consignment.rs b/src/containers/consignment.rs index f8a7b629..e3e7cd2c 100644 --- a/src/containers/consignment.rs +++ b/src/containers/consignment.rs @@ -22,32 +22,29 @@ use std::collections::BTreeSet; use std::fmt; use std::fmt::{Display, Formatter}; +use std::num::NonZeroU32; use std::ops::Deref; use std::str::FromStr; use aluvm::library::Lib; -use amplify::confinement::{ - Confined, LargeOrdSet, MediumBlob, SmallOrdMap, SmallOrdSet, TinyOrdMap, TinyOrdSet, -}; +use amplify::confinement::{Confined, LargeOrdSet, SmallOrdMap, SmallOrdSet}; use amplify::{ByteArray, Bytes32}; use armor::{ArmorHeader, AsciiArmor, StrictArmor, StrictArmorError}; use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; use commit_verify::{CommitEncode, CommitEngine, CommitId, CommitmentId, DigestExt, Sha256}; -use rgb::validation::{ResolveWitness, Validator, Validity, Warning, CONSIGNMENT_MAX_LIBS}; +use rgb::validation::{Failure, ResolveWitness, Validator, Validity, CONSIGNMENT_MAX_LIBS}; use rgb::{ - impl_serde_baid64, validation, AttachId, BundleId, ChainNet, ContractId, Extension, Genesis, - GraphSeal, Operation, Schema, SchemaId, + impl_serde_baid64, validation, BundleId, ChainNet, ContractId, Genesis, GraphSeal, OpId, + Operation, Schema, SchemaId, Txid, }; use rgbcore::validation::ConsignmentApi; use strict_encoding::{StrictDeserialize, StrictDumb, StrictSerialize}; use strict_types::TypeSystem; use super::{ - ContainerVer, ContentId, ContentSigs, IndexedConsignment, Supplement, WitnessBundle, - ASCII_ARMOR_CONSIGNMENT_TYPE, ASCII_ARMOR_CONTRACT, ASCII_ARMOR_IFACE, ASCII_ARMOR_SCHEMA, - ASCII_ARMOR_TERMINAL, ASCII_ARMOR_VERSION, + ContainerVer, IndexedConsignment, WitnessBundle, ASCII_ARMOR_CONSIGNMENT_TYPE, + ASCII_ARMOR_CONTRACT, ASCII_ARMOR_SCHEMA, ASCII_ARMOR_TERMINAL, ASCII_ARMOR_VERSION, }; -use crate::interface::{Iface, IfaceImpl}; use crate::persistence::{MemContract, MemContractState}; use crate::{SecretSeal, LIB_NAME_RGB_STD}; @@ -59,7 +56,6 @@ pub trait ConsignmentExt { fn schema_id(&self) -> SchemaId; fn schema(&self) -> &Schema; fn genesis(&self) -> &Genesis; - fn extensions(&self) -> impl Iterator; fn bundled_witnesses(&self) -> impl Iterator; } @@ -76,18 +72,13 @@ impl ConsignmentExt for &C { #[inline] fn genesis(&self) -> &Genesis { (*self).genesis() } - #[inline] - fn extensions(&self) -> impl Iterator { (*self).extensions() } - #[inline] fn bundled_witnesses(&self) -> impl Iterator { (*self).bundled_witnesses() } } -/// Interface identifier. -/// -/// Interface identifier commits to all the interface data. +/// Consignment identifier. #[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] @@ -143,6 +134,8 @@ pub struct ValidConsignment { impl ValidConsignment { pub fn validation_status(&self) -> &validation::Status { &self.validation_status } + pub fn validated_opids(&self) -> &BTreeSet { &self.validation_status.validated_opids } + pub fn into_consignment(self) -> Consignment { self.consignment } pub fn into_validation_status(self) -> validation::Status { self.validation_status } @@ -190,9 +183,6 @@ pub struct Consignment { /// Genesis data. pub genesis: Genesis, - /// All state extensions contained in the consignment. - pub extensions: LargeOrdSet, - /// All bundled state transitions contained in the consignment, together /// with their witness data. pub bundles: LargeOrdSet, @@ -200,27 +190,11 @@ pub struct Consignment { /// Schema (plus root schema, if any) under which contract is issued. pub schema: Schema, - /// Interfaces supported by the contract. - pub ifaces: TinyOrdMap, - - /// Known supplements. - pub supplements: TinyOrdSet, - - /// Type system covering all types used in schema, interfaces and - /// implementations. + /// Type system covering all types used in schema. pub types: TypeSystem, /// Collection of scripts used across consignment. pub scripts: Confined, 0, CONSIGNMENT_MAX_LIBS>, - - /// Data containers coming with this consignment. For the purposes of - /// in-memory consignments we are restricting the size of the containers to - /// 24 bit value (RGB allows containers up to 32-bit values in size). - pub attachments: SmallOrdMap, - - /// Signatures on the pieces of content which are the part of the - /// consignment. - pub signatures: TinyOrdMap, } impl StrictSerialize for Consignment {} @@ -235,27 +209,14 @@ impl CommitEncode for Consignment { e.commit_to_serialized(&self.contract_id()); e.commit_to_serialized(&self.genesis.disclose_hash()); - e.commit_to_set(&TinyOrdSet::from_iter_checked( - self.ifaces.values().map(|iimpl| iimpl.impl_id()), - )); e.commit_to_set(&LargeOrdSet::from_iter_checked( self.bundles.iter().map(WitnessBundle::commit_id), )); - e.commit_to_set(&LargeOrdSet::from_iter_checked( - self.extensions.iter().map(Extension::disclose_hash), - )); e.commit_to_map(&self.terminals); - e.commit_to_set(&SmallOrdSet::from_iter_checked(self.attachments.keys().copied())); - e.commit_to_set(&TinyOrdSet::from_iter_checked( - self.supplements.iter().map(|suppl| suppl.suppl_id()), - )); - e.commit_to_serialized(&self.types.id()); e.commit_to_set(&SmallOrdSet::from_iter_checked(self.scripts.iter().map(|lib| lib.id()))); - - e.commit_to_map(&self.signatures); } } @@ -272,9 +233,6 @@ impl ConsignmentExt for Consignment { #[inline] fn genesis(&self) -> &Genesis { &self.genesis } - #[inline] - fn extensions(&self) -> impl Iterator { self.extensions.iter() } - #[inline] fn bundled_witnesses(&self) -> impl Iterator { self.bundles.iter() } } @@ -295,7 +253,7 @@ impl Consignment { for mut witness_bundle in self.bundles { for (bundle_id, secret) in &self.terminals { if let Some(seal) = f(*secret)? { - witness_bundle.reveal_seal(*bundle_id, seal); + witness_bundle.bundle.reveal_seal(*bundle_id, seal); } } bundles.push(witness_bundle).ok(); @@ -309,25 +267,40 @@ impl Consignment { version: self.version, transfer: false, schema: self.schema, - ifaces: self.ifaces, - supplements: self.supplements, types: self.types, genesis: self.genesis, terminals: self.terminals, bundles: self.bundles, - extensions: self.extensions, - attachments: self.attachments, - signatures: self.signatures, scripts: self.scripts, } } + pub fn replace_transitions_input_ops(&self) -> BTreeSet { + self.bundles + .iter() + .flat_map(|b| b.bundle().known_transitions.values()) + .filter(|t| t.transition_type.is_replace()) + .flat_map(|t| t.inputs.iter()) + .filter(|i| i.ty.is_asset()) + .map(|i| i.op) + .collect::>() + } + pub fn validate( self, resolver: &impl ResolveWitness, - // TODO: Add sig validator - //_: &impl SigValidator, chain_net: ChainNet, + safe_height: Option, + ) -> Result, (validation::Status, Consignment)> { + self.validate_with_opids(resolver, chain_net, safe_height, bset![]) + } + + pub fn validate_with_opids( + self, + resolver: &impl ResolveWitness, + chain_net: ChainNet, + safe_height: Option, + trusted_op_seals: BTreeSet, ) -> Result, (validation::Status, Consignment)> { let index = IndexedConsignment::new(&self); let mut status = Validator::, _, _>::validate( @@ -335,39 +308,26 @@ impl Consignment { &resolver, chain_net, (&self.schema, self.contract_id()), + safe_height, + trusted_op_seals, ); let validity = status.validity(); if self.transfer != TRANSFER { - status.add_warning(Warning::Custom(s!("invalid consignment type"))); - } - // check ifaceid match implementation - for (iface, iimpl) in self.ifaces.iter() { - if iface.iface_id() != iimpl.iface_id { - status.add_warning(Warning::Custom(format!( - "implementation {} targets different interface {} than expected {}", - iimpl.impl_id(), - iimpl.iface_id, - iface.iface_id() - ))); - } + status.add_failure(Failure::Custom(s!("invalid consignment type"))); } // check bundle ids listed in terminals are present in the consignment for bundle_id in self.terminals.keys() { if !index.bundle_ids().any(|id| id == *bundle_id) { - status.add_warning(Warning::Custom(format!( + status.add_failure(Failure::Custom(format!( "terminal bundle id {bundle_id} is not present in the consignment" ))); } } - // TODO: check attach ids from data containers are present in operations - // TODO: validate sigs and remove untrusted - // TODO: Check that all extensions present in the consignment are used by state - // transitions - if validity != Validity::Valid { + if validity == Validity::Invalid { Err((status, self)) } else { Ok(ValidConsignment { @@ -376,6 +336,32 @@ impl Consignment { }) } } + + /// Modify a bundle in the consignment if it exists + pub fn modify_bundle(&mut self, witness_id: Txid, modifier: F) -> bool + where F: Fn(&mut WitnessBundle) { + let mut found = false; + let mut modified_bundles = BTreeSet::new(); + + let bundles: Vec<_> = self.bundles.iter().cloned().collect(); + + for bundle in bundles { + if bundle.witness_id() == witness_id { + let mut modified_bundle = bundle.clone(); + modifier(&mut modified_bundle); + modified_bundles.insert(modified_bundle); + found = true; + } else { + modified_bundles.insert(bundle); + } + } + + if found { + self.bundles = Confined::try_from_iter(modified_bundles).unwrap(); + } + + found + } } impl StrictArmor for Consignment { @@ -393,12 +379,6 @@ impl StrictArmor for Consignment { ArmorHeader::new(ASCII_ARMOR_CONTRACT, self.contract_id().to_string()), ArmorHeader::new(ASCII_ARMOR_SCHEMA, self.schema.schema_id().to_string()), ]; - if !self.ifaces.is_empty() { - headers.push(ArmorHeader::with( - ASCII_ARMOR_IFACE, - self.ifaces.keys().map(|iface| iface.name.to_string()), - )); - } if !self.terminals.is_empty() { headers.push(ArmorHeader::with( ASCII_ARMOR_TERMINAL, @@ -408,7 +388,7 @@ impl StrictArmor for Consignment { headers } fn parse_armor_headers(&mut self, headers: Vec) -> Result<(), StrictArmorError> { - // TODO: Check remaining headers - terminals, version, iface, contract, schema + // TODO: Check remaining headers - terminals, version, contract, schema if let Some(header) = headers .iter() .find(|header| header.title == ASCII_ARMOR_CONSIGNMENT_TYPE) diff --git a/src/containers/file.rs b/src/containers/file.rs index 925379ac..c1a9b4be 100644 --- a/src/containers/file.rs +++ b/src/containers/file.rs @@ -113,9 +113,6 @@ impl FileContent for Transfer { const MAGIC: [u8; MAGIC_LEN] = *b"TFR"; } -// TODO: Add disclosure -// TODO: Add batch and fascia - #[derive(Clone, Debug, From)] #[cfg_attr( feature = "serde", @@ -131,8 +128,6 @@ pub enum UniversalFile { #[from] Transfer(Transfer), - // TODO: Add disclosure - // TODO: Add batch and fascia } impl UniversalFile { @@ -268,39 +263,27 @@ mod test { "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#distant-history-exotic", ) .unwrap(), - flags: Default::default(), timestamp: Default::default(), issuer: Default::default(), chain_net: Default::default(), + seal_closing_strategy: Default::default(), metadata: Default::default(), globals: Default::default(), assignments: Default::default(), - valencies: Default::default(), - validator: Default::default(), }, - extensions: Default::default(), bundles: Default::default(), schema: rgb::Schema { ffv: Default::default(), - flags: Default::default(), name: strict_encoding::TypeName::from_str("Name").unwrap(), - timestamp: Default::default(), - developer: Default::default(), meta_types: Default::default(), global_types: Default::default(), owned_types: Default::default(), - valency_types: Default::default(), genesis: Default::default(), - extensions: Default::default(), transitions: Default::default(), - reserved: Default::default(), + default_assignment: Default::default(), }, - ifaces: Default::default(), - supplements: Default::default(), types: Default::default(), scripts: Default::default(), - attachments: Default::default(), - signatures: Default::default(), } } @@ -364,39 +347,27 @@ mod test { "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#distant-history-exotic", ) .unwrap(), - flags: Default::default(), timestamp: Default::default(), issuer: Default::default(), chain_net: Default::default(), + seal_closing_strategy: Default::default(), metadata: Default::default(), globals: Default::default(), assignments: Default::default(), - valencies: Default::default(), - validator: Default::default(), }, - extensions: Default::default(), bundles: Default::default(), schema: rgb::Schema { ffv: Default::default(), - flags: Default::default(), name: strict_encoding::TypeName::from_str("Name").unwrap(), - timestamp: Default::default(), - developer: Default::default(), meta_types: Default::default(), global_types: Default::default(), owned_types: Default::default(), - valency_types: Default::default(), genesis: Default::default(), - extensions: Default::default(), transitions: Default::default(), - reserved: Default::default(), + default_assignment: Default::default(), }, - ifaces: Default::default(), - supplements: Default::default(), types: Default::default(), scripts: Default::default(), - attachments: Default::default(), - signatures: Default::default(), } } diff --git a/src/containers/indexed.rs b/src/containers/indexed.rs index bc41181b..4e6db785 100644 --- a/src/containers/indexed.rs +++ b/src/containers/indexed.rs @@ -23,9 +23,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::ops::Deref; use rgb::validation::{ConsignmentApi, EAnchor, OpRef, Scripts}; -use rgb::{ - BundleId, Extension, Genesis, OpId, Operation, Schema, Transition, TransitionBundle, Txid, -}; +use rgb::{BundleId, Genesis, OpId, Operation, Schema, Transition, TransitionBundle, Txid}; use strict_types::TypeSystem; use super::{Consignment, PubWitness}; @@ -40,7 +38,6 @@ pub struct IndexedConsignment<'c, const TRANSFER: bool> { bundle_idx: BTreeMap, op_witness_idx: BTreeMap, op_bundle_idx: BTreeMap, - extension_idx: BTreeMap, witness_idx: BTreeMap, } @@ -56,15 +53,13 @@ impl<'c, const TRANSFER: bool> IndexedConsignment<'c, TRANSFER> { let mut bundle_idx = BTreeMap::new(); let mut op_witness_idx = BTreeMap::new(); let mut op_bundle_idx = BTreeMap::new(); - let mut extension_idx = BTreeMap::new(); let mut witness_idx = BTreeMap::new(); for witness_bundle in &consignment.bundles { witness_idx .insert(witness_bundle.pub_witness.to_witness_id(), &witness_bundle.pub_witness); let witness_id = witness_bundle.pub_witness.to_witness_id(); - let anchored_bundle = witness_bundle.anchored_bundle(); - let anchor = anchored_bundle.eanchor(); - let bundle = anchored_bundle.bundle(); + let anchor = witness_bundle.eanchor(); + let bundle = witness_bundle.bundle(); let bundle_id = bundle.bundle_id(); bundle_idx.insert(bundle_id, bundle); anchor_idx.insert(bundle_id, (witness_id, anchor)); @@ -73,9 +68,6 @@ impl<'c, const TRANSFER: bool> IndexedConsignment<'c, TRANSFER> { op_bundle_idx.insert(*opid, bundle_id); } } - for extension in &consignment.extensions { - extension_idx.insert(extension.id(), extension); - } let scripts = Scripts::from_iter_checked( consignment .scripts @@ -89,13 +81,10 @@ impl<'c, const TRANSFER: bool> IndexedConsignment<'c, TRANSFER> { bundle_idx, op_witness_idx, op_bundle_idx, - extension_idx, witness_idx, } } - fn extension(&self, opid: OpId) -> Option<&Extension> { self.extension_idx.get(&opid).copied() } - fn transition(&self, opid: OpId) -> Option<&Transition> { self.op_bundle_idx .get(&opid) @@ -119,9 +108,7 @@ impl ConsignmentApi for IndexedConsignment<'_, TRANSFER> { if opid == self.genesis.id() { return Some(OpRef::Genesis(&self.genesis)); } - self.transition(opid) - .map(OpRef::Transition) - .or_else(|| self.extension(opid).map(OpRef::Extension)) + self.transition(opid).map(OpRef::Transition) } fn genesis(&self) -> &Genesis { &self.genesis } diff --git a/src/containers/kit.rs b/src/containers/kit.rs index 4316f83c..978a3fee 100644 --- a/src/containers/kit.rs +++ b/src/containers/kit.rs @@ -25,7 +25,7 @@ use std::ops::Deref; use std::str::FromStr; use aluvm::library::Lib; -use amplify::confinement::{SmallOrdSet, TinyOrdMap, TinyOrdSet}; +use amplify::confinement::{SmallOrdSet, TinyOrdSet}; use amplify::{ByteArray, Bytes32}; use armor::{ArmorHeader, AsciiArmor, StrictArmor}; use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; @@ -34,12 +34,8 @@ use rgb::{validation, Schema}; use strict_encoding::{StrictDeserialize, StrictSerialize}; use strict_types::TypeSystem; -use super::{ - ContentRef, Supplement, ASCII_ARMOR_IFACE, ASCII_ARMOR_IIMPL, ASCII_ARMOR_SCHEMA, - ASCII_ARMOR_SCRIPT, ASCII_ARMOR_TYPE_SYSTEM, ASCII_ARMOR_VERSION, -}; -use crate::containers::{ContainerVer, ContentId, ContentSigs}; -use crate::interface::{Iface, IfaceImpl}; +use super::{ASCII_ARMOR_SCHEMA, ASCII_ARMOR_SCRIPT, ASCII_ARMOR_TYPE_SYSTEM, ASCII_ARMOR_VERSION}; +use crate::containers::ContainerVer; use crate::LIB_NAME_RGB_STD; /// Kit identifier. @@ -123,23 +119,13 @@ pub struct Kit { /// Version. pub version: ContainerVer, - pub ifaces: TinyOrdSet, - pub schemata: TinyOrdSet, - pub iimpls: TinyOrdSet, - - pub supplements: TinyOrdSet, - - /// Type system covering all types used in schema, interfaces and - /// implementations. + /// Type system covering all types used in schema. pub types: TypeSystem, /// Collection of scripts used across kit data. pub scripts: SmallOrdSet, - - /// Signatures on the pieces of content which are the part of the kit. - pub signatures: TinyOrdMap, } impl StrictSerialize for Kit {} @@ -151,23 +137,12 @@ impl CommitEncode for Kit { fn commit_encode(&self, e: &mut CommitEngine) { e.commit_to_serialized(&self.version); - e.commit_to_set(&TinyOrdSet::from_iter_checked( - self.ifaces.iter().map(|iface| iface.iface_id()), - )); e.commit_to_set(&TinyOrdSet::from_iter_checked( self.schemata.iter().map(|schema| schema.schema_id()), )); - e.commit_to_set(&TinyOrdSet::from_iter_checked( - self.iimpls.iter().map(|iimpl| iimpl.impl_id()), - )); - e.commit_to_set(&TinyOrdSet::from_iter_checked( - self.supplements.iter().map(|suppl| suppl.suppl_id()), - )); e.commit_to_serialized(&self.types.id()); e.commit_to_set(&SmallOrdSet::from_iter_checked(self.scripts.iter().map(|lib| lib.id()))); - - e.commit_to_map(&self.signatures); } } @@ -175,17 +150,8 @@ impl Kit { #[inline] pub fn kit_id(&self) -> KitId { self.commit_id() } - pub fn validate( - self, - // TODO: Add sig validator - //_: &impl SigValidator, - ) -> Result { + pub fn validate(self) -> Result { let status = validation::Status::new(); - // TODO: - // - Verify integrity for each interface - // - Verify implementations against interfaces - // - Check schema integrity - // - Validate content sigs and remove untrusted ones Ok(ValidKit { validation_status: status, kit: self, @@ -205,55 +171,6 @@ impl StrictArmor for Kit { let mut header = ArmorHeader::new(ASCII_ARMOR_SCHEMA, schema.name.to_string()); let id = schema.schema_id(); header.params.push((s!("id"), format!("{id:-}"))); - header - .params - .push((s!("dev"), schema.developer.to_string())); - if let Some(suppl) = self - .supplements - .iter() - .find(|s| s.content_id == ContentRef::Schema(id)) - { - header - .params - .push((s!("suppl"), format!("{:-}", suppl.suppl_id()))); - } - headers.push(header); - } - for iface in &self.ifaces { - let mut header = ArmorHeader::new(ASCII_ARMOR_IFACE, iface.name.to_string()); - let id = iface.iface_id(); - header.params.push((s!("id"), format!("{id:-}"))); - header.params.push((s!("dev"), iface.developer.to_string())); - if let Some(suppl) = self - .supplements - .iter() - .find(|s| s.content_id == ContentRef::Iface(id)) - { - header - .params - .push((s!("suppl"), format!("{:-}", suppl.suppl_id()))); - } - headers.push(header); - } - for iimpl in &self.iimpls { - let id = iimpl.impl_id(); - let mut header = ArmorHeader::new(ASCII_ARMOR_IIMPL, format!("{id:-}")); - header - .params - .push((s!("interface"), format!("{:-}", iimpl.iface_id))); - header - .params - .push((s!("schema"), format!("{:-}", iimpl.schema_id))); - header.params.push((s!("dev"), iimpl.developer.to_string())); - if let Some(suppl) = self - .supplements - .iter() - .find(|s| s.content_id == ContentRef::IfaceImpl(id)) - { - header - .params - .push((s!("suppl"), format!("{:-}", suppl.suppl_id()))); - } headers.push(header); } headers.push(ArmorHeader::new(ASCII_ARMOR_TYPE_SYSTEM, self.types.id().to_string())); @@ -291,12 +208,12 @@ mod test { fn error_kit_strs() { assert!(Kit::from_str( r#"-----BEGIN RGB KIT----- -Id: rgb:kit:e1jW6Rgc-2$JzXDg-XmR8XRJ-v!q$Dzf-yImkPjD-t8EjfvI -Version: 2 -Type-System: sts:8Vb$sM1F-5MsQc20-HEixf55-gJR37FM-0zRKfpY-SwIp35w#design-farmer-camel -Check-SHA256: 5563cc1568e244183804e0db3cec6ff9bf577f4a403924096177bf4a586160da +Id: rgb:kit:jXOeJYkD-NlOgJoP-_zT1Hvl-0fP71Zo-b2mAh2C-i5ISROo +Version: 0 +Type-System: sts:8Vb~sM1F-5MsQc20-HEixf55-gJR37FM-0zRKfpY-SwIp35w#design-farmer-camel +Check-SHA256: 837885c8f8091aeaeb9ec3c3f85a6ff470a415e610b8ba3e49f9b33c9cf9d619 -0ssI2000000000 +000000000 -----END RGB KIT-----"# ) @@ -306,11 +223,11 @@ Check-SHA256: 5563cc1568e244183804e0db3cec6ff9bf577f4a403924096177bf4a586160da assert!(Kit::from_str( r#"-----BEGIN RGB KIT----- Id: rgb:kit:11111111-2222222-XmR8XRJ-v!q$Dzf-yImkPjD-t8EjfvI -Version: 2 -Type-System: sts:8Vb$sM1F-5MsQc20-HEixf55-gJR37FM-0zRKfpY-SwIp35w#design-farmer-camel -Check-SHA256: 5563cc1568e244183804e0db3cec6ff9bf577f4a403924096177bf4a586160da +Version: 0 +Type-System: sts:8Vb~sM1F-5MsQc20-HEixf55-gJR37FM-0zRKfpY-SwIp35w#design-farmer-camel +Check-SHA256: 837885c8f8091aeaeb9ec3c3f85a6ff470a415e610b8ba3e49f9b33c9cf9d619 -0ssI2000000000 +000000000 -----END RGB KIT-----"# ) @@ -319,12 +236,12 @@ Check-SHA256: 5563cc1568e244183804e0db3cec6ff9bf577f4a403924096177bf4a586160da // wrong checksum assert!(Kit::from_str( r#"-----BEGIN RGB KIT----- -Id: rgb:kit:e1jW6Rgc-2$JzXDg-XmR8XRJ-v!q$Dzf-yImkPjD-t8EjfvI -Version: 2 -Type-System: sts:8Vb$sM1F-5MsQc20-HEixf55-gJR37FM-0zRKfpY-SwIp35w#design-farmer-camel +Id: rgb:kit:jXOeJYkD-NlOgJoP-_zT1Hvl-0fP71Zo-b2mAh2C-i5ISROo +Version: 0 +Type-System: sts:8Vb~sM1F-5MsQc20-HEixf55-gJR37FM-0zRKfpY-SwIp35w#design-farmer-camel Check-SHA256: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -0ssI2000000000 +000000000 -----END RGB KIT-----"# ) diff --git a/src/containers/mod.rs b/src/containers/mod.rs index edb19938..c42cdcd0 100644 --- a/src/containers/mod.rs +++ b/src/containers/mod.rs @@ -19,56 +19,36 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! RGB containers are data packages which can be transferred between smart -//! contract users. There are two main types of containers: -//! 1. [`Consignment`]s, containing information about partial state of a *single contract*, -//! extending from its genesis up to certain contract endpoints. -//! 2. [`Disclosure`]s, containing extracts from (possibly) independent state transitions and -//! extensions under multiple contracts. Useful fro disclosing the concealed state for some other -//! parties, and also for performing "change" operations on inventory during state transfers. +//! RGB containers are data packages which can be transferred between smart contract users. +//! The main type of container is the [`Consignment`], containing information about partial state +//! of a *single contract*, extending from its genesis up to certain contract endpoints. mod seal; mod anchors; mod consignment; -mod disclosure; mod util; mod partials; mod indexed; mod file; mod kit; -mod suppl; -pub use anchors::{ - AnchorSet, AnchoredBundle, AnchoredBundleMismatch, ClientBundle, PubWitness, SealWitness, - ToWitnessId, UnrelatedTransition, WitnessBundle, -}; +pub use anchors::{PubWitness, SealWitness, SealWitnessMergeError, ToWitnessId, WitnessBundle}; pub use consignment::{ Consignment, ConsignmentExt, ConsignmentId, ConsignmentParseError, Contract, Transfer, ValidConsignment, ValidContract, ValidTransfer, }; -pub use disclosure::Disclosure; pub use file::{FileContent, LoadError, UniversalFile}; pub use indexed::IndexedConsignment; pub use kit::{Kit, KitId, ValidKit}; pub use partials::{Batch, Fascia, TransitionInfo, TransitionInfoError}; pub use seal::{BuilderSeal, VoutSeal}; -pub use suppl::{ - AnnotationName, Annotations, ContentRef, SupplId, SupplItem, SupplMap, SupplSub, Supplement, - TickerSuppl, VelocityHint, SUPPL_ANNOT_IFACE_CLASS, SUPPL_ANNOT_IFACE_FEATURES, - SUPPL_ANNOT_VELOCITY, -}; -pub use util::{ - ContainerVer, ContentId, ContentSigs, DumbValidator, SigBlob, SigValidator, TrustLevel, -}; +pub use util::ContainerVer; pub const ASCII_ARMOR_NAME: &str = "Name"; -pub const ASCII_ARMOR_IFACE: &str = "Interface"; -pub const ASCII_ARMOR_IIMPL: &str = "Implementation"; pub const ASCII_ARMOR_SCHEMA: &str = "Schema"; pub const ASCII_ARMOR_CONTRACT: &str = "Contract"; pub const ASCII_ARMOR_VERSION: &str = "Version"; pub const ASCII_ARMOR_TERMINAL: &str = "Terminal"; -pub const ASCII_ARMOR_SUPPL: &str = "Supplement"; pub const ASCII_ARMOR_SCRIPT: &str = "Alu-Lib"; pub const ASCII_ARMOR_TYPE_SYSTEM: &str = "Type-System"; pub const ASCII_ARMOR_CONSIGNMENT_TYPE: &str = "Type"; diff --git a/src/containers/partials.rs b/src/containers/partials.rs index eb1b7261..c5a22ff8 100644 --- a/src/containers/partials.rs +++ b/src/containers/partials.rs @@ -30,7 +30,7 @@ use strict_encoding::{ StrictDecode, StrictDeserialize, StrictDumb, StrictEncode, StrictSerialize, StrictType, }; -use crate::containers::{AnchorSet, PubWitness}; +use super::SealWitness; use crate::LIB_NAME_RGB_STD; #[derive(Clone, Eq, Debug)] @@ -111,7 +111,7 @@ pub enum TransitionInfoError { )] pub struct Batch { pub main: TransitionInfo, - pub blanks: Confined, 0, { U24 - 1 }>, + pub extras: Confined, 0, { U24 - 1 }>, } impl StrictSerialize for Batch {} @@ -122,7 +122,7 @@ impl IntoIterator for Batch { type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { - let mut vec = self.blanks.release(); + let mut vec = self.extras.release(); vec.push(self.main); vec.into_iter() } @@ -131,7 +131,7 @@ impl IntoIterator for Batch { impl Batch { pub fn set_priority(&mut self, priority: u64) { self.main.transition.nonce = priority; - for info in &mut self.blanks { + for info in &mut self.extras { info.transition.nonce = priority; } } @@ -149,16 +149,14 @@ impl Batch { serde(crate = "serde_crate", rename_all = "camelCase") )] pub struct Fascia { - pub witness: PubWitness, - pub anchor: AnchorSet, + pub seal_witness: SealWitness, pub bundles: NonEmptyOrdMap, } impl StrictDumb for Fascia { fn strict_dumb() -> Self { Fascia { - witness: strict_dumb!(), - anchor: strict_dumb!(), + seal_witness: strict_dumb!(), bundles: NonEmptyOrdMap::with_key_value(strict_dumb!(), strict_dumb!()), } } @@ -167,7 +165,7 @@ impl StrictSerialize for Fascia {} impl StrictDeserialize for Fascia {} impl Fascia { - pub fn witness_id(&self) -> Txid { self.witness.txid() } + pub fn witness_id(&self) -> Txid { self.seal_witness.public.txid() } pub fn into_bundles(self) -> impl IntoIterator { self.bundles.into_iter() diff --git a/src/containers/suppl.rs b/src/containers/suppl.rs deleted file mode 100644 index 5da0ea8b..00000000 --- a/src/containers/suppl.rs +++ /dev/null @@ -1,355 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// 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. -// -// 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::confinement::{SmallBlob, TinyOrdMap}; -use amplify::{ByteArray, Bytes32}; -use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use chrono::Utc; -use commit_verify::{CommitId, CommitmentId, DigestExt, Sha256}; -use rgb::{AssignmentType, ContractId, GlobalStateType, Identity, SchemaId}; -use strict_encoding::stl::{AlphaCaps, AlphaNumDash}; -use strict_encoding::{ - DeserializeError, FieldName, RString, SerializeError, StrictDeserialize, StrictSerialize, - TypeName, VariantName, -}; -use strict_types::value; - -use crate::interface::{IfaceId, ImplId}; -use crate::LIB_NAME_RGB_STD; - -pub const SUPPL_ANNOT_VELOCITY: &str = "Velocity"; -pub const SUPPL_ANNOT_IFACE_CLASS: &str = "Standard"; -pub const SUPPL_ANNOT_IFACE_FEATURES: &str = "Features"; - -/// Contract supplement identifier. -/// -/// Contract supplement identifier commits to all of the supplement 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_STD)] -pub struct SupplId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl From for SupplId { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for SupplId { - const TAG: &'static str = "urn:lnp-bp:rgb:suppl#2024-03-11"; -} - -impl DisplayBaid64 for SupplId { - const HRI: &'static str = "rgb:sup"; - const CHUNKING: bool = false; - 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 SupplId {} -impl FromStr for SupplId { - type Err = Baid64ParseError; - fn from_str(s: &str) -> Result { Self::from_baid64_str(s) } -} -impl Display for SupplId { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) } -} - -impl_serde_baid64!(SupplId); - -impl SupplId { - pub const fn from_array(id: [u8; 32]) -> Self { Self(Bytes32::from_array(id)) } -} - -#[derive(Wrapper, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From, Display)] -#[wrapper(Deref, FromStr)] -#[display(inner)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct AnnotationName(RString); - -impl From<&'static str> for AnnotationName { - fn from(s: &'static str) -> Self { Self(RString::from(s)) } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, From)] -#[display(inner)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = order, dumb = ContentRef::Schema(strict_dumb!()))] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum ContentRef { - #[from] - Schema(SchemaId), - #[from] - Genesis(ContractId), - #[from] - Iface(IfaceId), - #[from] - IfaceImpl(ImplId), -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, 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 SupplSub { - #[default] - Itself = 0, - Meta = 1, - Global, - Owned, - Valency, - Assignment, - Genesis, - Transition, - Extension, - Exception, -} - -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum SupplItem { - #[default] - #[strict_type(tag = 0)] - Default, - #[strict_type(tag = 1)] - TypeNo(u16), - #[strict_type(tag = 0x11)] - TypeName(TypeName), - #[strict_type(tag = 0x12)] - FieldName(FieldName), - #[strict_type(tag = 0x13)] - VariantName(VariantName), -} - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct SupplMap(TinyOrdMap); - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct Annotations(TinyOrdMap); - -/// Contract supplement, providing non-consensus information about standard -/// way of working with the contract data. Each contract can have only a single -/// valid supplement; the supplement is attached to the contract via trusted -/// provider signature (providers are ordered by the priority). -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = SupplId)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Supplement { - pub content_id: ContentRef, - pub timestamp: i64, - pub creator: Identity, - /// Strict-encoded custom fields. - pub annotations: TinyOrdMap, -} - -impl StrictSerialize for Supplement {} -impl StrictDeserialize for Supplement {} - -impl Supplement { - pub fn suppl_id(&self) -> SupplId { self.commit_id() } - - pub fn new(content: impl Into, creator: impl Into) -> Self { - Supplement { - content_id: content.into(), - timestamp: Utc::now().timestamp(), - creator: creator.into(), - annotations: none!(), - } - } - - pub fn get_default_opt( - &self, - sub: SupplSub, - name: impl Into, - ) -> Option { - self.get_default(sub, name).transpose().ok().flatten() - } - - pub fn get_default( - &self, - sub: SupplSub, - name: impl Into, - ) -> Option> { - let annotation = self - .annotations - .get(&sub)? - .get(&SupplItem::Default)? - .get(&name.into())?; - Some(T::from_strict_serialized(annotation.clone())) - } - - pub fn get( - &self, - sub: SupplSub, - item: SupplItem, - name: impl Into, - ) -> Option> { - let annotation = self.annotations.get(&sub)?.get(&item)?.get(&name.into())?; - Some(T::from_strict_serialized(annotation.clone())) - } - - pub fn annotate_itself( - &mut self, - name: impl Into, - data: &impl StrictSerialize, - ) -> Result { - self.annotate_default(SupplSub::Itself, name, data) - } - - pub fn annotate_default( - &mut self, - sub: SupplSub, - name: impl Into, - data: &impl StrictSerialize, - ) -> Result { - self.annotate(sub, SupplItem::Default, name, data) - } - - pub fn annotate( - &mut self, - sub: SupplSub, - item: SupplItem, - name: impl Into, - data: &impl StrictSerialize, - ) -> Result { - let mut a = self - .annotations - .remove(&sub) - .expect("zero items allowed") - .unwrap_or_default(); - let mut b = a - .remove(&item) - .expect("zero items allowed") - .unwrap_or_default(); - let prev = b.insert(name.into(), data.to_strict_serialized()?)?; - a.insert(item, b)?; - self.annotations.insert(sub, a)?; - Ok(prev.is_some()) - } -} - -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = custom)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum TickerSuppl { - #[strict_type(tag = 0, dumb)] - Absent, - #[strict_type(tag = 1)] - Global(GlobalStateType, value::Path), - #[strict_type(tag = 2)] - Owned(AssignmentType, value::Path), -} - -impl StrictSerialize for TickerSuppl {} -impl StrictDeserialize for TickerSuppl {} - -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = repr, try_from_u8, into_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display(lowercase)] -#[repr(u8)] -pub enum VelocityHint { - #[default] - Unspecified = 0, - /// Should be used for thinks like secondary issuance for tokens which do - /// not inflate very often. - Seldom = 15, - /// Should be used for digital identity revocations. - Episodic = 31, - /// Should be used for digital art, shares, bonds etc. - Regular = 63, - /// Should be used for fungible tokens. - Frequent = 127, - /// Should be used for stablecoins and money. - HighFrequency = 255, -} - -impl StrictSerialize for VelocityHint {} -impl StrictDeserialize for VelocityHint {} - -impl VelocityHint { - pub fn with_value(value: &u8) -> Self { - match *value { - 0 => VelocityHint::Unspecified, - 1..=15 => VelocityHint::Seldom, - 16..=31 => VelocityHint::Episodic, - 32..=63 => VelocityHint::Regular, - 64..=127 => VelocityHint::Frequent, - 128..=255 => VelocityHint::HighFrequency, - } - } -} diff --git a/src/containers/util.rs b/src/containers/util.rs index 92b68043..edd020e8 100644 --- a/src/containers/util.rs +++ b/src/containers/util.rs @@ -19,15 +19,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::btree_map; - -use amplify::confinement::{NonEmptyBlob, NonEmptyOrdMap}; -use commit_verify::StrictHash; -use rgb::{ContractId, Identity, SchemaId}; -use strict_encoding::StrictDumb; - -use super::SupplId; -use crate::interface::{IfaceId, ImplId}; use crate::LIB_NAME_RGB_STD; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Default)] @@ -41,97 +32,7 @@ use crate::LIB_NAME_RGB_STD; #[non_exhaustive] #[repr(u8)] pub enum ContainerVer { - // V0 and V1 was a previous version before v0.11, currently not supported. #[default] - #[display("v2", alt = "2")] - V2 = 2, -} - -pub trait SigValidator { - fn validate_sig(&self, identity: &Identity, sig: SigBlob) -> bool; -} - -pub struct DumbValidator; -impl SigValidator for DumbValidator { - fn validate_sig(&self, _: &Identity, _: SigBlob) -> bool { false } -} - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Default)] -#[display(lowercase)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, 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 TrustLevel { - Malicious = 0x10, - #[default] - Unknown = 0x20, - Untrusted = 0x40, - Trusted = 0x80, - Ultimate = 0xC0, -} - -impl TrustLevel { - pub fn should_accept(self) -> bool { self >= Self::Unknown } - pub fn should_use(self) -> bool { self >= Self::Trusted } - pub fn must_use(self) -> bool { self >= Self::Ultimate } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = order, dumb = ContentId::Schema(strict_dumb!()))] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum ContentId { - Schema(SchemaId), - Genesis(ContractId), - Iface(IfaceId), - IfaceImpl(ImplId), - Suppl(SupplId), -} - -#[derive(Wrapper, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From, Display)] -#[wrapper(Deref, AsSlice, BorrowSlice, Hex)] -#[display(LowerHex)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = StrictHash)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct SigBlob(NonEmptyBlob<4096>); - -impl Default for SigBlob { - fn default() -> Self { SigBlob(NonEmptyBlob::with(0)) } -} - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, Hash, Debug, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct ContentSigs(NonEmptyOrdMap); - -impl StrictDumb for ContentSigs { - fn strict_dumb() -> Self { - Self(NonEmptyOrdMap::with_key_value(strict_dumb!(), SigBlob::default())) - } -} - -impl IntoIterator for ContentSigs { - type Item = (Identity, SigBlob); - type IntoIter = btree_map::IntoIter; - - fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } + #[display("v0", alt = "0")] + V0 = 0, } diff --git a/src/contract/assignments.rs b/src/contract/assignments.rs index b0577334..5c084ddf 100644 --- a/src/contract/assignments.rs +++ b/src/contract/assignments.rs @@ -24,13 +24,11 @@ use std::collections::{BTreeSet, HashMap}; use std::fmt::Debug; use std::hash::Hash; -use amplify::confinement::SmallVec; use invoice::Amount; use rgb::vm::WitnessOrd; use rgb::{ - Assign, AssignAttach, AssignData, AssignFungible, AssignRights, AssignmentType, AttachState, - BundleId, DataState, ExposedSeal, ExposedState, OpId, Opout, OutputSeal, RevealedAttach, - RevealedData, RevealedValue, Txid, TypedAssigns, VoidState, + AssignmentType, BundleId, ExposedSeal, OpId, Opout, OutputSeal, RevealedData, RevealedValue, + Txid, VoidState, }; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; @@ -49,24 +47,15 @@ impl KnownState for () { impl KnownState for VoidState { const IS_FUNGIBLE: bool = false; } -impl KnownState for DataState { - const IS_FUNGIBLE: bool = false; -} impl KnownState for Amount { const IS_FUNGIBLE: bool = true; } -impl KnownState for AttachState { - const IS_FUNGIBLE: bool = false; -} impl KnownState for RevealedValue { const IS_FUNGIBLE: bool = true; } impl KnownState for RevealedData { const IS_FUNGIBLE: bool = false; } -impl KnownState for RevealedAttach { - const IS_FUNGIBLE: bool = false; -} #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] @@ -168,7 +157,7 @@ impl OutputAssignment { opout: Opout::new(opid, ty, no), seal: seal.to_output_seal().expect( "processing contract from unverified/invalid stash: seal must have txid \ - information since it comes from genesis or extension", + information since it comes from genesis", ), state, bundle_id, @@ -203,55 +192,3 @@ impl OutputAssignment { } } } - -pub trait TypedAssignsExt { - fn reveal_seal(&mut self, seal: Seal); - - fn filter_revealed_seals(&self) -> Vec; -} - -impl TypedAssignsExt for TypedAssigns { - fn reveal_seal(&mut self, seal: Seal) { - fn reveal( - vec: &mut SmallVec>, - revealed: Seal, - ) { - for assign in vec.iter_mut() { - match assign { - Assign::ConfidentialSeal { seal, state, lock } - if *seal == revealed.conceal() => - { - *assign = Assign::Revealed { - seal: revealed, - state: state.clone(), - lock: *lock, - } - } - _ => {} - } - } - } - - match self { - TypedAssigns::Declarative(v) => reveal(v, seal), - TypedAssigns::Fungible(v) => reveal(v, seal), - TypedAssigns::Structured(v) => reveal(v, seal), - TypedAssigns::Attachment(v) => reveal(v, seal), - } - } - - fn filter_revealed_seals(&self) -> Vec { - match self { - TypedAssigns::Declarative(s) => { - s.iter().filter_map(AssignRights::revealed_seal).collect() - } - TypedAssigns::Fungible(s) => { - s.iter().filter_map(AssignFungible::revealed_seal).collect() - } - TypedAssigns::Structured(s) => s.iter().filter_map(AssignData::revealed_seal).collect(), - TypedAssigns::Attachment(s) => { - s.iter().filter_map(AssignAttach::revealed_seal).collect() - } - } - } -} diff --git a/src/contract/builder.rs b/src/contract/builder.rs new file mode 100644 index 00000000..e65c5372 --- /dev/null +++ b/src/contract/builder.rs @@ -0,0 +1,740 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// 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. +// +// 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::result_large_err)] + +use std::collections::{BTreeMap, HashSet}; + +use amplify::confinement::{Confined, NonEmptyOrdSet, TinyOrdMap, U16}; +use amplify::{confinement, Wrapper}; +use chrono::Utc; +use invoice::Amount; +use rgb::assignments::AssignVec; +use rgb::validation::Scripts; +use rgb::{ + validation, Assign, AssignmentType, Assignments, ChainNet, ContractId, ExposedSeal, + FungibleType, Genesis, GenesisSeal, GlobalState, GraphSeal, Identity, Layer1, MetadataError, + Opout, OwnedStateSchema, RevealedData, RevealedValue, Schema, Transition, TransitionType, + TypedAssigns, +}; +use rgbcore::{GlobalStateSchema, GlobalStateType, MetaType, Metadata}; +use strict_encoding::{FieldName, SerializeError, StrictSerialize}; +use strict_types::{decode, SemId, TypeSystem}; + +use crate::containers::{BuilderSeal, ContainerVer, Contract, ValidConsignment}; +use crate::contract::resolver::DumbResolver; +use crate::contract::AllocatedState; +use crate::persistence::StashInconsistency; + +#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] +#[display(doc_comments)] +pub enum BuilderError { + #[from] + #[display(inner)] + MetadataInvalid(MetadataError), + + /// unknown owned state name `{0}`. + InvalidStateField(FieldName), + + /// state `{0}` provided to the builder has invalid type. + InvalidStateType(AssignmentType), + + /// {0} is not supported by the contract genesis. + InvalidLayer1(Layer1), + + #[from] + #[display(inner)] + StrictEncode(SerializeError), + + #[from] + #[display(inner)] + Reify(decode::Error), + + #[from] + #[display(inner)] + Confinement(confinement::Error), + + #[from] + #[display(doc_comments)] + Inconsistency(StashInconsistency), + + #[from] + #[display(inner)] + ContractInconsistency(validation::Status), +} + +#[derive(Clone, Debug)] +pub struct ContractBuilder { + builder: OperationBuilder, + scripts: Scripts, + issuer: Identity, + chain_net: ChainNet, +} + +impl ContractBuilder { + pub fn with( + issuer: Identity, + schema: Schema, + types: TypeSystem, + scripts: Scripts, + chain_net: ChainNet, + ) -> Self { + Self { + builder: OperationBuilder::with(schema, types), + scripts, + issuer, + chain_net, + } + } + + pub fn type_system(&self) -> &TypeSystem { self.builder.type_system() } + + #[inline] + pub fn global_type(&self, name: impl Into) -> GlobalStateType { + self.builder.global_type(name) + } + + #[inline] + pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } + + #[inline] + pub fn add_metadata( + mut self, + name: impl Into, + value: impl StrictSerialize, + ) -> Result { + self.builder = self.builder.add_metadata(name, value)?; + Ok(self) + } + + #[inline] + pub fn add_metadata_raw( + mut self, + type_id: MetaType, + value: impl StrictSerialize, + ) -> Result { + self.builder = self.builder.add_metadata_raw(type_id, value)?; + Ok(self) + } + + #[inline] + pub fn add_global_state( + mut self, + name: impl Into, + value: impl StrictSerialize, + ) -> Result { + self.builder = self.builder.add_global_state(name, value)?; + Ok(self) + } + + #[inline] + pub fn add_global_state_raw( + mut self, + type_id: GlobalStateType, + value: impl StrictSerialize, + ) -> Result { + self.builder = self.builder.add_global_state_raw(type_id, value)?; + Ok(self) + } + + pub fn add_rights( + mut self, + name: impl Into, + seal: impl Into>, + ) -> Result { + let seal = seal.into(); + self.builder = self.builder.add_rights(name, seal)?; + Ok(self) + } + + pub fn add_rights_raw( + mut self, + type_id: AssignmentType, + seal: impl Into>, + ) -> Result { + let seal = seal.into(); + self.builder = self.builder.add_rights_raw(type_id, seal)?; + Ok(self) + } + + pub fn add_fungible_state( + mut self, + name: impl Into, + seal: impl Into>, + value: impl Into, + ) -> Result { + let seal = seal.into(); + self.builder = self.builder.add_fungible_state(name, seal, value)?; + Ok(self) + } + + pub fn add_fungible_state_raw( + mut self, + type_id: AssignmentType, + seal: impl Into>, + value: impl Into, + ) -> Result { + let state = RevealedValue::new(value.into()); + self.builder = self.builder.add_fungible_state_raw(type_id, seal, state)?; + Ok(self) + } + + pub fn add_data( + mut self, + name: impl Into, + seal: impl Into>, + value: impl StrictSerialize, + ) -> Result { + let seal = seal.into(); + self.builder = self.builder.add_data(name, seal, value)?; + Ok(self) + } + + pub fn add_data_raw( + mut self, + type_id: AssignmentType, + seal: impl Into>, + state: RevealedData, + ) -> Result { + let seal = seal.into(); + self.builder = self.builder.add_data_raw(type_id, seal, state)?; + Ok(self) + } + + pub fn issue_contract(self) -> Result, BuilderError> { + self.issue_contract_raw(Utc::now().timestamp()) + } + + pub fn issue_contract_raw( + self, + timestamp: i64, + ) -> Result, BuilderError> { + let (schema, global, assignments, types, metadata) = self.builder.complete(); + + let genesis = Genesis { + ffv: none!(), + schema_id: schema.schema_id(), + timestamp, + chain_net: self.chain_net, + seal_closing_strategy: Default::default(), + metadata, + globals: global, + assignments, + issuer: self.issuer, + }; + + let scripts = Confined::from_iter_checked(self.scripts.into_values()); + + let contract = Contract { + version: ContainerVer::V0, + transfer: false, + terminals: none!(), + genesis, + bundles: none!(), + schema, + + types, + scripts, + }; + + let valid_contract = contract + .validate(&DumbResolver, self.chain_net, None) + .map_err(|(status, _)| status)?; + + Ok(valid_contract) + } +} + +#[derive(Clone, Debug)] +pub struct TransitionBuilder { + contract_id: ContractId, + builder: OperationBuilder, + nonce: u64, + transition_type: TransitionType, + inputs: TinyOrdMap, +} + +impl TransitionBuilder { + pub fn named_transition( + contract_id: ContractId, + schema: Schema, + transition_name: impl Into, + types: TypeSystem, + ) -> Result { + let transition_type = schema.transition_type(transition_name); + Ok(Self::with(contract_id, schema, transition_type, types)) + } + + pub fn with( + contract_id: ContractId, + schema: Schema, + transition_type: TransitionType, + types: TypeSystem, + ) -> Self { + Self { + contract_id, + builder: OperationBuilder::with(schema, types), + nonce: u64::MAX, + transition_type, + inputs: none!(), + } + } + + pub fn type_system(&self) -> &TypeSystem { self.builder.type_system() } + + pub fn transition_type(&self) -> TransitionType { self.transition_type } + + pub fn set_nonce(mut self, nonce: u64) -> Self { + self.nonce = nonce; + self + } + + #[inline] + pub fn add_metadata( + mut self, + name: impl Into, + value: impl StrictSerialize, + ) -> Result { + self.builder = self.builder.add_metadata(name, value)?; + Ok(self) + } + + #[inline] + pub fn add_metadata_raw( + mut self, + type_id: MetaType, + value: impl StrictSerialize, + ) -> Result { + self.builder = self.builder.add_metadata_raw(type_id, value)?; + Ok(self) + } + + #[inline] + pub fn add_global_state( + mut self, + name: impl Into, + value: impl StrictSerialize, + ) -> Result { + self.builder = self.builder.add_global_state(name, value)?; + Ok(self) + } + + pub fn add_input(mut self, opout: Opout, state: AllocatedState) -> Result { + self.inputs.insert(opout, state)?; + Ok(self) + } + + #[inline] + pub fn assignment_type(&self, name: impl Into) -> AssignmentType { + self.builder.assignment_type(name) + } + + #[inline] + pub fn global_type(&self, name: impl Into) -> GlobalStateType { + self.builder.global_type(name) + } + + #[inline] + pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } + + pub fn add_owned_state_raw( + mut self, + type_id: AssignmentType, + seal: impl Into>, + state: AllocatedState, + ) -> Result { + self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?; + Ok(self) + } + + pub fn add_rights( + mut self, + name: impl Into, + seal: impl Into>, + ) -> Result { + self.builder = self.builder.add_rights(name, seal)?; + Ok(self) + } + + pub fn add_rights_raw( + mut self, + type_id: AssignmentType, + seal: impl Into>, + ) -> Result { + self.builder = self.builder.add_rights_raw(type_id, seal)?; + Ok(self) + } + + pub fn add_fungible_state( + mut self, + name: impl Into, + seal: impl Into>, + value: impl Into, + ) -> Result { + self.builder = self.builder.add_fungible_state(name, seal, value)?; + Ok(self) + } + + pub fn add_fungible_state_raw( + mut self, + type_id: AssignmentType, + seal: impl Into>, + value: impl Into, + ) -> Result { + let state = RevealedValue::new(value.into()); + self.builder = self.builder.add_fungible_state_raw(type_id, seal, state)?; + Ok(self) + } + + pub fn add_data( + mut self, + name: impl Into, + seal: impl Into>, + value: impl StrictSerialize, + ) -> Result { + self.builder = self.builder.add_data(name, seal, value)?; + Ok(self) + } + + pub fn add_data_raw( + mut self, + type_id: AssignmentType, + seal: impl Into>, + state: RevealedData, + ) -> Result { + self.builder = self.builder.add_data_raw(type_id, seal, state)?; + Ok(self) + } + + pub fn has_inputs(&self) -> bool { !self.inputs.is_empty() } + + pub fn complete_transition(self) -> Result { + let (_, global, assignments, _, metadata) = self.builder.complete(); + + let transition = Transition { + ffv: none!(), + contract_id: self.contract_id, + nonce: self.nonce, + transition_type: self.transition_type, + metadata, + globals: global, + inputs: NonEmptyOrdSet::from_iter_checked(self.inputs.into_keys()).into(), + assignments, + signature: none!(), + }; + + // TODO: Validate against schema + + Ok(transition) + } +} + +#[derive(Clone, Debug)] +pub struct OperationBuilder { + schema: Schema, + + global: GlobalState, + meta: Metadata, + rights: TinyOrdMap>, 1, U16>>, + fungible: + TinyOrdMap, RevealedValue>, 1, U16>>, + data: TinyOrdMap, RevealedData>, 1, U16>>, + types: TypeSystem, +} + +impl OperationBuilder { + fn with(schema: Schema, types: TypeSystem) -> Self { + OperationBuilder { + schema, + + global: none!(), + meta: none!(), + rights: none!(), + fungible: none!(), + data: none!(), + + types, + } + } + + fn type_system(&self) -> &TypeSystem { &self.types } + + fn assignment_type(&self, name: impl Into) -> AssignmentType { + self.schema.assignment_type(name) + } + + fn meta_type(&self, name: impl Into) -> MetaType { self.schema.meta_type(name) } + + fn meta_name(&self, ty: MetaType) -> &FieldName { self.schema.meta_name(ty) } + + fn global_type(&self, name: impl Into) -> GlobalStateType { + self.schema.global_type(name) + } + + #[inline] + fn state_schema(&self, type_id: AssignmentType) -> &OwnedStateSchema { + &self + .schema + .owned_types + .get(&type_id) + .expect("schema should support the assignment type: must be checked by the constructor") + .owned_state_schema + } + + #[inline] + fn meta_schema(&self, type_id: MetaType) -> &SemId { + &self + .schema + .meta_types + .get(&type_id) + .expect("schema should support the meta type: must be checked by the constructor") + .sem_id + } + + #[inline] + fn global_schema(&self, type_id: GlobalStateType) -> &GlobalStateSchema { + &self + .schema + .global_types + .get(&type_id) + .expect( + "schema should support the global state type: must be checked by the constructor", + ) + .global_state_schema + } + + pub fn add_metadata( + self, + name: impl Into, + value: impl StrictSerialize, + ) -> Result { + let type_id = self.meta_type(name); + self.add_metadata_raw(type_id, value) + } + + pub fn add_metadata_raw( + mut self, + type_id: MetaType, + value: impl StrictSerialize, + ) -> Result { + let serialized = value.to_strict_serialized::<{ u16::MAX as usize }>()?; + + let sem_id = self.meta_schema(type_id); + self.types.strict_deserialize_type(*sem_id, &serialized)?; + self.meta.add_value(type_id, serialized.into())?; + Ok(self) + } + + pub fn add_global_state( + self, + name: impl Into, + value: impl StrictSerialize, + ) -> Result { + let type_id = self.global_type(name); + self.add_global_state_raw(type_id, value) + } + + pub fn add_global_state_raw( + mut self, + type_id: GlobalStateType, + value: impl StrictSerialize, + ) -> Result { + let serialized = value.to_strict_serialized::<{ u16::MAX as usize }>()?; + + // Check value matches type requirements + let sem_id = self.global_schema(type_id).sem_id; + self.types.strict_deserialize_type(sem_id, &serialized)?; + + self.global.add_state(type_id, serialized.into())?; + + Ok(self) + } + + fn add_owned_state_raw( + self, + type_id: AssignmentType, + seal: impl Into>, + state: AllocatedState, + ) -> Result { + match state { + AllocatedState::Void => self.add_rights_raw(type_id, seal), + AllocatedState::Amount(value) => self.add_fungible_state_raw(type_id, seal, value), + AllocatedState::Data(data) => self.add_data_raw(type_id, seal, data), + } + } + + fn add_rights( + self, + name: impl Into, + seal: impl Into>, + ) -> Result { + let type_id = self.assignment_type(name); + self.add_rights_raw(type_id, seal) + } + + fn add_rights_raw( + mut self, + type_id: AssignmentType, + seal: impl Into>, + ) -> Result { + let state_schema = self.state_schema(type_id); + if *state_schema != OwnedStateSchema::Declarative { + return Err(BuilderError::InvalidStateType(type_id)); + } + + let seal = seal.into(); + match self.rights.get_mut(&type_id) { + Some(assignments) => { + assignments.push(seal)?; + } + None => { + self.rights.insert(type_id, Confined::with(seal))?; + } + } + + Ok(self) + } + + fn add_fungible_state( + self, + name: impl Into, + seal: impl Into>, + value: impl Into, + ) -> Result { + let type_id = self.assignment_type(name); + let state = RevealedValue::new(value.into()); + self.add_fungible_state_raw(type_id, seal, state) + } + + fn add_fungible_state_raw( + mut self, + type_id: AssignmentType, + seal: impl Into>, + state: RevealedValue, + ) -> Result { + let state_schema = self.state_schema(type_id); + if *state_schema != OwnedStateSchema::Fungible(FungibleType::Unsigned64Bit) { + return Err(BuilderError::InvalidStateType(type_id)); + } + + let seal = seal.into(); + match self.fungible.get_mut(&type_id) { + Some(assignments) => { + assignments.insert(seal, state)?; + } + None => { + self.fungible + .insert(type_id, Confined::with((seal, state)))?; + } + } + + Ok(self) + } + + fn add_data( + self, + name: impl Into, + seal: impl Into>, + value: impl StrictSerialize, + ) -> Result { + let serialized = value.to_strict_serialized::()?; + let state = RevealedData::from(serialized); + + let type_id = self.assignment_type(name); + self.add_data_raw(type_id, seal, state) + } + + fn add_data_raw( + mut self, + type_id: AssignmentType, + seal: impl Into>, + state: RevealedData, + ) -> Result { + let state_schema = self.state_schema(type_id); + if let OwnedStateSchema::Structured(_) = *state_schema { + let seal = seal.into(); + match self.data.get_mut(&type_id) { + Some(assignments) => { + assignments.insert(seal, state)?; + } + None => { + self.data.insert(type_id, Confined::with((seal, state)))?; + } + } + } else { + return Err(BuilderError::InvalidStateType(type_id)); + } + Ok(self) + } + + fn complete(self) -> (Schema, GlobalState, Assignments, TypeSystem, Metadata) { + let owned_state = self.fungible.into_iter().map(|(id, vec)| { + let vec = vec + .into_iter() + .map(|(seal, value)| match seal { + BuilderSeal::Revealed(seal) => Assign::Revealed { seal, state: value }, + BuilderSeal::Concealed(seal) => Assign::ConfidentialSeal { seal, state: value }, + }) + .collect::>(); + let state = Confined::try_from_iter(vec).expect("at least one element"); + let state = TypedAssigns::Fungible(AssignVec::with(state)); + (id, state) + }); + let owned_data = self.data.into_iter().map(|(id, vec)| { + let vec_data = vec.into_iter().map(|(seal, value)| match seal { + BuilderSeal::Revealed(seal) => Assign::Revealed { seal, state: value }, + BuilderSeal::Concealed(seal) => Assign::ConfidentialSeal { seal, state: value }, + }); + let state_data = Confined::try_from_iter(vec_data).expect("at least one element"); + let state_data = TypedAssigns::Structured(AssignVec::with(state_data)); + (id, state_data) + }); + let owned_rights = self.rights.into_iter().map(|(id, vec)| { + let vec_data = vec.into_iter().map(|seal| match seal { + BuilderSeal::Revealed(seal) => Assign::Revealed { + seal, + state: none!(), + }, + BuilderSeal::Concealed(seal) => Assign::ConfidentialSeal { + seal, + state: none!(), + }, + }); + let state_data = Confined::try_from_iter(vec_data).expect("at least one element"); + let state_data = TypedAssigns::Declarative(AssignVec::with(state_data)); + (id, state_data) + }); + + let owned_state = Confined::try_from_iter(owned_state).expect("same size"); + let owned_data = Confined::try_from_iter(owned_data).expect("same size"); + let owned_rights = Confined::try_from_iter(owned_rights).expect("same size"); + + let mut assignments = Assignments::from_inner(owned_state); + assignments + .extend(Assignments::from_inner(owned_data).into_inner()) + .expect("too many assignments"); + assignments + .extend(Assignments::from_inner(owned_rights).into_inner()) + .expect("too many assignments"); + + (self.schema, self.global, assignments, self.types, self.meta) + } +} diff --git a/src/interface/contract.rs b/src/contract/data.rs similarity index 82% rename from src/interface/contract.rs rename to src/contract/data.rs index 49042304..750a1d8c 100644 --- a/src/interface/contract.rs +++ b/src/contract/data.rs @@ -25,22 +25,21 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use bp::Outpoint; use invoice::{Allocation, Amount}; use rgb::{ - AssignmentType, AttachState, ContractId, DataState, OpId, OutputSeal, RevealedAttach, - RevealedData, RevealedValue, Schema, Txid, VoidState, + AssignmentType, ContractId, GlobalStateType, OpId, OutputSeal, RevealedData, RevealedValue, + Schema, Txid, VoidState, }; use strict_encoding::{FieldName, StrictDecode, StrictDumb, StrictEncode}; use strict_types::{StrictVal, TypeSystem}; -use crate::contract::{KnownState, OutputAssignment, WitnessInfo}; +use crate::contract::{AssignmentsFilter, KnownState, OutputAssignment, WitnessInfo}; use crate::info::ContractInfo; -use crate::interface::{AssignmentsFilter, IfaceImpl}; use crate::persistence::ContractStateRead; use crate::LIB_NAME_RGB_STD; #[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] #[display(doc_comments)] pub enum ContractError { - /// field name {0} is unknown to the contract interface + /// field name {0} is unknown to the contract schema FieldNameUnknown(FieldName), } @@ -61,20 +60,14 @@ pub enum AllocatedState { Void, #[from] - #[from(RevealedValue)] + #[from(Amount)] #[strict_type(tag = 1)] - Amount(Amount), + Amount(RevealedValue), #[from] - #[from(RevealedData)] #[from(Allocation)] #[strict_type(tag = 2)] - Data(DataState), - - #[from] - #[from(RevealedAttach)] - #[strict_type(tag = 3)] - Attachment(AttachState), + Data(RevealedData), } impl KnownState for AllocatedState { @@ -84,7 +77,7 @@ impl KnownState for AllocatedState { impl AllocatedState { fn unwrap_fungible(&self) -> Amount { match self { - AllocatedState::Amount(amount) => *amount, + AllocatedState::Amount(revealed_value) => (*revealed_value).into(), _ => panic!("unwrapping non-fungible state"), } } @@ -93,8 +86,7 @@ impl AllocatedState { pub type OwnedAllocation = OutputAssignment; pub type RightsAllocation = OutputAssignment; pub type FungibleAllocation = OutputAssignment; -pub type DataAllocation = OutputAssignment; -pub type AttachAllocation = OutputAssignment; +pub type DataAllocation = OutputAssignment; #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)] #[cfg_attr( @@ -180,7 +172,7 @@ impl ContractOp { fn fungible_genesis(our_allocations: HashSet) -> Self { let to = our_allocations.iter().map(|a| a.seal).collect(); let opids = our_allocations.iter().map(|a| a.opout.op).collect(); - let issued = our_allocations + let issued: Amount = our_allocations .iter() .map(|a| a.state.unwrap_fungible()) .sum(); @@ -188,7 +180,7 @@ impl ContractOp { direction: OpDirection::Issued, ty: reduce_to_ty(our_allocations), opids, - state: AllocatedState::Amount(issued), + state: AllocatedState::Amount(issued.into()), to, witness: None, } @@ -197,7 +189,7 @@ impl ContractOp { fn fungible_sent(witness: WitnessInfo, ext_allocations: HashSet) -> Self { let opids = ext_allocations.iter().map(|a| a.opout.op).collect(); let to = ext_allocations.iter().map(|a| a.seal).collect(); - let amount = ext_allocations + let amount: Amount = ext_allocations .iter() .map(|a| a.state.unwrap_fungible()) .sum(); @@ -205,7 +197,7 @@ impl ContractOp { direction: OpDirection::Sent, ty: reduce_to_ty(ext_allocations), opids, - state: AllocatedState::Amount(amount), + state: AllocatedState::Amount(amount.into()), to, witness: Some(witness), } @@ -214,7 +206,7 @@ impl ContractOp { fn fungible_received(witness: WitnessInfo, our_allocations: HashSet) -> Self { let opids = our_allocations.iter().map(|a| a.opout.op).collect(); let to = our_allocations.iter().map(|a| a.seal).collect(); - let amount = our_allocations + let amount: Amount = our_allocations .iter() .map(|a| a.state.unwrap_fungible()) .sum(); @@ -222,61 +214,59 @@ impl ContractOp { direction: OpDirection::Received, ty: reduce_to_ty(our_allocations), opids, - state: AllocatedState::Amount(amount), + state: AllocatedState::Amount(amount.into()), to, witness: Some(witness), } } } -/// Contract state is an in-memory structure providing API to read structured -/// data from the [`rgb::ContractHistory`]. +/// Data of a contract. #[derive(Clone, Eq, PartialEq, Debug)] -pub struct ContractIface { +pub struct ContractData { pub state: S, pub schema: Schema, - pub iface: IfaceImpl, pub types: TypeSystem, pub info: ContractInfo, } -impl ContractIface { +impl ContractData { pub fn contract_id(&self) -> ContractId { self.state.contract_id() } /// # Panics /// - /// If data are corrupted and contract schema doesn't match interface - /// implementations. - pub fn global( - &self, - name: impl Into, - ) -> Result + '_, ContractError> { - let name = name.into(); - let type_id = self - .iface - .global_type(&name) - .ok_or(ContractError::FieldNameUnknown(name))?; - let global_schema = self + /// If data is corrupted. + pub fn global(&self, name: impl Into) -> impl Iterator + '_ { + self.global_raw(self.schema.global_type(name)) + } + + /// # Panics + /// + /// If data is corrupted. + pub fn global_raw(&self, type_id: GlobalStateType) -> impl Iterator + '_ { + let global_details = self .schema .global_types .get(&type_id) - .expect("schema doesn't match interface"); - Ok(self - .state + .expect("cannot find type ID in schema global types"); + self.state .global(type_id) - .expect("schema doesn't match interface") + .expect("cannot find type ID in global state") .map(|data| { self.types - .strict_deserialize_type(global_schema.sem_id, data.borrow().as_slice()) + .strict_deserialize_type( + global_details.global_state_schema.sem_id, + data.borrow().as_slice(), + ) .expect("unvalidated contract data in stash") .unbox() - })) + }) } fn extract_state<'c, A, U>( &'c self, state: impl IntoIterator> + 'c, - name: impl Into, + type_id: AssignmentType, filter: impl AssignmentsFilter + 'c, ) -> Result> + 'c, ContractError> where @@ -284,24 +274,19 @@ impl ContractIface { U: From + KnownState + 'c, { Ok(self - .extract_state_unfiltered(state, name)? + .extract_state_unfiltered(state, type_id)? .filter(move |outp| filter.should_include(outp.seal, outp.witness))) } fn extract_state_unfiltered<'c, A, U>( &'c self, state: impl IntoIterator> + 'c, - name: impl Into, + type_id: AssignmentType, ) -> Result> + 'c, ContractError> where A: Clone + KnownState + 'c, U: From + KnownState + 'c, { - let name = name.into(); - let type_id = self - .iface - .assignments_type(&name) - .ok_or(ContractError::FieldNameUnknown(name))?; Ok(state .into_iter() .filter(move |outp| outp.opout.ty == type_id) @@ -314,7 +299,16 @@ impl ContractIface { name: impl Into, filter: impl AssignmentsFilter + 'c, ) -> Result + 'c, ContractError> { - self.extract_state(self.state.rights_all(), name, filter) + let type_id = self.schema.assignment_type(name); + self.rights_raw(type_id, filter) + } + + pub fn rights_raw<'c>( + &'c self, + type_id: AssignmentType, + filter: impl AssignmentsFilter + 'c, + ) -> Result + 'c, ContractError> { + self.extract_state(self.state.rights_all(), type_id, filter) } pub fn fungible<'c>( @@ -322,7 +316,16 @@ impl ContractIface { name: impl Into, filter: impl AssignmentsFilter + 'c, ) -> Result + 'c, ContractError> { - self.extract_state(self.state.fungible_all(), name, filter) + let type_id = self.schema.assignment_type(name); + self.fungible_raw(type_id, filter) + } + + pub fn fungible_raw<'c>( + &'c self, + type_id: AssignmentType, + filter: impl AssignmentsFilter + 'c, + ) -> Result + 'c, ContractError> { + self.extract_state(self.state.fungible_all(), type_id, filter) } pub fn data<'c>( @@ -330,15 +333,16 @@ impl ContractIface { name: impl Into, filter: impl AssignmentsFilter + 'c, ) -> Result + 'c, ContractError> { - self.extract_state(self.state.data_all(), name, filter) + let type_id = self.schema.assignment_type(name); + self.data_raw(type_id, filter) } - pub fn attachments<'c>( + pub fn data_raw<'c>( &'c self, - name: impl Into, + type_id: AssignmentType, filter: impl AssignmentsFilter + 'c, - ) -> Result + 'c, ContractError> { - self.extract_state(self.state.attach_all(), name, filter) + ) -> Result + 'c, ContractError> { + self.extract_state(self.state.data_all(), type_id, filter) } pub fn allocations<'c>( @@ -361,10 +365,8 @@ impl ContractIface { } f(filter, self.state.rights_all()) - .map(OwnedAllocation::from) - .chain(f(filter, self.state.fungible_all()).map(OwnedAllocation::from)) - .chain(f(filter, self.state.data_all()).map(OwnedAllocation::from)) - .chain(f(filter, self.state.attach_all()).map(OwnedAllocation::from)) + .chain(f(filter, self.state.fungible_all())) + .chain(f(filter, self.state.data_all())) } pub fn outpoint_allocations( @@ -383,7 +385,6 @@ impl ContractIface { .into_iter() .chain(self.history_rights(filter_outpoints.clone(), filter_witnesses.clone())) .chain(self.history_data(filter_outpoints.clone(), filter_witnesses.clone())) - .chain(self.history_attach(filter_outpoints, filter_witnesses)) .collect() } @@ -451,7 +452,7 @@ impl ContractIface { .difference(&our_allocations) .cloned() .collect::>(); - // This was a blank state transition with no external payment + // This was an extra state transition with no external payment if ext_allocations.is_empty() { continue; } @@ -510,14 +511,6 @@ impl ContractIface { self.operations(|state| state.data_all(), filter_outpoints, filter_witnesses) } - pub fn history_attach( - &self, - filter_outpoints: impl AssignmentsFilter, - filter_witnesses: impl AssignmentsFilter, - ) -> Vec { - self.operations(|state| state.attach_all(), filter_outpoints, filter_witnesses) - } - pub fn witness_info(&self, witness_id: Txid) -> Option { let ord = self.state.witness_ord(witness_id)?; Some(WitnessInfo { diff --git a/src/interface/filter.rs b/src/contract/filter.rs similarity index 100% rename from src/interface/filter.rs rename to src/contract/filter.rs diff --git a/src/contract/merge_reveal.rs b/src/contract/merge_reveal.rs index ecf0d3ca..015269e0 100644 --- a/src/contract/merge_reveal.rs +++ b/src/contract/merge_reveal.rs @@ -19,25 +19,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::BTreeMap; - use amplify::confinement::Confined; use amplify::Wrapper; use bp::Txid; use commit_verify::{mpc, Conceal}; use rgb::{ - Assign, Assignments, BundleId, ExposedSeal, ExposedState, Extension, Genesis, OpId, Operation, - Transition, TransitionBundle, TypedAssigns, + Assign, Assignments, BundleId, ExposedSeal, ExposedState, Genesis, OpId, Operation, Transition, + TransitionBundle, TypedAssigns, }; #[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From)] #[display(doc_comments)] pub enum MergeRevealError { - /// operations {0} and {1} has different commitment ids and can't be + /// operations {0} and {1} have different commitment ids and can't be /// merge-revealed. This usually means internal application business logic /// error which should be reported to the software vendor. OperationMismatch(OpId, OpId), + /// operations with ID {0} have different signatures and can't be merge-revealed. + /// This usually means internal application business logic + /// error which should be reported to the software vendor. + SignatureMismatch(OpId), + /// mismatch in anchor chains: one grip references bitcoin transaction /// {bitcoin} and the other merged part references liquid transaction /// {liquid}. @@ -49,6 +52,9 @@ pub enum MergeRevealError { /// anchors in anchored bundle are not equal for bundle {0}. AnchorsNonEqual(BundleId), + /// assignments have different keys. + AssignmentsDifferentKeys, + /// the merged bundles contain more transitions than inputs. InsufficientInputs, @@ -74,112 +80,71 @@ pub enum MergeRevealError { /// merge(ConfidentialSeal, ConfidentialAmount) => Revealed /// merge(ConfidentialAmount, ConfidentialSeal) => Revealed /// merge(Confidential, Anything) => Anything -pub trait MergeReveal: Sized { - // TODO: Take self by mut ref instead of consuming (will remove clones in - // Stash::consume operation). - fn merge_reveal(self, other: Self) -> Result; +pub trait MergeReveal { + fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError>; } -/* -pub trait MergeRevealContract: Sized { - fn merge_reveal_contract( - self, - other: Self, - contract_id: ContractId, - ) -> Result; -} - */ - impl MergeReveal for Assign { - fn merge_reveal(self, other: Self) -> Result { + fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> { debug_assert_eq!(self.conceal(), other.conceal()); - match (self, other) { - // Anything + Revealed = Revealed - (_, state @ Assign::Revealed { .. }) | (state @ Assign::Revealed { .. }, _) => { - Ok(state) - } - - (state @ Assign::ConfidentialSeal { .. }, Assign::ConfidentialSeal { .. }) => Ok(state), + // Anything + Revealed = Revealed + if let Assign::Revealed { .. } = other { + *self = other.clone(); } + Ok(()) } } impl MergeReveal for TypedAssigns { - fn merge_reveal(self, other: Self) -> Result { + fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> { match (self, other) { (TypedAssigns::Declarative(first_vec), TypedAssigns::Declarative(second_vec)) => { - let mut result = Vec::with_capacity(first_vec.len()); - for (first, second) in first_vec.into_iter().zip(second_vec.into_iter()) { - result.push(first.merge_reveal(second)?); + for (first, second) in first_vec.iter_mut().zip(second_vec.as_ref()) { + first.merge_reveal(second)?; } - Ok(TypedAssigns::Declarative( - Confined::try_from(result).expect("collection of the same size"), - )) } (TypedAssigns::Fungible(first_vec), TypedAssigns::Fungible(second_vec)) => { - let mut result = Vec::with_capacity(first_vec.len()); - for (first, second) in first_vec.into_iter().zip(second_vec.into_iter()) { - result.push(first.merge_reveal(second)?); + for (first, second) in first_vec.iter_mut().zip(second_vec.as_ref()) { + first.merge_reveal(second)?; } - Ok(TypedAssigns::Fungible( - Confined::try_from(result).expect("collection of the same size"), - )) } (TypedAssigns::Structured(first_vec), TypedAssigns::Structured(second_vec)) => { - let mut result = Vec::with_capacity(first_vec.len()); - for (first, second) in first_vec.into_iter().zip(second_vec.into_iter()) { - result.push(first.merge_reveal(second)?); + for (first, second) in first_vec.iter_mut().zip(second_vec.as_ref()) { + first.merge_reveal(second)?; } - Ok(TypedAssigns::Structured( - Confined::try_from(result).expect("collection of the same size"), - )) } - (TypedAssigns::Attachment(first_vec), TypedAssigns::Attachment(second_vec)) => { - let mut result = Vec::with_capacity(first_vec.len()); - for (first, second) in first_vec.into_iter().zip(second_vec.into_iter()) { - result.push(first.merge_reveal(second)?); - } - Ok(TypedAssigns::Attachment( - Confined::try_from(result).expect("collection of the same size"), - )) - } // No other patterns possible, should not reach here _ => { unreachable!("Assignments::consensus_commitments is broken") } - } + }; + Ok(()) } } impl MergeReveal for Assignments { - fn merge_reveal(self, other: Self) -> Result { - let mut result = BTreeMap::new(); - for (first, second) in self - .into_inner() - .into_iter() - .zip(other.into_inner().into_iter()) - { - debug_assert_eq!(first.0, second.0); - result.insert(first.0, first.1.merge_reveal(second.1)?); + fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> { + for (ass_type, other_typed_assigns) in other.as_inner().iter() { + let typed_assigns = self + .get_mut(ass_type) + .ok_or(MergeRevealError::AssignmentsDifferentKeys)?; + typed_assigns.merge_reveal(other_typed_assigns)?; } - Ok(Assignments::from_inner( - Confined::try_from(result).expect("collection of the same size"), - )) + Ok(()) } } impl MergeReveal for TransitionBundle { - fn merge_reveal(mut self, other: Self) -> Result { + fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> { debug_assert_eq!(self.bundle_id(), other.bundle_id()); - let mut self_transitions = self.known_transitions.release(); - for (opid, other_transition) in other.known_transitions { - if let Some(mut transition) = self_transitions.remove(&opid) { - transition = transition.merge_reveal(other_transition)?; - self_transitions.insert(opid, transition); + let mut self_transitions = self.known_transitions.to_unconfined(); + for (opid, other_transition) in &other.known_transitions { + if let Some(transition) = self_transitions.get_mut(opid) { + transition.merge_reveal(other_transition)?; } } self.known_transitions = Confined::from_checked(self_transitions); @@ -187,32 +152,12 @@ impl MergeReveal for TransitionBundle { if self.input_map.len() < self.known_transitions.len() { return Err(MergeRevealError::InsufficientInputs); } - Ok(self) - } -} - -/* -impl MergeRevealContract for AnchoredBundle { - fn merge_reveal_contract( - self, - other: Self, - contract_id: ContractId, - ) -> Result { - let bundle_id = self.bundle_id(); - let anchor1 = self.anchor.into_merkle_block(contract_id, bundle_id)?; - let anchor2 = other.anchor.into_merkle_block(contract_id, bundle_id)?; - Ok(AnchoredBundle { - anchor: anchor1 - .merge_reveal(anchor2)? - .into_merkle_proof(contract_id)?, - bundle: self.bundle.merge_reveal(other.bundle)?, - }) + Ok(()) } } - */ impl MergeReveal for Genesis { - fn merge_reveal(mut self, other: Self) -> Result { + fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> { let self_id = self.id(); let other_id = other.id(); if self_id != other_id { @@ -221,31 +166,34 @@ impl MergeReveal for Genesis { OpId::from_inner(other_id.into_inner()), )); } - self.assignments = self.assignments.merge_reveal(other.assignments)?; - Ok(self) + self.assignments.merge_reveal(&other.assignments)?; + Ok(()) } } impl MergeReveal for Transition { - fn merge_reveal(mut self, other: Self) -> Result { - let self_id = self.id(); - let other_id = other.id(); - if self_id != other_id { - return Err(MergeRevealError::OperationMismatch(self_id, other_id)); - } - self.assignments = self.assignments.merge_reveal(other.assignments)?; - Ok(self) - } -} - -impl MergeReveal for Extension { - fn merge_reveal(mut self, other: Self) -> Result { + fn merge_reveal(&mut self, other: &Self) -> Result<(), MergeRevealError> { let self_id = self.id(); let other_id = other.id(); if self_id != other_id { return Err(MergeRevealError::OperationMismatch(self_id, other_id)); } - self.assignments = self.assignments.merge_reveal(other.assignments)?; - Ok(self) + self.assignments.merge_reveal(&other.assignments)?; + match (self.signature.take(), other.signature.as_ref()) { + (None, None) => {} + (Some(sig), None) => { + self.signature = Some(sig); + } + (None, Some(sig)) => { + self.signature = Some(sig.clone()); + } + (Some(sig1), Some(sig2)) if sig1 == *sig2 => { + self.signature = Some(sig1); + } + _ => { + return Err(MergeRevealError::SignatureMismatch(self_id)); + } + }; + Ok(()) } } diff --git a/src/contract/mod.rs b/src/contract/mod.rs index 3e22d409..067833f5 100644 --- a/src/contract/mod.rs +++ b/src/contract/mod.rs @@ -20,12 +20,24 @@ // limitations under the License. mod assignments; +mod builder; +mod data; +mod filter; mod merge_reveal; +mod schema; +pub(crate) mod resolver; -pub use assignments::{KnownState, OutputAssignment, TypedAssignsExt, WitnessInfo}; +pub use assignments::{KnownState, OutputAssignment, WitnessInfo}; +pub use builder::{BuilderError, ContractBuilder, TransitionBuilder}; +pub use data::{ + AllocatedState, ContractData, ContractError, ContractOp, DataAllocation, FungibleAllocation, + OpDirection, OwnedAllocation, RightsAllocation, +}; +pub use filter::{AssignmentsFilter, FilterExclude, FilterIncludeAll}; pub use merge_reveal::{MergeReveal, MergeRevealError}; use rgb::vm::OrdOpRef; -use rgb::{ExtensionType, OpId, TransitionType, Txid}; +use rgb::{OpId, TransitionType, Txid}; +pub use schema::{IssuerWrapper, SchemaWrapper}; use crate::LIB_NAME_RGB_STD; @@ -41,7 +53,6 @@ pub enum OpWitness { #[strict_type(dumb)] Genesis, Transition(Txid, TransitionType), - Extension(Txid, ExtensionType), } impl From> for OpWitness { @@ -51,9 +62,6 @@ impl From> for OpWitness { OrdOpRef::Transition(op, witness_id, ..) => { OpWitness::Transition(witness_id, op.transition_type) } - OrdOpRef::Extension(op, witness_id, ..) => { - OpWitness::Extension(witness_id, op.extension_type) - } } } } @@ -63,9 +71,7 @@ impl OpWitness { pub fn witness_id(&self) -> Option { match self { OpWitness::Genesis => None, - OpWitness::Transition(witness_id, _) | OpWitness::Extension(witness_id, _) => { - Some(*witness_id) - } + OpWitness::Transition(witness_id, _) => Some(*witness_id), } } } @@ -79,10 +85,10 @@ impl OpWitness { serde(crate = "serde_crate", rename_all = "camelCase") )] pub struct GlobalOut { - pub opid: OpId, - pub nonce: u64, pub index: u16, pub op_witness: OpWitness, + pub nonce: u64, + pub opid: OpId, } impl GlobalOut { diff --git a/src/interface/resolver.rs b/src/contract/resolver.rs similarity index 100% rename from src/interface/resolver.rs rename to src/contract/resolver.rs diff --git a/src/contract/schema.rs b/src/contract/schema.rs new file mode 100644 index 00000000..18206c15 --- /dev/null +++ b/src/contract/schema.rs @@ -0,0 +1,53 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// 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. +// +// 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::confinement::Confined; +use strict_types::TypeSystem; + +use crate::containers::{ContainerVer, Kit, ValidKit}; +use crate::contract::ContractData; +use crate::persistence::ContractStateRead; +use crate::validation::Scripts; +use crate::Schema; + +/// The instances implementing this trait are used as wrappers around [`ContractData`] object, +/// allowing a simple API matching the schema requirements. +pub trait SchemaWrapper { + fn with(data: ContractData) -> Self; +} + +pub trait IssuerWrapper { + type Wrapper: SchemaWrapper; + + fn schema() -> Schema; + fn types() -> TypeSystem; + fn scripts() -> Scripts; + + fn kit() -> ValidKit { + let kit = Kit { + version: ContainerVer::V0, + schemata: tiny_bset![Self::schema()], + types: Self::types(), + scripts: Confined::from_iter_checked(Self::scripts().release().into_values()), + }; + kit.validate().expect("invalid construction") + } +} diff --git a/src/indexers/any.rs b/src/indexers/any.rs new file mode 100644 index 00000000..9526d40d --- /dev/null +++ b/src/indexers/any.rs @@ -0,0 +1,128 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2024 by +// Zoe Faltibà +// Rewritten in 2024 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2024 LNP/BP Standards Association. 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::HashMap; + +use bp::{Tx, Txid}; +use rgbcore::validation::{ResolveWitness, WitnessResolverError}; +use rgbcore::vm::WitnessOrd; +use rgbcore::ChainNet; + +use crate::containers::Consignment; + +// We need to repeat methods of `WitnessResolve` trait here to avoid making +// wrappers around resolver types. TODO: Use wrappers instead +pub trait RgbResolver: Send { + fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), String>; + fn resolve_pub_witness(&self, txid: Txid) -> Result, String>; + fn resolve_pub_witness_ord(&self, txid: Txid) -> Result; +} + +/// Type that contains any of the [`Resolver`] types defined by the library +#[derive(From)] +#[non_exhaustive] +pub struct AnyResolver { + inner: Box, + consignment_txes: HashMap, +} + +impl AnyResolver { + #[cfg(feature = "electrum_blocking")] + pub fn electrum_blocking(url: &str, config: Option) -> Result { + Ok(AnyResolver { + inner: Box::new( + electrum::Client::from_config(url, config.unwrap_or_default()) + .map_err(|e| e.to_string())?, + ), + consignment_txes: Default::default(), + }) + } + + #[cfg(feature = "esplora_blocking")] + pub fn esplora_blocking(url: &str, config: Option) -> Result { + Ok(AnyResolver { + inner: Box::new( + esplora::BlockingClient::from_config(url, config.unwrap_or_default()) + .map_err(|e| e.to_string())?, + ), + consignment_txes: Default::default(), + }) + } + + #[cfg(feature = "mempool_blocking")] + pub fn mempool_blocking(url: &str, config: Option) -> Result { + Ok(AnyResolver { + inner: Box::new(super::mempool_blocking::MemPoolClient::new( + url, + config.unwrap_or_default(), + )?), + consignment_txes: Default::default(), + }) + } + + /// Add to the resolver the TXs found in the consignment bundles. Those TXs + /// will not be resolved by an indexer and will be considered tentative. + /// Use with caution, this could allow accepting a consignment containing TXs that have not + /// been broadcasted. + pub fn add_consignment_txes(&mut self, consignment: &Consignment) { + self.consignment_txes.extend( + consignment + .bundles + .iter() + .filter_map(|bw| bw.pub_witness.tx().cloned()) + .map(|tx| (tx.txid(), tx)), + ); + } +} + +impl ResolveWitness for AnyResolver { + fn resolve_pub_witness(&self, witness_id: Txid) -> Result { + if let Some(tx) = self.consignment_txes.get(&witness_id) { + return Ok(tx.clone()); + } + + self.inner + .resolve_pub_witness(witness_id) + .map_err(|e| WitnessResolverError::Other(witness_id, e)) + .and_then(|r| r.ok_or(WitnessResolverError::Unknown(witness_id))) + } + + fn resolve_pub_witness_ord( + &self, + witness_id: Txid, + ) -> Result { + if self.consignment_txes.contains_key(&witness_id) { + return Ok(WitnessOrd::Tentative); + } + + self.inner + .resolve_pub_witness_ord(witness_id) + .map_err(|e| WitnessResolverError::Other(witness_id, e)) + } + + fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), WitnessResolverError> { + self.inner + .check_chain_net(chain_net) + .map_err(|_| WitnessResolverError::WrongChainNet) + } +} diff --git a/src/indexers/electrum_blocking.rs b/src/indexers/electrum_blocking.rs new file mode 100644 index 00000000..b0181ed5 --- /dev/null +++ b/src/indexers/electrum_blocking.rs @@ -0,0 +1,158 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2024 by +// Zoe Faltibà +// Rewritten in 2024 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2024 LNP/BP Standards Association. 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::iter; +use std::num::NonZeroU32; + +use bp::{ConsensusDecode, Tx, Txid}; +use electrum::{Client, ElectrumApi, Param}; +pub use electrum::{Config, ConfigBuilder, Error, Socks5Config}; +use rgbcore::vm::{WitnessOrd, WitnessPos}; +use rgbcore::ChainNet; + +use super::RgbResolver; + +macro_rules! check { + ($e:expr) => { + $e.map_err(|e| e.to_string())? + }; +} + +impl RgbResolver for Client { + fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), String> { + // check the electrum server is for the correct network + let block_hash = check!(self.block_header(0)).block_hash(); + if chain_net.genesis_block_hash() != block_hash { + return Err(s!("resolver is for a network different from the wallet's one")); + } + // check the electrum server has the required functionality (verbose + // transactions) + let txid = match chain_net { + ChainNet::BitcoinMainnet => { + "33e794d097969002ee05d336686fc03c9e15a597c1b9827669460fac98799036" + } + ChainNet::BitcoinTestnet3 => { + "5e6560fd518aadbed67ee4a55bdc09f19e619544f5511e9343ebba66d2f62653" + } + ChainNet::BitcoinTestnet4 => { + "7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e" + } + ChainNet::BitcoinSignet => { + "8153034f45e695453250a8fb7225a5e545144071d8ed7b0d3211efa1f3c92ad8" + } + ChainNet::BitcoinRegtest => { + "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + } + _ => return Err(s!("only bitcoin is supported")), + }; + if let Err(e) = self.raw_call("blockchain.transaction.get", vec![ + Param::String(txid.to_string()), + Param::Bool(true), + ]) { + if !e + .to_string() + .contains("genesis block coinbase is not considered an ordinary transaction") + { + return Err(s!( + "verbose transactions are unsupported by the provided electrum service" + )); + } + } + Ok(()) + } + + fn resolve_pub_witness_ord(&self, txid: Txid) -> Result { + // We get the height of the tip of blockchain + let header = check!(self.block_headers_subscribe()); + + // Now we get and parse transaction information to get the number of + // confirmations + let tx_details = match self.raw_call("blockchain.transaction.get", vec![ + Param::String(txid.to_string()), + Param::Bool(true), + ]) { + Err(e) + if e.to_string() + .contains("No such mempool or blockchain transaction") => + { + return Ok(WitnessOrd::Archived); + } + Err(e) => return Err(e.to_string()), + Ok(v) => v, + }; + let forward = iter::from_fn(|| self.block_headers_pop().ok().flatten()).count() as isize; + + let Some(confirmations) = tx_details.get("confirmations") else { + return Ok(WitnessOrd::Tentative); + }; + let confirmations = check!(confirmations + .as_u64() + .and_then(|x| u32::try_from(x).ok()) + .ok_or(Error::InvalidResponse(tx_details.clone()))); + if confirmations == 0 { + return Ok(WitnessOrd::Tentative); + } + let block_time = check!(tx_details + .get("blocktime") + .and_then(|v| v.as_i64()) + .ok_or(Error::InvalidResponse(tx_details.clone()))); + + let tip_height = u32::try_from(header.height).map_err(|_| s!("impossible height value"))?; + let height: isize = (tip_height - confirmations) as isize; + const SAFETY_MARGIN: isize = 1; + // first check from expected min to max height + let get_merkle_res = (1..=forward + 1) + // we need this under assumption that electrum was lying due to "DB desynchronization" + // since this have a very low probability we do that after everything else + .chain((1..=SAFETY_MARGIN).flat_map(|i| [i + forward + 1, 1 - i])) + .find_map(|offset| self.transaction_get_merkle(&txid, (height + offset) as usize).ok()) + .ok_or_else(|| s!("transaction can't be located in the blockchain"))?; + + let tx_height = u32::try_from(get_merkle_res.block_height) + .map_err(|_| s!("impossible height value"))?; + + let height = + check!(NonZeroU32::new(tx_height).ok_or(Error::InvalidResponse(tx_details.clone()))); + let pos = check!(WitnessPos::bitcoin(height, block_time) + .ok_or(Error::InvalidResponse(tx_details.clone()))); + + Ok(WitnessOrd::Mined(pos)) + } + + fn resolve_pub_witness(&self, txid: Txid) -> Result, String> { + self.transaction_get_raw(&txid) + .map_err(|e| e.to_string()) + .and_then(|raw_tx| { + Tx::consensus_deserialize(raw_tx) + .map_err(|e| format!("cannot deserialize raw TX - {e}")) + }) + .map(Some) + .or_else(|e| { + if e.contains("No such mempool or blockchain transaction") { + Ok(None) + } else { + Err(e) + } + }) + } +} diff --git a/src/indexers/esplora_blocking.rs b/src/indexers/esplora_blocking.rs new file mode 100644 index 00000000..8b7d0046 --- /dev/null +++ b/src/indexers/esplora_blocking.rs @@ -0,0 +1,68 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2023 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2023 LNP/BP Standards Association. 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::num::NonZeroU32; + +use bp::{Tx, Txid}; +use esplora::BlockingClient; +pub use esplora::{Builder, Config, Error}; +use rgbcore::vm::{WitnessOrd, WitnessPos}; +use rgbcore::ChainNet; + +use super::RgbResolver; + +impl RgbResolver for BlockingClient { + fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), String> { + // check the esplora server is for the correct network + let block_hash = self.block_hash(0)?; + if chain_net.genesis_block_hash() != block_hash { + return Err(s!("resolver is for a network different from the wallet's one")); + } + Ok(()) + } + + fn resolve_pub_witness_ord(&self, txid: Txid) -> Result { + if self.tx(&txid)?.is_none() { + return Ok(WitnessOrd::Archived); + } + let status = self.tx_status(&txid)?; + let ord = match status + .block_height + .and_then(|h| status.block_time.map(|t| (h, t))) + { + Some((h, t)) => { + let height = NonZeroU32::new(h).ok_or(Error::InvalidServerData)?; + WitnessOrd::Mined( + WitnessPos::bitcoin(height, t as i64).ok_or(Error::InvalidServerData)?, + ) + } + None => WitnessOrd::Tentative, + }; + Ok(ord) + } + + fn resolve_pub_witness(&self, txid: Txid) -> Result, String> { + self.tx(&txid).or_else(|e| match e { + Error::TransactionNotFound(_) => Ok(None), + e => Err(e.to_string()), + }) + } +} diff --git a/src/indexers/mempool_blocking.rs b/src/indexers/mempool_blocking.rs new file mode 100644 index 00000000..279e18f6 --- /dev/null +++ b/src/indexers/mempool_blocking.rs @@ -0,0 +1,131 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2023 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2023 LNP/BP Standards Association. 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::{Tx, Txid}; +use esplora::{BlockingClient, Config, Error}; +use rgbcore::vm::WitnessOrd; +use rgbcore::ChainNet; + +use super::RgbResolver; + +#[derive(Clone, Debug)] +/// Represents a client for interacting with a mempool. +// Currently, this client is wrapping an `esplora::BlockingClient` instance. +// If the mempool service changes in the future and is not compatible with +// esplora::BlockingClient, Only the internal implementation needs to be +// modified +pub struct MemPoolClient { + inner: BlockingClient, +} + +impl MemPoolClient { + /// Creates a new `MemPoolClient` instance. + /// + /// # Arguments + /// + /// * `url` - The URL of the mempool server. + /// * `config` - The configuration for the mempool client. + /// + /// # Returns + /// + /// Returns a `Result` containing the `MemPoolClient` instance if + /// successful, or an `Error` if an error occurred. + #[allow(clippy::result_large_err)] + pub fn new(url: &str, config: Config) -> Result { + let inner = BlockingClient::from_config(url, config)?; + Ok(MemPoolClient { inner }) + } +} + +impl RgbResolver for MemPoolClient { + fn check_chain_net(&self, chain_net: ChainNet) -> Result<(), String> { + self.inner.check_chain_net(chain_net) + } + + fn resolve_pub_witness_ord(&self, txid: Txid) -> Result { + self.inner.resolve_pub_witness_ord(txid) + } + + fn resolve_pub_witness(&self, txid: Txid) -> Result, String> { + self.inner.resolve_pub_witness(txid) + } +} + +#[cfg(test)] +mod test { + use esplora::Config; + #[test] + fn test_mempool_client_mainnet_tx() { + let client = super::MemPoolClient::new("https://mempool.space/api", Config::default()) + .expect("Failed to create client"); + let txid = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + .parse() + .unwrap(); + let status = client.inner.tx_status(&txid).unwrap(); + assert_eq!(status.block_height, Some(0)); + assert_eq!(status.block_time, Some(1231006505)); + } + + #[test] + fn test_mempool_client_testnet_tx() { + let client = + super::MemPoolClient::new("https://mempool.space/testnet/api", Config::default()) + .expect("Failed to create client"); + + let txid = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + .parse() + .unwrap(); + let status = client.inner.tx_status(&txid).unwrap(); + assert_eq!(status.block_height, Some(0)); + assert_eq!(status.block_time, Some(1296688602)); + } + + #[test] + fn test_mempool_client_testnet4_tx() { + let client = + super::MemPoolClient::new("https://mempool.space/testnet4/api", Config::default()) + .expect("Failed to create client"); + let txid = "7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e" + .parse() + .unwrap(); + let status = client.inner.tx_status(&txid).unwrap(); + assert_eq!(status.block_height, Some(0)); + assert_eq!(status.block_time, Some(1714777860)); + } + + #[test] + fn test_mempool_client_testnet4_tx_detail() { + let client = + super::MemPoolClient::new("https://mempool.space/testnet4/api", Config::default()) + .expect("Failed to create client"); + let txid = "7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e" + .parse() + .unwrap(); + let tx = client + .inner + .tx(&txid) + .expect("Failed to get tx") + .expect("Tx not found"); + assert!(!tx.inputs.is_empty()); + assert!(!tx.outputs.is_empty()); + assert_eq!(tx.outputs[0].value, 5_000_000_000); + } +} diff --git a/src/containers/disclosure.rs b/src/indexers/mod.rs similarity index 69% rename from src/containers/disclosure.rs rename to src/indexers/mod.rs index b81f83c9..9c108bba 100644 --- a/src/containers/disclosure.rs +++ b/src/indexers/mod.rs @@ -2,10 +2,10 @@ // // SPDX-License-Identifier: Apache-2.0 // -// Written in 2019-2024 by +// Written in 2019-2023 by // Dr Maxim Orlovsky // -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. +// Copyright (C) 2019-2023 LNP/BP Standards Association. 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. @@ -19,5 +19,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -// TODO: Implement disclosures -pub struct Disclosure; +mod any; +#[cfg(feature = "esplora_blocking")] +pub mod esplora_blocking; +#[cfg(feature = "electrum_blocking")] +pub mod electrum_blocking; + +#[cfg(feature = "mempool_blocking")] +pub mod mempool_blocking; + +pub use any::{AnyResolver, RgbResolver}; diff --git a/src/info.rs b/src/info.rs index 2c826714..3c877849 100644 --- a/src/info.rs +++ b/src/info.rs @@ -19,171 +19,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::HashMap; use std::fmt::{self, Debug, Display, Formatter}; -use std::str::FromStr; -use amplify::confinement::TinyOrdSet; use chrono::{DateTime, TimeZone, Utc}; -use rgb::{ChainNet, ContractId, Genesis, Identity, Operation, SchemaId}; -use strict_encoding::stl::{AlphaCapsLodash, AlphaNumLodash}; -use strict_encoding::{FieldName, RString, StrictDeserialize, StrictSerialize, TypeName}; - -use crate::containers::{ - SupplSub, Supplement, SUPPL_ANNOT_IFACE_CLASS, SUPPL_ANNOT_IFACE_FEATURES, -}; -use crate::interface::{Iface, IfaceId, IfaceImpl, IfaceRef, ImplId, VerNo}; -use crate::persistence::SchemaIfaces; -use crate::LIB_NAME_RGB_STD; - -#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From)] -#[wrapper(Deref, Display, FromStr)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct IfaceClassName(RString); - -impl_ident_type!(IfaceClassName); -impl_ident_subtype!(IfaceClassName); -impl_strict_newtype!(IfaceClassName, LIB_NAME_RGB_STD); - -impl StrictSerialize for IfaceClassName {} -impl StrictDeserialize for IfaceClassName {} - -#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default, From)] -#[wrapper(Deref)] -#[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] -pub struct FeatureList(TinyOrdSet); - -impl StrictSerialize for FeatureList {} -impl StrictDeserialize for FeatureList {} - -#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct IfaceInfo { - pub id: IfaceId, - pub version: VerNo, - pub name: TypeName, - pub standard: Option, - pub features: FeatureList, - pub developer: Identity, - pub created_at: DateTime, - pub inherits: Vec, - pub default_op: Option, -} - -impl IfaceInfo { - pub fn new( - iface: &Iface, - names: &HashMap, - suppl: Option<&Supplement>, - ) -> Self { - let mut standard = None; - let mut features = none!(); - if let Some(suppl) = suppl { - standard = - suppl.get_default_opt::(SupplSub::Itself, SUPPL_ANNOT_IFACE_CLASS); - if let Some(list) = - suppl.get_default_opt::(SupplSub::Itself, SUPPL_ANNOT_IFACE_FEATURES) - { - features = list - }; - } - Self::with(iface, standard, features, names) - } - - pub fn with( - iface: &Iface, - standard: Option, - features: FeatureList, - names: &HashMap, - ) -> Self { - IfaceInfo { - id: iface.iface_id(), - version: iface.version, - name: iface.name.clone(), - standard, - features, - developer: iface.developer.clone(), - created_at: Utc - .timestamp_opt(iface.timestamp, 0) - .single() - .unwrap_or_else(Utc::now), - inherits: iface - .inherits - .iter() - .map(|id| { - names - .get(id) - .cloned() - .map(IfaceRef::Name) - .unwrap_or(IfaceRef::Id(*id)) - }) - .collect(), - default_op: iface.default_operation.clone(), - } - } -} - -impl Display for IfaceInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!( - f, - "{}\t", - self.standard - .as_ref() - .map(IfaceClassName::to_string) - .unwrap_or_else(|| s!("~")) - )?; - write!(f, "{: <40}\t", self.name.to_string())?; - write!(f, "{}\t", self.created_at.format("%Y-%m-%d"))?; - write!(f, "{}\t", self.version)?; - writeln!(f, "{}", self.id)?; - - writeln!( - f, - " Features: {}", - self.features - .iter() - .map(FieldName::to_string) - .collect::>() - .join(", ") - )?; - - writeln!( - f, - " Defaults to: {}", - self.default_op - .as_ref() - .map(FieldName::to_string) - .unwrap_or_else(|| s!("~")) - )?; - - writeln!(f, " Developer: {}", self.developer)?; - - writeln!( - f, - " Inherits: {}", - self.inherits - .iter() - .map(|f| format!("{:#}", f)) - .collect::>() - .chunks(5) - .map(|chunk| chunk.join(", ")) - .collect::>() - .join("\n ") - ) - } -} +use rgb::{ChainNet, ContractId, Genesis, Identity, Operation, Schema, SchemaId}; +use strict_encoding::TypeName; #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] #[cfg_attr( @@ -194,27 +34,13 @@ impl Display for IfaceInfo { pub struct SchemaInfo { pub id: SchemaId, pub name: TypeName, - pub developer: Identity, - pub created_at: DateTime, - pub implements: Vec, } impl SchemaInfo { - pub fn with(schema_ifaces: &SchemaIfaces) -> Self { - let schema = &schema_ifaces.schema; + pub fn with(schema: &Schema) -> Self { SchemaInfo { id: schema.schema_id(), name: schema.name.clone(), - developer: schema.developer.clone(), - created_at: Utc - .timestamp_opt(schema.timestamp, 0) - .single() - .unwrap_or_else(Utc::now), - implements: schema_ifaces - .iimpls - .iter() - .map(|(name, iimpl)| ImplInfo::with(name.clone(), iimpl)) - .collect(), } } } @@ -223,53 +49,10 @@ impl Display for SchemaInfo { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{: <24}", self.name.to_string())?; write!(f, "\t{: <80}", self.id.to_string())?; - write!(f, "\t{}", self.created_at.format("%Y-%m-%d"))?; - writeln!(f, "\t{}", self.developer)?; - for info in &self.implements { - write!(f, " {info}")?; - } Ok(()) } } -#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ImplInfo { - pub id: ImplId, - pub iface_id: IfaceId, - pub iface_name: TypeName, - pub developer: Identity, - pub created_at: DateTime, -} - -impl ImplInfo { - pub fn with(iface_name: TypeName, iimpl: &IfaceImpl) -> Self { - ImplInfo { - id: iimpl.impl_id(), - iface_id: iimpl.iface_id, - iface_name, - developer: iimpl.developer.clone(), - created_at: Utc - .timestamp_opt(iimpl.timestamp, 0) - .single() - .unwrap_or_else(Utc::now), - } - } -} - -impl Display for ImplInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{: <24}", self.iface_name.to_string())?; - write!(f, "\t{: <80}", self.id.to_string())?; - write!(f, "\t{}", self.created_at.format("%Y-%m-%d"))?; - writeln!(f, "\t{}", self.developer) - } -} - #[derive(Clone, Eq, PartialEq, Hash, Debug)] #[cfg_attr( feature = "serde", diff --git a/src/interface/builder.rs b/src/interface/builder.rs deleted file mode 100644 index 93c51f9f..00000000 --- a/src/interface/builder.rs +++ /dev/null @@ -1,1150 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// 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. -// -// 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::result_large_err)] - -use std::collections::{BTreeMap, HashSet}; - -use amplify::confinement::{Confined, SmallOrdSet, TinyOrdMap, U16}; -use amplify::{confinement, Wrapper}; -use chrono::Utc; -use invoice::{Allocation, Amount}; -use rgb::validation::Scripts; -use rgb::{ - validation, Assign, AssignmentType, Assignments, AttachState, ChainNet, ContractId, DataState, - ExposedSeal, FungibleType, Genesis, GenesisSeal, GlobalState, GraphSeal, Identity, Input, - Layer1, MetadataError, Opout, OwnedStateSchema, RevealedAttach, RevealedData, RevealedValue, - Schema, Transition, TransitionType, TypedAssigns, -}; -use rgbcore::{GlobalStateSchema, GlobalStateType, MetaType, Metadata, ValencyType}; -use strict_encoding::{FieldName, SerializeError, StrictSerialize}; -use strict_types::{decode, SemId, TypeSystem}; - -use crate::containers::{BuilderSeal, ContainerVer, Contract, ValidConsignment}; -use crate::interface::resolver::DumbResolver; -use crate::interface::{Iface, IfaceImpl, TransitionIface}; -use crate::persistence::PersistedState; - -#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum BuilderError { - /// metadata `{0}` are not known to the schema - MetadataNotFound(FieldName), - - #[from] - #[display(inner)] - MetadataInvalid(MetadataError), - - /// global state `{0}` is not known to the schema. - GlobalNotFound(FieldName), - - /// assignment `{0}` is not known to the schema. - AssignmentNotFound(FieldName), - - /// transition `{0}` is not known to the schema. - TransitionNotFound(FieldName), - - /// unknown owned state name `{0}`. - InvalidStateField(FieldName), - - /// state `{0}` provided to the builder has invalid type. - InvalidStateType(AssignmentType), - - /// interface doesn't specifies default operation name, thus an explicit - /// operation type must be provided with `set_operation_type` method. - NoOperationSubtype, - - /// interface doesn't have a default assignment type. - NoDefaultAssignment, - - /// {0} is not supported by the contract genesis. - InvalidLayer1(Layer1), - - #[from] - #[display(inner)] - StrictEncode(SerializeError), - - #[from] - #[display(inner)] - Reify(decode::Error), - - #[from] - #[display(inner)] - Confinement(confinement::Error), - - #[from] - #[display(inner)] - ContractInconsistency(validation::Status), -} - -#[derive(Clone, Debug)] -pub struct ContractBuilder { - builder: OperationBuilder, - scripts: Scripts, - issuer: Identity, - chain_net: ChainNet, -} - -impl ContractBuilder { - pub fn with( - issuer: Identity, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - types: TypeSystem, - scripts: Scripts, - chain_net: ChainNet, - ) -> Self { - Self { - builder: OperationBuilder::with(iface, schema, iimpl, types), - scripts, - issuer, - chain_net, - } - } - - #[allow(clippy::too_many_arguments)] - pub fn deterministic( - issuer: Identity, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - types: TypeSystem, - scripts: Scripts, - chain_net: ChainNet, - ) -> Self { - Self { - builder: OperationBuilder::deterministic(iface, schema, iimpl, types), - scripts, - issuer, - chain_net, - } - } - - pub fn type_system(&self) -> &TypeSystem { self.builder.type_system() } - - #[inline] - pub fn global_type(&self, name: &FieldName) -> Option { - self.builder.global_type(name) - } - - #[inline] - pub fn valency_type(&self, name: &FieldName) -> Option { - self.builder.valency_type(name) - } - - #[inline] - pub fn valency_name(&self, type_id: ValencyType) -> &FieldName { - self.builder.valency_name(type_id) - } - - #[inline] - pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } - - #[inline] - pub fn add_metadata( - mut self, - name: impl Into, - value: impl StrictSerialize, - ) -> Result { - self.builder = self.builder.add_metadata(name, value)?; - Ok(self) - } - - #[inline] - pub fn add_global_state( - mut self, - name: impl Into, - value: impl StrictSerialize, - ) -> Result { - self.builder = self.builder.add_global_state(name, value)?; - Ok(self) - } - - pub fn add_owned_state_det( - mut self, - name: impl Into, - seal: impl Into>, - state: PersistedState, - ) -> Result { - let seal = seal.into(); - self.builder = self.builder.add_owned_state_det(name, seal, state)?; - Ok(self) - } - - pub fn add_rights( - mut self, - name: impl Into, - seal: impl Into>, - ) -> Result { - let seal = seal.into(); - self.builder = self.builder.add_rights(name, seal)?; - Ok(self) - } - - pub fn add_fungible_state( - mut self, - name: impl Into, - seal: impl Into>, - value: impl Into, - ) -> Result { - let name = name.into(); - let seal = seal.into(); - self.builder = self.builder.add_fungible_state(name, seal, value)?; - Ok(self) - } - - pub fn add_data( - mut self, - name: impl Into, - seal: impl Into>, - value: impl StrictSerialize, - ) -> Result { - let seal = seal.into(); - self.builder = self.builder.add_data(name, seal, value)?; - Ok(self) - } - - pub fn add_data_det( - mut self, - name: impl Into, - seal: impl Into>, - data: RevealedData, - ) -> Result { - let seal = seal.into(); - self.builder = self.builder.add_data_det(name, seal, data)?; - Ok(self) - } - - pub fn add_attachment( - mut self, - name: impl Into, - seal: impl Into>, - attachment: AttachState, - ) -> Result { - let seal = seal.into(); - self.builder = self.builder.add_attachment(name, seal, attachment)?; - Ok(self) - } - - pub fn add_attachment_det( - mut self, - name: impl Into, - seal: impl Into>, - attachment: RevealedAttach, - ) -> Result { - let seal = seal.into(); - self.builder = self.builder.add_attachment_det(name, seal, attachment)?; - Ok(self) - } - - pub fn issue_contract(self) -> Result, BuilderError> { - debug_assert!( - !self.builder.deterministic, - "for issuing deterministic contracts please use issue_contract_det method" - ); - self.issue_contract_raw(Utc::now().timestamp()) - } - - pub fn issue_contract_det( - self, - timestamp: i64, - ) -> Result, BuilderError> { - debug_assert!( - self.builder.deterministic, - "for issuing deterministic contracts please use deterministic constructor" - ); - self.issue_contract_raw(timestamp) - } - - fn issue_contract_raw(self, timestamp: i64) -> Result, BuilderError> { - let (schema, iface, iimpl, global, assignments, types) = self.builder.complete(); - - let genesis = Genesis { - ffv: none!(), - schema_id: schema.schema_id(), - flags: none!(), - timestamp, - chain_net: self.chain_net, - metadata: empty!(), - globals: global, - assignments, - valencies: none!(), - issuer: self.issuer, - validator: none!(), - }; - - let ifaces = tiny_bmap! { iface => iimpl }; - let scripts = Confined::from_iter_checked(self.scripts.into_values()); - - let contract = Contract { - version: ContainerVer::V2, - transfer: false, - terminals: none!(), - genesis, - extensions: none!(), - bundles: none!(), - schema, - ifaces, - attachments: none!(), // TODO: Add support for attachment files - - types, - scripts, - - supplements: none!(), // TODO: Add supplements - signatures: none!(), // TODO: Add signatures - }; - - let valid_contract = contract - .validate(&DumbResolver, self.chain_net) - .map_err(|(status, _)| status)?; - - Ok(valid_contract) - } -} - -#[derive(Clone, Debug)] -pub struct TransitionBuilder { - contract_id: ContractId, - builder: OperationBuilder, - nonce: u64, - transition_type: TransitionType, - inputs: TinyOrdMap, -} - -impl TransitionBuilder { - pub fn blank_transition( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - types: TypeSystem, - ) -> Self { - Self::with(contract_id, iface, schema, iimpl, TransitionType::BLANK, types) - } - - pub fn blank_transition_det( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - types: TypeSystem, - ) -> Self { - Self::deterministic(contract_id, iface, schema, iimpl, TransitionType::BLANK, types) - } - - pub fn default_transition( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - types: TypeSystem, - ) -> Result { - let transition_type = iface - .default_operation - .as_ref() - .and_then(|name| iimpl.transition_type(name)) - .ok_or(BuilderError::NoOperationSubtype)?; - Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types)) - } - - pub fn default_transition_det( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - types: TypeSystem, - ) -> Result { - let transition_type = iface - .default_operation - .as_ref() - .and_then(|name| iimpl.transition_type(name)) - .ok_or(BuilderError::NoOperationSubtype)?; - Ok(Self::deterministic(contract_id, iface, schema, iimpl, transition_type, types)) - } - - pub fn named_transition( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - transition_name: impl Into, - types: TypeSystem, - ) -> Result { - let transition_name = transition_name.into(); - let transition_type = iimpl - .transition_type(&transition_name) - .ok_or(BuilderError::TransitionNotFound(transition_name))?; - Ok(Self::with(contract_id, iface, schema, iimpl, transition_type, types)) - } - - pub fn named_transition_det( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - transition_name: impl Into, - types: TypeSystem, - ) -> Result { - let transition_name = transition_name.into(); - let transition_type = iimpl - .transition_type(&transition_name) - .ok_or(BuilderError::TransitionNotFound(transition_name))?; - Ok(Self::deterministic(contract_id, iface, schema, iimpl, transition_type, types)) - } - - fn with( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - transition_type: TransitionType, - types: TypeSystem, - ) -> Self { - Self { - contract_id, - builder: OperationBuilder::with(iface, schema, iimpl, types), - nonce: u64::MAX, - transition_type, - inputs: none!(), - } - } - - fn deterministic( - contract_id: ContractId, - iface: Iface, - schema: Schema, - iimpl: IfaceImpl, - transition_type: TransitionType, - types: TypeSystem, - ) -> Self { - Self { - contract_id, - builder: OperationBuilder::deterministic(iface, schema, iimpl, types), - nonce: u64::MAX, - transition_type, - inputs: none!(), - } - } - - pub fn type_system(&self) -> &TypeSystem { self.builder.type_system() } - - pub fn transition_type(&self) -> TransitionType { self.transition_type } - - pub fn set_nonce(mut self, nonce: u64) -> Self { - self.nonce = nonce; - self - } - - #[inline] - pub fn add_metadata( - mut self, - name: impl Into, - value: impl StrictSerialize, - ) -> Result { - self.builder = self.builder.add_metadata(name, value)?; - Ok(self) - } - - #[inline] - pub fn add_global_state( - mut self, - name: impl Into, - value: impl StrictSerialize, - ) -> Result { - self.builder = self.builder.add_global_state(name, value)?; - Ok(self) - } - - pub fn add_input(mut self, opout: Opout, state: PersistedState) -> Result { - self.inputs.insert(Input::with(opout), state)?; - Ok(self) - } - - pub fn default_assignment(&self) -> Result<&FieldName, BuilderError> { - self.builder - .transition_iface(self.transition_type) - .default_assignment - .as_ref() - .ok_or(BuilderError::NoDefaultAssignment) - } - - #[inline] - pub fn assignments_type(&self, name: &FieldName) -> Option { - self.builder.assignments_type(name) - } - - #[inline] - pub fn global_type(&self, name: &FieldName) -> Option { - self.builder.global_type(name) - } - - #[inline] - pub fn valency_type(&self, name: &FieldName) -> Option { - self.builder.valency_type(name) - } - - pub fn valency_name(&self, type_id: ValencyType) -> &FieldName { - self.builder.valency_name(type_id) - } - - pub fn meta_name(&self, type_id: MetaType) -> &FieldName { self.builder.meta_name(type_id) } - - pub fn add_owned_state_det( - mut self, - name: impl Into, - seal: impl Into>, - state: PersistedState, - ) -> Result { - self.builder = self.builder.add_owned_state_det(name, seal, state)?; - Ok(self) - } - - pub fn add_owned_state_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - state: PersistedState, - ) -> Result { - self.builder = self.builder.add_owned_state_raw(type_id, seal, state)?; - Ok(self) - } - - pub fn add_rights( - mut self, - name: impl Into, - seal: impl Into>, - ) -> Result { - self.builder = self.builder.add_rights(name, seal)?; - Ok(self) - } - - pub fn add_fungible_default_state( - self, - seal: impl Into>, - value: u64, - ) -> Result { - let assignment_name = self.default_assignment()?.clone(); - self.add_fungible_state(assignment_name, seal.into(), value) - } - - pub fn add_fungible_state( - mut self, - name: impl Into, - seal: impl Into>, - value: impl Into, - ) -> Result { - self.builder = self.builder.add_fungible_state(name.into(), seal, value)?; - Ok(self) - } - - pub fn add_fungible_state_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - value: impl Into, - ) -> Result { - let state = RevealedValue::new(value.into()); - self.builder = self.builder.add_fungible_state_raw(type_id, seal, state)?; - Ok(self) - } - - pub fn add_data( - mut self, - name: impl Into, - seal: impl Into>, - value: impl StrictSerialize, - ) -> Result { - self.builder = self.builder.add_data(name, seal, value)?; - Ok(self) - } - - pub fn add_data_det( - mut self, - name: impl Into, - seal: impl Into>, - data: RevealedData, - ) -> Result { - self.builder = self.builder.add_data_det(name, seal, data)?; - Ok(self) - } - - pub fn add_data_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - allocation: impl Into, - blinding: u64, - ) -> Result { - let revealed_state = RevealedData::with_salt(allocation.into(), blinding.into()); - self.builder = self.builder.add_data_raw(type_id, seal, revealed_state)?; - Ok(self) - } - - pub fn add_data_default( - self, - seal: impl Into>, - value: impl StrictSerialize, - ) -> Result { - let assignment_name = self.default_assignment()?.clone(); - self.add_data(assignment_name, seal.into(), value) - } - - pub fn add_attachment( - mut self, - name: impl Into, - seal: impl Into>, - attachment: AttachState, - ) -> Result { - self.builder = self.builder.add_attachment(name, seal, attachment)?; - Ok(self) - } - - pub fn add_attachment_det( - mut self, - name: impl Into, - seal: impl Into>, - attachment: RevealedAttach, - ) -> Result { - self.builder = self.builder.add_attachment_det(name, seal, attachment)?; - Ok(self) - } - - pub fn has_inputs(&self) -> bool { !self.inputs.is_empty() } - - pub fn complete_transition(self) -> Result { - let (_, _, _, global, assignments, _) = self.builder.complete(); - - let transition = Transition { - ffv: none!(), - contract_id: self.contract_id, - nonce: self.nonce, - transition_type: self.transition_type, - metadata: empty!(), - globals: global, - inputs: SmallOrdSet::from_iter_checked(self.inputs.into_keys()).into(), - assignments, - valencies: none!(), - witness: none!(), - validator: none!(), - }; - - // TODO: Validate against schema - - Ok(transition) - } -} - -#[derive(Clone, Debug)] -pub struct OperationBuilder { - // TODO: use references instead of owned values - schema: Schema, - iface: Iface, - iimpl: IfaceImpl, - deterministic: bool, - - global: GlobalState, - meta: Metadata, - rights: TinyOrdMap>, 1, U16>>, - fungible: - TinyOrdMap, RevealedValue>, 1, U16>>, - data: TinyOrdMap, RevealedData>, 1, U16>>, - attachments: - TinyOrdMap, RevealedAttach>, 1, U16>>, - // TODO: add valencies - types: TypeSystem, -} - -impl OperationBuilder { - fn with(iface: Iface, schema: Schema, iimpl: IfaceImpl, types: TypeSystem) -> Self { - OperationBuilder { - schema, - iface, - iimpl, - deterministic: false, - - global: none!(), - meta: none!(), - rights: none!(), - fungible: none!(), - attachments: none!(), - data: none!(), - - types, - } - } - - fn deterministic(iface: Iface, schema: Schema, iimpl: IfaceImpl, types: TypeSystem) -> Self { - OperationBuilder { - schema, - iface, - iimpl, - deterministic: true, - - global: none!(), - meta: none!(), - rights: none!(), - fungible: none!(), - attachments: none!(), - data: none!(), - - types, - } - } - - fn type_system(&self) -> &TypeSystem { &self.types } - - fn transition_iface(&self, ty: TransitionType) -> &TransitionIface { - let transition_name = self.iimpl.transition_name(ty).expect("reverse type"); - self.iface - .transitions - .get(transition_name) - .expect("internal inconsistency") - } - - fn assignments_type(&self, name: &FieldName) -> Option { - self.iimpl.assignments_type(name) - } - - fn meta_type(&self, name: &FieldName) -> Option { self.iimpl.meta_type(name) } - - fn meta_name(&self, ty: MetaType) -> &FieldName { - self.iimpl.meta_name(ty).expect("internal inconsistency") - } - - fn global_type(&self, name: &FieldName) -> Option { - self.iimpl.global_type(name) - } - - fn valency_type(&self, name: &FieldName) -> Option { - self.iimpl.valency_type(name) - } - - fn valency_name(&self, ty: ValencyType) -> &FieldName { - self.iimpl.valency_name(ty).expect("internal inconsistency") - } - - #[inline] - fn state_schema(&self, type_id: AssignmentType) -> &OwnedStateSchema { - self.schema - .owned_types - .get(&type_id) - .expect("schema should match interface: must be checked by the constructor") - } - - #[inline] - fn meta_schema(&self, type_id: MetaType) -> &SemId { - self.schema - .meta_types - .get(&type_id) - .expect("schema should match interface: must be checked by the constructor") - } - - #[inline] - fn global_schema(&self, type_id: GlobalStateType) -> &GlobalStateSchema { - self.schema - .global_types - .get(&type_id) - .expect("schema should match interface: must be checked by the constructor") - } - - pub fn add_metadata( - mut self, - name: impl Into, - value: impl StrictSerialize, - ) -> Result { - let name = name.into(); - let serialized = value.to_strict_serialized::<{ u16::MAX as usize }>()?; - - let Some(type_id) = self.meta_type(&name) else { - return Err(BuilderError::MetadataNotFound(name)); - }; - - let sem_id = self.meta_schema(type_id); - self.types.strict_deserialize_type(*sem_id, &serialized)?; - self.meta.add_value(type_id, serialized.into())?; - Ok(self) - } - - pub fn add_global_state( - mut self, - name: impl Into, - value: impl StrictSerialize, - ) -> Result { - let name = name.into(); - let serialized = value.to_strict_serialized::<{ u16::MAX as usize }>()?; - - // Check value matches type requirements - let Some(type_id) = self.global_type(&name) else { - return Err(BuilderError::GlobalNotFound(name)); - }; - let sem_id = self.global_schema(type_id).sem_id; - self.types.strict_deserialize_type(sem_id, &serialized)?; - - self.global.add_state(type_id, serialized.into())?; - - Ok(self) - } - - fn add_owned_state_det( - self, - name: impl Into, - seal: impl Into>, - state: PersistedState, - ) -> Result { - debug_assert!( - self.deterministic, - "to add owned state in deterministic way the builder has to be created using \ - deterministic constructor" - ); - let name = name.into(); - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name.clone()))?; - self.add_owned_state_raw(type_id, seal, state) - } - - fn add_owned_state_raw( - self, - type_id: AssignmentType, - seal: impl Into>, - state: PersistedState, - ) -> Result { - match state { - PersistedState::Void => self.add_rights_raw(type_id, seal), - PersistedState::Amount(value) => { - self.add_fungible_state_raw(type_id, seal, RevealedValue::new(value)) - } - PersistedState::Data(data, salt) => { - self.add_data_raw(type_id, seal, RevealedData::with_salt(data, salt)) - } - PersistedState::Attachment(attach, salt) => self.add_attachment_raw( - type_id, - seal, - RevealedAttach::with_salt(attach.id, attach.media_type, salt), - ), - } - } - - fn add_rights( - self, - name: impl Into, - seal: impl Into>, - ) -> Result { - let name = name.into(); - - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - self.add_rights_raw(type_id, seal) - } - - fn add_rights_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - ) -> Result { - let state_schema = self.state_schema(type_id); - if *state_schema != OwnedStateSchema::Declarative { - return Err(BuilderError::InvalidStateType(type_id)); - } - - let seal = seal.into(); - match self.rights.get_mut(&type_id) { - Some(assignments) => { - assignments.push(seal)?; - } - None => { - self.rights.insert(type_id, Confined::with(seal))?; - } - } - - Ok(self) - } - - fn add_fungible_state( - self, - name: impl Into, - seal: impl Into>, - value: impl Into, - ) -> Result { - let name = name.into(); - - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - let state = RevealedValue::new(value.into()); - self.add_fungible_state_raw(type_id, seal, state) - } - - fn add_fungible_state_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - state: RevealedValue, - ) -> Result { - let state_schema = self.state_schema(type_id); - if *state_schema != OwnedStateSchema::Fungible(FungibleType::Unsigned64Bit) { - return Err(BuilderError::InvalidStateType(type_id)); - } - - let seal = seal.into(); - match self.fungible.get_mut(&type_id) { - Some(assignments) => { - assignments.insert(seal, state)?; - } - None => { - self.fungible - .insert(type_id, Confined::with((seal, state)))?; - } - } - - Ok(self) - } - - fn add_data( - self, - name: impl Into, - seal: impl Into>, - value: impl StrictSerialize, - ) -> Result { - debug_assert!( - !self.deterministic, - "for adding state to deterministic contracts you have to use add_*_det methods" - ); - - let name = name.into(); - let serialized = value.to_strict_serialized::()?; - let state = DataState::from(serialized); - - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - self.add_data_raw(type_id, seal, RevealedData::new_random_salt(state)) - } - - fn add_data_det( - self, - name: impl Into, - seal: impl Into>, - state: RevealedData, - ) -> Result { - debug_assert!( - self.deterministic, - "to add owned state in deterministic way the builder has to be created using \ - deterministic constructor" - ); - - let name = name.into(); - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - self.add_data_raw(type_id, seal, state) - } - - fn add_data_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - state: RevealedData, - ) -> Result { - let state_schema = self.state_schema(type_id); - if let OwnedStateSchema::Structured(_) = *state_schema { - let seal = seal.into(); - match self.data.get_mut(&type_id) { - Some(assignments) => { - assignments.insert(seal, state)?; - } - None => { - self.data.insert(type_id, Confined::with((seal, state)))?; - } - } - } else { - return Err(BuilderError::InvalidStateType(type_id)); - } - Ok(self) - } - - fn add_attachment( - self, - name: impl Into, - seal: impl Into>, - state: AttachState, - ) -> Result { - debug_assert!( - !self.deterministic, - "for adding state to deterministic contracts you have to use add_*_det methods" - ); - - let name = name.into(); - - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - self.add_attachment_raw( - type_id, - seal, - RevealedAttach::new_random_salt(state.id, state.media_type), - ) - } - - fn add_attachment_det( - self, - name: impl Into, - seal: impl Into>, - state: RevealedAttach, - ) -> Result { - debug_assert!( - self.deterministic, - "to add owned state in deterministic way the builder has to be created using \ - deterministic constructor" - ); - - let name = name.into(); - - let type_id = self - .assignments_type(&name) - .ok_or(BuilderError::AssignmentNotFound(name))?; - - self.add_attachment_raw(type_id, seal, state) - } - - fn add_attachment_raw( - mut self, - type_id: AssignmentType, - seal: impl Into>, - state: RevealedAttach, - ) -> Result { - let state_schema = self.state_schema(type_id); - if let OwnedStateSchema::Attachment(_) = *state_schema { - let seal = seal.into(); - match self.attachments.get_mut(&type_id) { - Some(assignments) => { - assignments.insert(seal, state)?; - } - None => { - self.attachments - .insert(type_id, Confined::with((seal, state)))?; - } - } - } else { - return Err(BuilderError::InvalidStateType(type_id)); - } - Ok(self) - } - - fn complete(self) -> (Schema, Iface, IfaceImpl, GlobalState, Assignments, TypeSystem) { - let owned_state = self.fungible.into_iter().map(|(id, vec)| { - let vec = vec - .into_iter() - .map(|(seal, value)| match seal { - BuilderSeal::Revealed(seal) => Assign::Revealed { - seal, - state: value, - lock: none!(), - }, - BuilderSeal::Concealed(seal) => Assign::ConfidentialSeal { - seal, - state: value, - lock: none!(), - }, - }) - .collect::>(); - let state = Confined::try_from_iter(vec).expect("at least one element"); - let state = TypedAssigns::Fungible(state); - (id, state) - }); - let owned_data = self.data.into_iter().map(|(id, vec)| { - let vec_data = vec.into_iter().map(|(seal, value)| match seal { - BuilderSeal::Revealed(seal) => Assign::Revealed { - seal, - state: value, - lock: none!(), - }, - BuilderSeal::Concealed(seal) => Assign::ConfidentialSeal { - seal, - state: value, - lock: none!(), - }, - }); - let state_data = Confined::try_from_iter(vec_data).expect("at least one element"); - let state_data = TypedAssigns::Structured(state_data); - (id, state_data) - }); - let owned_rights = self.rights.into_iter().map(|(id, vec)| { - let vec_data = vec.into_iter().map(|seal| match seal { - BuilderSeal::Revealed(seal) => Assign::Revealed { - seal, - state: none!(), - lock: none!(), - }, - BuilderSeal::Concealed(seal) => Assign::ConfidentialSeal { - seal, - state: none!(), - lock: none!(), - }, - }); - let state_data = Confined::try_from_iter(vec_data).expect("at least one element"); - let state_data = TypedAssigns::Declarative(state_data); - (id, state_data) - }); - let owned_attachments = self.attachments.into_iter().map(|(id, vec)| { - let vec_data = vec.into_iter().map(|(seal, value)| match seal { - BuilderSeal::Revealed(seal) => Assign::Revealed { - seal, - state: value, - lock: none!(), - }, - BuilderSeal::Concealed(seal) => Assign::ConfidentialSeal { - seal, - state: value, - lock: none!(), - }, - }); - let state_data = Confined::try_from_iter(vec_data).expect("at least one element"); - let state_data = TypedAssigns::Attachment(state_data); - (id, state_data) - }); - - let owned_state = Confined::try_from_iter(owned_state).expect("same size"); - let owned_data = Confined::try_from_iter(owned_data).expect("same size"); - let owned_rights = Confined::try_from_iter(owned_rights).expect("same size"); - let owned_attachments = Confined::try_from_iter(owned_attachments).expect("same size"); - - let mut assignments = Assignments::from_inner(owned_state); - assignments - .extend(Assignments::from_inner(owned_data).into_inner()) - .expect("too many assignments"); - assignments - .extend(Assignments::from_inner(owned_rights).into_inner()) - .expect("too many assignments"); - assignments - .extend(Assignments::from_inner(owned_attachments).into_inner()) - .expect("too many assignments"); - - (self.schema, self.iface, self.iimpl, self.global, assignments, self.types) - } -} diff --git a/src/interface/contractum.rs b/src/interface/contractum.rs deleted file mode 100644 index 107dc970..00000000 --- a/src/interface/contractum.rs +++ /dev/null @@ -1,347 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// 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. -// -// 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::HashMap; -use std::fmt; -use std::fmt::{Display, Formatter}; - -use amplify::confinement::TinyOrdSet; -use rgb::Occurrences; -use strict_encoding::{FieldName, TypeName, VariantName}; -use strict_types::{SemId, SymbolicSys}; - -use super::{ - ArgMap, ExtensionIface, GenesisIface, Iface, IfaceId, Modifier, OwnedIface, TransitionIface, -}; - -struct ArgMapDisplay<'a>(&'a ArgMap); - -impl Display for ArgMapDisplay<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - for (i, (name, occ)) in self.0.iter().enumerate() { - if i > 0 { - f.write_str(", ")? - } - write!(f, "{name}")?; - match occ { - Occurrences::Once => Ok(()), - Occurrences::NoneOrOnce => write!(f, "(?)"), - Occurrences::NoneOrMore => write!(f, "(*)"), - Occurrences::OnceOrMore => write!(f, "(+)"), - Occurrences::NoneOrUpTo(to) => write!(f, "(..{to})"), - Occurrences::OnceOrUpTo(to) => write!(f, "(1..{to})"), - Occurrences::Exactly(v) => write!(f, "({v})"), - Occurrences::Range(r) => write!(f, "({}..{})", r.start(), r.end()), - }?; - } - Ok(()) - } -} - -struct OpIfaceDisplay<'a> { - metadata: &'a TinyOrdSet, - globals: &'a ArgMap, - assignments: &'a ArgMap, - valencies: &'a TinyOrdSet, - errors: &'a TinyOrdSet, -} - -impl<'a> OpIfaceDisplay<'a> { - fn genesis(op: &'a GenesisIface) -> Self { - Self { - metadata: &op.metadata, - globals: &op.globals, - assignments: &op.assignments, - valencies: &op.valencies, - errors: &op.errors, - } - } - - fn transition(op: &'a TransitionIface) -> Self { - Self { - metadata: &op.metadata, - globals: &op.globals, - assignments: &op.assignments, - valencies: &op.valencies, - errors: &op.errors, - } - } - - fn extension(op: &'a ExtensionIface) -> Self { - Self { - metadata: &op.metadata, - globals: &op.globals, - assignments: &op.assignments, - valencies: &op.valencies, - errors: &op.errors, - } - } -} - -impl Display for OpIfaceDisplay<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if !self.errors.is_empty() { - write!(f, "\t\terrors: ")?; - for (i, name) in self.errors.iter().enumerate() { - if i > 0 { - f.write_str(", ")?; - } - write!(f, "{name}")?; - } - writeln!(f)?; - } - - if !self.metadata.is_empty() { - write!(f, "\t\tmeta: ")?; - for (i, meta) in self.metadata.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{meta}")?; - } - writeln!(f)?; - } - if !self.globals.is_empty() { - writeln!(f, "\t\tglobals: {}", ArgMapDisplay(self.globals))?; - } - if !self.valencies.is_empty() { - write!(f, "\t\tvalencies: ")?; - for (i, name) in self.valencies.iter().enumerate() { - if i > 0 { - f.write_str(", ")? - } - write!(f, "{name}")?; - } - writeln!(f)?; - } - if !self.assignments.is_empty() { - writeln!(f, "\t\tassigns: {}", ArgMapDisplay(self.assignments))?; - } - Ok(()) - } -} - -pub struct IfaceDisplay<'a> { - iface: &'a Iface, - externals: &'a HashMap, - types: &'a SymbolicSys, -} - -impl<'a> IfaceDisplay<'a> { - pub fn new( - iface: &'a Iface, - externals: &'a HashMap, - types: &'a SymbolicSys, - ) -> Self { - Self { - iface, - types, - externals, - } - } -} - -impl Display for IfaceDisplay<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - fn sugar(f: &mut Formatter<'_>, required: bool, multiple: bool) -> fmt::Result { - match (required, multiple) { - (true, true) => write!(f, "(+)"), - (false, false) => write!(f, "(?)"), - (false, true) => write!(f, "(*)"), - _ => Ok(()), - } - } - fn resolve(f: &mut Formatter<'_>, types: &SymbolicSys, id: SemId) -> fmt::Result { - match types.lookup(id) { - Some(fqn) => write!(f, "{fqn}"), - None => write!(f, "{id:-} -- type name unknown"), - } - } - fn opsugar( - f: &mut Formatter<'_>, - pred: &str, - name: Option<&FieldName>, - modifier: Modifier, - optional: bool, - default: bool, - ) -> fmt::Result { - write!(f, "\t{pred}")?; - if let Some(name) = name { - write!(f, " {name}")?; - } - let mut modifiers = vec![]; - if !optional { - modifiers.push("required"); - } - if default { - modifiers.push("default"); - } - match modifier { - Modifier::Final => modifiers.push("final"), - Modifier::Abstract => modifiers.push("abstract"), - Modifier::Override => modifiers.push("override"), - } - - if !modifiers.is_empty() { - f.write_str(": ")?; - } - for (i, name) in modifiers.into_iter().enumerate() { - if i > 0 { - f.write_str(", ")?; - } - f.write_str(name)?; - } - writeln!(f) - } - - writeln!(f, "@version({:#})", self.iface.version)?; - writeln!(f, "@id({})", self.iface.iface_id())?; - if !self.iface.developer.is_anonymous() { - writeln!(f, "@developer(\"{}\")", self.iface.developer)?; - } - writeln!(f, "@timestamp({})", self.iface.timestamp)?; - write!(f, "interface {}", self.iface.name)?; - if !self.iface.inherits.is_empty() { - f.write_str(": ")?; - for (index, id) in self.iface.inherits.iter().enumerate() { - if index > 0 { - f.write_str(", ")?; - } - match self.externals.get(id) { - Some(name) => write!(f, "{name}")?, - None => writeln!(f, "{id:-}")?, - } - } - } - writeln!(f)?; - - for (fname, semid) in &self.iface.metadata { - write!(f, "\tmeta {fname}: ")?; - match self.types.lookup(*semid) { - Some(fqn) => write!(f, "{fqn}"), - None => write!(f, "{semid} -- type name is unknown"), - }?; - writeln!(f)?; - } - if !self.iface.metadata.is_empty() { - writeln!(f)?; - } - - for (fname, g) in &self.iface.global_state { - write!(f, "\tglobal {fname}")?; - sugar(f, g.required, g.multiple)?; - write!(f, ": ")?; - match g.sem_id { - Some(id) => resolve(f, self.types, id)?, - None => write!(f, "Any")?, - } - writeln!(f)?; - } - writeln!(f)?; - - for (fname, a) in &self.iface.assignments { - write!(f, "\t")?; - match a.public { - true => write!(f, "public ")?, - false => write!(f, "owned ")?, - } - write!(f, "{fname}")?; - sugar(f, a.required, a.multiple)?; - f.write_str(": ")?; - match a.owned_state { - OwnedIface::Any => write!(f, "AnyType")?, - OwnedIface::Amount => write!(f, "Zk64")?, - OwnedIface::AnyData => write!(f, "Any")?, - OwnedIface::AnyAttach => write!(f, "AnyAttachment")?, - OwnedIface::Rights => write!(f, "Rights")?, - OwnedIface::Data(id) => resolve(f, self.types, id)?, - } - writeln!(f)?; - } - if !self.iface.assignments.is_empty() { - writeln!(f)?; - } - - for (fname, v) in &self.iface.valencies { - write!(f, "\tvalency {fname}")?; - if !v.required { - write!(f, "(?)")?; - } - writeln!(f)?; - } - if !self.iface.valencies.is_empty() { - writeln!(f)?; - } - - for (name, descr) in &self.iface.errors { - writeln!(f, "\terror {name}")?; - writeln!(f, "\t\t\"{descr}\"")?; - } - if !self.iface.errors.is_empty() { - writeln!(f)?; - } - - let op = OpIfaceDisplay::genesis(&self.iface.genesis); - opsugar(f, "genesis", None, self.iface.genesis.modifier, true, false)?; - writeln!(f, "{op}")?; - - for (name, t) in &self.iface.transitions { - let default = self.iface.default_operation.as_ref() == Some(name); - opsugar(f, "transition", Some(name), t.modifier, t.optional, default)?; - - let op = OpIfaceDisplay::transition(t); - write!(f, "{op}")?; - - if let Some(ref d) = t.default_assignment { - writeln!(f, "\t\tdefault: {d}")?; - } - - writeln!(f, "\t\tinputs: {}", ArgMapDisplay(&t.inputs))?; - - writeln!(f)?; - } - - for (name, e) in &self.iface.extensions { - let default = self.iface.default_operation.as_ref() == Some(name); - opsugar(f, "extension", Some(name), e.modifier, e.optional, default)?; - - let op = OpIfaceDisplay::extension(e); - write!(f, "{op}")?; - - if let Some(ref d) = e.default_assignment { - writeln!(f, "\t\tdefault: {d}")?; - } - - write!(f, "\t\tredeems: ")?; - for (i, name) in e.redeems.iter().enumerate() { - if i > 0 { - f.write_str(", ")? - } - write!(f, "{name}")?; - } - writeln!(f)?; - - writeln!(f)?; - } - - Ok(()) - } -} diff --git a/src/interface/iface.rs b/src/interface/iface.rs deleted file mode 100644 index e765f691..00000000 --- a/src/interface/iface.rs +++ /dev/null @@ -1,694 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// 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. -// -// 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::HashMap; -use std::fmt::{self, Debug, Display, Formatter}; -use std::hash::{Hash, Hasher}; -use std::str::FromStr; - -use amplify::confinement::{TinyOrdMap, TinyOrdSet, TinyString, TinyVec}; -use amplify::{ByteArray, Bytes32}; -use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use chrono::{DateTime, TimeZone, Utc}; -use commit_verify::{CommitId, CommitmentId, DigestExt, Sha256}; -use rgb::{ContractId, Identity, Occurrences, SchemaId, Txid}; -use strict_encoding::{ - FieldName, StrictDecode, StrictDeserialize, StrictDumb, StrictEncode, StrictSerialize, - StrictType, TypeName, VariantName, -}; -use strict_types::{SemId, SymbolicSys, TypeLib}; - -use crate::interface::{ContractIface, IfaceDisplay, IfaceImpl, VerNo}; -use crate::persistence::{ContractStateRead, SchemaIfaces}; -use crate::{WitnessInfo, LIB_NAME_RGB_STD}; - -/// Interface identifier. -/// -/// Interface identifier commits to all the interface 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_STD)] -pub struct IfaceId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl From for IfaceId { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for IfaceId { - const TAG: &'static str = "urn:lnp-bp:rgb:interface#2024-02-04"; -} - -impl DisplayBaid64 for IfaceId { - const HRI: &'static str = "rgb:ifc"; - 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 IfaceId {} -impl FromStr for IfaceId { - type Err = Baid64ParseError; - fn from_str(s: &str) -> Result { Self::from_baid64_str(s) } -} -impl Display for IfaceId { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) } -} - -impl_serde_baid64!(IfaceId); - -impl IfaceId { - pub const fn from_array(id: [u8; 32]) -> Self { IfaceId(Bytes32::from_array(id)) } -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, From)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum IfaceRef { - #[from] - #[from(&'static str)] - Name(TypeName), - #[from] - Id(IfaceId), -} - -impl Display for IfaceRef { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - IfaceRef::Name(name) => f.write_str(name.as_str()), - IfaceRef::Id(id) => { - if f.alternate() { - write!(f, "{}", id.to_baid64_mnemonic()) - } else { - write!(f, "{}", id) - } - } - } - } -} - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] -pub enum Req { - Optional, - Required, - NoneOrMore, - OneOrMore, -} - -impl Req { - pub fn is_required(self) -> bool { self == Req::Required || self == Req::OneOrMore } - pub fn is_multiple(self) -> bool { self == Req::NoneOrMore || self == Req::OneOrMore } -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ValencyIface { - pub required: bool, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct GlobalIface { - pub sem_id: Option, - pub required: bool, - pub multiple: bool, -} - -impl GlobalIface { - pub fn any(req: Req) -> Self { - GlobalIface { - sem_id: None, - required: req.is_required(), - multiple: req.is_multiple(), - } - } - pub fn optional(sem_id: SemId) -> Self { - GlobalIface { - sem_id: Some(sem_id), - required: false, - multiple: false, - } - } - pub fn required(sem_id: SemId) -> Self { - GlobalIface { - sem_id: Some(sem_id), - required: true, - multiple: false, - } - } - pub fn none_or_many(sem_id: SemId) -> Self { - GlobalIface { - sem_id: Some(sem_id), - required: false, - multiple: true, - } - } - pub fn one_or_many(sem_id: SemId) -> Self { - GlobalIface { - sem_id: Some(sem_id), - required: true, - multiple: true, - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = order)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct AssignIface { - pub owned_state: OwnedIface, - pub public: bool, - pub required: bool, - pub multiple: bool, -} - -impl AssignIface { - pub fn public(owned_state: OwnedIface, req: Req) -> Self { - AssignIface { - owned_state, - public: true, - required: req.is_required(), - multiple: req.is_multiple(), - } - } - - pub fn private(owned_state: OwnedIface, req: Req) -> Self { - AssignIface { - owned_state, - public: false, - required: req.is_required(), - multiple: req.is_multiple(), - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, tags = order)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub enum OwnedIface { - #[strict_type(dumb)] - Any, - Rights, - Amount, - AnyData, - AnyAttach, - Data(SemId), -} - -impl OwnedIface { - pub fn sem_id(&self) -> Option { - if let Self::Data(id) = self { - Some(*id) - } else { - None - } - } -} - -pub type ArgMap = TinyOrdMap; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD, into_u8, try_from_u8, tags = repr)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[display(lowercase)] -#[repr(u8)] -pub enum Modifier { - Abstract = 0, - Override = 1, - #[default] - Final = 0xFF, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct GenesisIface { - pub modifier: Modifier, - pub metadata: TinyOrdSet, - pub globals: ArgMap, - pub assignments: ArgMap, - pub valencies: TinyOrdSet, - pub errors: TinyOrdSet, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct ExtensionIface { - pub modifier: Modifier, - /// Defines whence schema may omit providing this operation. - pub optional: bool, - pub metadata: TinyOrdSet, - pub globals: ArgMap, - pub assignments: ArgMap, - pub redeems: TinyOrdSet, - pub valencies: TinyOrdSet, - pub errors: TinyOrdSet, - pub default_assignment: Option, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct TransitionIface { - pub modifier: Modifier, - /// Defines whence schema may omit providing this operation. - pub optional: bool, - pub metadata: TinyOrdSet, - pub globals: ArgMap, - pub inputs: ArgMap, - pub assignments: ArgMap, - pub valencies: TinyOrdSet, - pub errors: TinyOrdSet, - pub default_assignment: Option, -} - -/// A class of interfaces: one or several interfaces inheriting from each other. -/// -/// Interface standards like RGB20, RGB21 and RGB25 are actually interface -/// classes. -pub trait IfaceClass: Clone + Default { - const IFACE_NAME: &'static str; - const IFACE_IDS: &'static [IfaceId]; - - type Wrapper: IfaceWrapper; - - fn stl(&self) -> TypeLib; - fn iface(&self) -> Iface; - fn iface_id(&self) -> IfaceId; -} - -/// The instances implementing this trait are used as wrappers around -/// [`ContractIface`] object, allowing a simple API matching the interface class -/// requirements. -pub trait IfaceWrapper { - /// Object which represent concise summary about a contract; - type Info: Clone + Eq + Debug; - - fn with(iface: ContractIface) -> Self; - - /// Constructs information object describing a specific class in terms of - /// the interface class. - fn info(&self) -> Self::Info; - - /// Returns contract id. - fn contract_id(&self) -> ContractId; - - /// Returns schema id of the contract. - fn schema_id(&self) -> SchemaId; - - /// Returns information about a witness, if it is known to the contract state. - fn witness_info(&self, witness_id: Txid) -> Option; -} - -/// Interface definition. -#[derive(Clone, Eq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = IfaceId)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct Iface { - pub version: VerNo, - pub name: TypeName, - pub inherits: TinyVec, // TODO: Replace with TinyIndexSet - pub timestamp: i64, - pub metadata: TinyOrdMap, - pub global_state: TinyOrdMap, - pub assignments: TinyOrdMap, - pub valencies: TinyOrdMap, - pub genesis: GenesisIface, - pub transitions: TinyOrdMap, - pub extensions: TinyOrdMap, - pub default_operation: Option, - pub errors: TinyOrdMap, - pub developer: Identity, -} - -impl PartialEq for Iface { - fn eq(&self, other: &Self) -> bool { self.iface_id() == other.iface_id() } -} - -impl Ord for Iface { - fn cmp(&self, other: &Self) -> Ordering { self.iface_id().cmp(&other.iface_id()) } -} - -impl PartialOrd for Iface { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } -} - -impl Hash for Iface { - fn hash(&self, state: &mut H) { state.write(self.iface_id().as_slice()) } -} - -impl StrictSerialize for Iface {} -impl StrictDeserialize for Iface {} - -impl Iface { - #[inline] - pub fn iface_id(&self) -> IfaceId { self.commit_id() } - - pub fn display<'a>( - &'a self, - externals: &'a HashMap, - sys: &'a SymbolicSys, - ) -> IfaceDisplay<'a> { - IfaceDisplay::new(self, externals, sys) - } - - pub fn types(&self) -> impl Iterator + '_ { - self.metadata - .values() - .copied() - .chain(self.global_state.values().filter_map(|i| i.sem_id)) - .chain( - self.assignments - .values() - .filter_map(|i| i.owned_state.sem_id()), - ) - } - - pub fn find_abstractable_impl<'a>( - &self, - schema_ifaces: &'a SchemaIfaces, - ) -> Option<&'a IfaceImpl> { - schema_ifaces.get(self.iface_id()).or_else(|| { - self.inherits - .iter() - .rev() - .find_map(move |parent| schema_ifaces.get(*parent)) - }) - } - - pub fn check(&self) -> Result<(), Vec> { - let proc_globals = |op_name: &OpName, - globals: &ArgMap, - errors: &mut Vec| { - for (name, occ) in globals { - if let Some(g) = self.global_state.get(name) { - if occ.min_value() > 1 && !g.multiple { - errors.push(IfaceInconsistency::MultipleGlobal( - op_name.clone(), - name.clone(), - )); - } - } else { - errors.push(IfaceInconsistency::UnknownGlobal(op_name.clone(), name.clone())); - } - } - }; - let proc_assignments = - |op_name: &OpName, assignments: &ArgMap, errors: &mut Vec| { - for (name, occ) in assignments { - if let Some(a) = self.assignments.get(name) { - if occ.min_value() > 1 && !a.multiple { - errors.push(IfaceInconsistency::MultipleAssignment( - op_name.clone(), - name.clone(), - )); - } - } else { - errors.push(IfaceInconsistency::UnknownAssignment( - op_name.clone(), - name.clone(), - )); - } - } - }; - let proc_valencies = |op_name: &OpName, - valencies: &TinyOrdSet, - errors: &mut Vec| { - for name in valencies { - if self.valencies.get(name).is_none() { - errors.push(IfaceInconsistency::UnknownValency(op_name.clone(), name.clone())); - } - } - }; - let proc_errors = |op_name: &OpName, - errs: &TinyOrdSet, - errors: &mut Vec| { - for name in errs { - if !self.errors.contains_key(name) { - errors.push(IfaceInconsistency::UnknownError(op_name.clone(), name.clone())); - } - } - }; - - let mut errors = vec![]; - - let now = Utc::now(); - match Utc.timestamp_opt(self.timestamp, 0).single() { - Some(ts) if ts > now => errors.push(IfaceInconsistency::FutureTimestamp(ts)), - None => errors.push(IfaceInconsistency::InvalidTimestamp(self.timestamp)), - _ => {} - } - - for name in &self.genesis.metadata { - if !self.metadata.contains_key(name) { - errors.push(IfaceInconsistency::UnknownMetadata(OpName::Genesis, name.clone())); - } - } - proc_globals(&OpName::Genesis, &self.genesis.globals, &mut errors); - proc_assignments(&OpName::Genesis, &self.genesis.assignments, &mut errors); - proc_valencies(&OpName::Genesis, &self.genesis.valencies, &mut errors); - proc_errors(&OpName::Genesis, &self.genesis.errors, &mut errors); - - for (name, t) in &self.transitions { - let op_name = OpName::Transition(name.clone()); - - for name in &t.metadata { - if !self.metadata.contains_key(name) { - errors.push(IfaceInconsistency::UnknownMetadata(op_name.clone(), name.clone())); - } - } - proc_globals(&op_name, &t.globals, &mut errors); - proc_assignments(&op_name, &t.assignments, &mut errors); - proc_valencies(&op_name, &t.valencies, &mut errors); - proc_errors(&op_name, &t.errors, &mut errors); - - for (name, occ) in &t.inputs { - if let Some(a) = self.assignments.get(name) { - if occ.min_value() > 1 && !a.multiple { - errors.push(IfaceInconsistency::MultipleInputs( - op_name.clone(), - name.clone(), - )); - } - } else { - errors.push(IfaceInconsistency::UnknownInput(op_name.clone(), name.clone())); - } - } - if let Some(ref name) = t.default_assignment { - if t.assignments.get(name).is_none() { - errors - .push(IfaceInconsistency::UnknownDefaultAssignment(op_name, name.clone())); - } - } - } - - for (name, e) in &self.extensions { - let op_name = OpName::Extension(name.clone()); - - for name in &e.metadata { - if !self.metadata.contains_key(name) { - errors.push(IfaceInconsistency::UnknownMetadata(op_name.clone(), name.clone())); - } - } - proc_globals(&op_name, &e.globals, &mut errors); - proc_assignments(&op_name, &e.assignments, &mut errors); - proc_valencies(&op_name, &e.valencies, &mut errors); - proc_errors(&op_name, &e.errors, &mut errors); - - for name in &e.redeems { - if self.valencies.get(name).is_none() { - errors.push(IfaceInconsistency::UnknownRedeem(op_name.clone(), name.clone())); - } - } - if let Some(ref name) = e.default_assignment { - if e.assignments.get(name).is_none() { - errors - .push(IfaceInconsistency::UnknownDefaultAssignment(op_name, name.clone())); - } - } - } - - for name in self.transitions.keys() { - if self.extensions.contains_key(name) { - errors.push(IfaceInconsistency::RepeatedOperationName(name.clone())); - } - } - - if let Some(ref name) = self.default_operation { - if self.transitions.get(name).is_none() && self.extensions.get(name).is_none() { - errors.push(IfaceInconsistency::UnknownDefaultOp(name.clone())); - } - } - - for (name, g) in &self.global_state { - if g.required && self.genesis.globals.get(name).is_none() { - errors.push(IfaceInconsistency::RequiredGlobalAbsent(name.clone())); - } - } - for (name, a) in &self.assignments { - if a.required && self.genesis.assignments.get(name).is_none() { - errors.push(IfaceInconsistency::RequiredAssignmentAbsent(name.clone())); - } - } - for (name, v) in &self.valencies { - if v.required && self.genesis.valencies.get(name).is_none() { - errors.push(IfaceInconsistency::RequiredValencyAbsent(name.clone())); - } - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } - - // TODO: Implement checking interface inheritance. - /* - pub fn check_inheritance<'a>(&self, ifaces: impl IntoIterator) -> Result<(), Vec> { - // check for the depth - } - */ - - // TODO: Implement checking types against presence in a type system. - /* - pub fn check_types(&self, sys: &TypeSystem) -> Result<(), Vec> { - for g in self.global_state.values() { - if let Some(id) = g.sem_id { - - } - } - } - */ -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display)] -pub enum OpName { - #[display("genesis")] - Genesis, - #[display("transition '{0}'")] - Transition(FieldName), - #[display("extension '{0}'")] - Extension(FieldName), -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Error)] -#[display(doc_comments)] -pub enum IfaceInconsistency { - /// timestamp is invalid ({0}). - InvalidTimestamp(i64), - /// timestamp in the future ({0}). - FutureTimestamp(DateTime), - /// unknown global state '{1}' referenced from {0}. - UnknownGlobal(OpName, FieldName), - /// unknown valency '{1}' referenced from {0}. - UnknownValency(OpName, FieldName), - /// unknown input '{1}' referenced from {0}. - UnknownRedeem(OpName, FieldName), - /// unknown assignment '{1}' referenced from {0}. - UnknownAssignment(OpName, FieldName), - /// unknown input '{1}' referenced from {0}. - UnknownInput(OpName, FieldName), - /// unknown error '{1}' referenced from {0}. - UnknownError(OpName, VariantName), - /// unknown default assignment '{1}' referenced from {0}. - UnknownDefaultAssignment(OpName, FieldName), - /// unknown default operation '{0}'. - UnknownDefaultOp(FieldName), - /// unknown metadata '{1}' in {0}. - UnknownMetadata(OpName, FieldName), - /// global state '{1}' must have a unique single value, but operation {0} - /// defines multiple global state of this type. - MultipleGlobal(OpName, FieldName), - /// assignment '{1}' must be unique, but operation {0} defines multiple - /// assignments of this type. - MultipleAssignment(OpName, FieldName), - /// assignment '{1}' is unique, but operation {0} defines multiple inputs of - /// this type, which is not possible. - MultipleInputs(OpName, FieldName), - /// operation name '{0}' is used by both state transition and extension. - RepeatedOperationName(FieldName), - /// global state '{0}' is required, but genesis doesn't define it. - RequiredGlobalAbsent(FieldName), - /// assignment '{0}' is required, but genesis doesn't define it. - RequiredAssignmentAbsent(FieldName), - /// valency '{0}' is required, but genesis doesn't define it. - RequiredValencyAbsent(FieldName), -} diff --git a/src/interface/iimpl.rs b/src/interface/iimpl.rs deleted file mode 100644 index 1e528ed1..00000000 --- a/src/interface/iimpl.rs +++ /dev/null @@ -1,563 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// 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. -// -// 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::HashMap; -use std::fmt::{self, Display, Formatter}; -use std::str::FromStr; - -use amplify::confinement::TinyOrdSet; -use amplify::{ByteArray, Bytes32}; -use baid64::{Baid64ParseError, DisplayBaid64, FromBaid64Str}; -use chrono::{DateTime, TimeZone, Utc}; -use commit_verify::{CommitId, CommitmentId, DigestExt, Sha256}; -use rgb::{ - impl_serde_baid64, AssignmentType, ExtensionType, GlobalStateType, Identity, MetaType, Schema, - SchemaId, TransitionType, ValencyType, -}; -use strict_encoding::{FieldName, StrictDumb, VariantName}; -use strict_types::encoding::{StrictDecode, StrictEncode, StrictType}; - -use crate::interface::iface::IfaceId; -use crate::interface::{Iface, VerNo}; -use crate::{ReservedBytes, LIB_NAME_RGB_STD}; - -pub trait SchemaTypeIndex: - Copy + Eq + Ord + StrictType + StrictDumb + StrictEncode + StrictDecode -{ -} -impl SchemaTypeIndex for u8 {} // Error types -impl SchemaTypeIndex for MetaType {} -impl SchemaTypeIndex for GlobalStateType {} -impl SchemaTypeIndex for AssignmentType {} -impl SchemaTypeIndex for ValencyType {} -impl SchemaTypeIndex for ExtensionType {} -impl SchemaTypeIndex for TransitionType {} - -/// Interface identifier. -/// -/// Interface identifier commits to all the interface 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_STD)] -pub struct ImplId( - #[from] - #[from([u8; 32])] - Bytes32, -); - -impl From for ImplId { - fn from(hasher: Sha256) -> Self { hasher.finish().into() } -} - -impl CommitmentId for ImplId { - const TAG: &'static str = "urn:lnp-bp:rgb:iface-impl#2024-02-04"; -} - -impl DisplayBaid64 for ImplId { - const HRI: &'static str = "rgb:imp"; - 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 ImplId {} -impl FromStr for ImplId { - type Err = Baid64ParseError; - fn from_str(s: &str) -> Result { Self::from_baid64_str(s) } -} -impl Display for ImplId { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { self.fmt_baid64(f) } -} - -impl_serde_baid64!(ImplId); - -impl ImplId { - pub const fn from_array(id: [u8; 32]) -> Self { ImplId(Bytes32::from_array(id)) } -} - -/// Maps certain form of type id (global or owned state or a valency) to a -/// human-readable name. -/// -/// Two distinct [`NamedField`] objects must always have both different state -/// ids and names. -#[derive(Clone, Eq, PartialOrd, Ord, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct NamedField { - pub id: T, - pub name: FieldName, - /// Reserved bytes for storing information about value transformation - /// procedures - pub reserved: ReservedBytes<4usize>, -} - -impl PartialEq for NamedField -where T: SchemaTypeIndex -{ - fn eq(&self, other: &Self) -> bool { self.id == other.id || self.name == other.name } -} - -impl NamedField { - pub fn with(id: T, name: FieldName) -> NamedField { - NamedField { - id, - name, - reserved: default!(), - } - } -} - -/// Maps certain form of type id (global or owned state or a valency) to a -/// human-readable name. -/// -/// Two distinct [`crate::interface::NamedField`] objects must always have both -/// different state ids and names. -#[derive(Clone, Eq, PartialOrd, Ord, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct NamedVariant { - pub id: T, - pub name: VariantName, - /// Reserved bytes for storing information about value transformation - /// procedures - pub reserved: ReservedBytes<4usize>, -} - -impl PartialEq for NamedVariant -where T: SchemaTypeIndex -{ - fn eq(&self, other: &Self) -> bool { self.id == other.id || self.name == other.name } -} - -impl NamedVariant { - pub fn with(id: T, name: VariantName) -> NamedVariant { - NamedVariant { - id, - name, - reserved: default!(), - } - } -} - -/// Maps operation numeric type id to a human-readable name. -/// -/// Two distinct [`NamedType`] objects must always have both different state -/// ids and names. -#[derive(Clone, Eq, PartialOrd, Ord, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct NamedType { - pub id: T, - pub name: FieldName, - /// Reserved bytes for storing information about adaptor procedures - pub reserved: ReservedBytes<0, 4>, -} - -impl PartialEq for NamedType -where T: SchemaTypeIndex -{ - fn eq(&self, other: &Self) -> bool { self.id == other.id || self.name == other.name } -} - -impl NamedType { - pub fn with(id: T, name: impl Into) -> NamedType { - NamedType { - id, - name: name.into(), - reserved: default!(), - } - } -} - -/// Interface implementation for some specific schema. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict, id = ImplId)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct IfaceImpl { - pub version: VerNo, - pub schema_id: SchemaId, - pub iface_id: IfaceId, - pub timestamp: i64, - pub metadata: TinyOrdSet>, - pub global_state: TinyOrdSet>, - pub assignments: TinyOrdSet>, - pub valencies: TinyOrdSet>, - pub transitions: TinyOrdSet>, - pub extensions: TinyOrdSet>, - pub errors: TinyOrdSet>, - pub developer: Identity, -} - -impl IfaceImpl { - #[inline] - pub fn impl_id(&self) -> ImplId { self.commit_id() } - - pub fn meta_name(&self, id: MetaType) -> Option<&FieldName> { - self.metadata - .iter() - .find(|nt| nt.id == id) - .map(|nt| &nt.name) - } - - pub fn meta_type(&self, name: &FieldName) -> Option { - self.metadata - .iter() - .find(|nt| &nt.name == name) - .map(|nt| nt.id) - } - - pub fn global_type(&self, name: &FieldName) -> Option { - self.global_state - .iter() - .find(|nt| &nt.name == name) - .map(|nt| nt.id) - } - - pub fn assignments_type(&self, name: &FieldName) -> Option { - self.assignments - .iter() - .find(|nt| &nt.name == name) - .map(|nt| nt.id) - } - - pub fn transition_type(&self, name: &FieldName) -> Option { - self.transitions - .iter() - .find(|nt| &nt.name == name) - .map(|nt| nt.id) - } - - pub fn extension_name(&self, id: ExtensionType) -> Option<&FieldName> { - self.extensions - .iter() - .find(|nt| nt.id == id) - .map(|nt| &nt.name) - } - - pub fn extension_type(&self, name: &FieldName) -> Option { - self.extensions - .iter() - .find(|nt| &nt.name == name) - .map(|nt| nt.id) - } - - pub fn valency_type(&self, name: &FieldName) -> Option { - self.valencies - .iter() - .find(|nt| &nt.name == name) - .map(|nt| nt.id) - } - - pub fn valency_name(&self, id: ValencyType) -> Option<&FieldName> { - self.valencies - .iter() - .find(|nt| nt.id == id) - .map(|nt| &nt.name) - } - pub fn global_name(&self, id: GlobalStateType) -> Option<&FieldName> { - self.global_state - .iter() - .find(|nt| nt.id == id) - .map(|nt| &nt.name) - } - - pub fn assignment_name(&self, id: AssignmentType) -> Option<&FieldName> { - self.assignments - .iter() - .find(|nt| nt.id == id) - .map(|nt| &nt.name) - } - - pub fn transition_name(&self, id: TransitionType) -> Option<&FieldName> { - self.transitions - .iter() - .find(|nt| nt.id == id) - .map(|nt| &nt.name) - } - - pub fn error_name(&self, errno: u8) -> Option<&VariantName> { - self.errors - .iter() - .find(|nt| nt.id == errno) - .map(|nt| &nt.name) - } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Error)] -#[display(doc_comments)] -pub enum ImplInconsistency { - /// timestamp is invalid ({0}). - InvalidTimestamp(i64), - /// timestamp in the future ({0}). - FutureTimestamp(DateTime), - - /// interface metadata field '{0}' is not resolved by the implementation. - IfaceMetaAbsent(FieldName), - /// implementation metadata field '{0}' maps to an unknown schema metadata - /// type {1}. - SchemaMetaAbsent(FieldName, MetaType), - - /// interface global state field '{0}' is not resolved by the - /// implementation. - IfaceGlobalAbsent(FieldName), - /// implementation global state field '{0}' maps to an unknown schema global - /// state type {1}. - SchemaGlobalAbsent(FieldName, GlobalStateType), - - /// interface owned state field '{0}' is not resolved by the - /// implementation. - IfaceAssignmentAbsent(FieldName), - /// implementation owned state field '{0}' maps to an unknown schema owned - /// state type {1}. - SchemaAssignmentAbsent(FieldName, AssignmentType), - - /// interface valency field '{0}' is not resolved by the implementation. - IfaceValencyAbsent(FieldName), - /// implementation valency field '{0}' maps to an unknown schema valency - /// {1}. - SchemaValencyAbsent(FieldName, ValencyType), - - /// interface state transition name '{0}' is not resolved by the - /// implementation. - IfaceTransitionAbsent(FieldName), - /// implementation state transition name '{0}' maps to an unknown schema - /// state transition type {1}. - SchemaTransitionAbsent(FieldName, TransitionType), - - /// interface state extension name '{0}' is not resolved by the - /// implementation. - IfaceExtensionAbsent(FieldName), - /// implementation state extension name '{0}' maps to an unknown schema - /// state extension type {1}. - SchemaExtensionAbsent(FieldName, ExtensionType), - - /// implementation references unknown interface error '{0}'. - IfaceErrorAbsent(VariantName), - - /// metadata field '{0}' is repeated {1} times - RepeatedMetaData(FieldName, i32), - - /// global state field '{0}' is repeated {1} times - RepeatedGlobalState(FieldName, i32), - - /// assignments field '{0}' is repeated {1} times - RepeatedAssignments(FieldName, i32), - - /// valencies field '{0}' is repeated {1} times - RepeatedValencies(FieldName, i32), - - /// transition field '{0}' is repeated {1} times - RepeatedTransitions(FieldName, i32), - - /// extension field '{0}' is repeated {1} times - RepeatedExtensions(FieldName, i32), -} - -impl IfaceImpl { - pub fn check(&self, iface: &Iface, schema: &Schema) -> Result<(), Vec> { - let mut errors = vec![]; - let now = Utc::now(); - let mut dup_metadata = HashMap::new(); - let mut dup_global_state = HashMap::new(); - let mut dup_assignments = HashMap::new(); - let mut dup_valencies = HashMap::new(); - let mut dup_transitions = HashMap::new(); - let mut dup_extensions = HashMap::new(); - - match Utc.timestamp_opt(self.timestamp, 0).single() { - Some(ts) if ts > now => errors.push(ImplInconsistency::FutureTimestamp(ts)), - None => errors.push(ImplInconsistency::InvalidTimestamp(self.timestamp)), - _ => {} - } - - for name in iface.metadata.keys() { - if self.metadata.iter().all(|field| &field.name != name) { - errors.push(ImplInconsistency::IfaceMetaAbsent(name.clone())); - } - } - for field in &self.metadata { - dup_metadata - .entry(field.name.clone()) - .and_modify(|counter| *counter += 1) - .or_insert(0); - if !schema.meta_types.contains_key(&field.id) { - errors.push(ImplInconsistency::SchemaMetaAbsent(field.name.clone(), field.id)); - } - } - - dup_metadata - .iter() - .filter(|(_, &count)| count > 1) - .for_each(|(field_name, &count)| { - errors.push(ImplInconsistency::RepeatedMetaData(field_name.clone(), count)); - }); - - for name in iface.global_state.keys() { - if self.global_state.iter().all(|field| &field.name != name) { - errors.push(ImplInconsistency::IfaceGlobalAbsent(name.clone())); - } - } - for field in &self.global_state { - dup_global_state - .entry(field.name.clone()) - .and_modify(|counter| *counter += 1) - .or_insert(0); - if !schema.global_types.contains_key(&field.id) { - errors.push(ImplInconsistency::SchemaGlobalAbsent(field.name.clone(), field.id)); - } - } - - dup_global_state - .iter() - .filter(|(_, &count)| count > 1) - .for_each(|(field_name, &count)| { - errors.push(ImplInconsistency::RepeatedGlobalState(field_name.clone(), count)); - }); - - for name in iface.assignments.keys() { - if self.assignments.iter().all(|field| &field.name != name) { - errors.push(ImplInconsistency::IfaceAssignmentAbsent(name.clone())); - } - } - for field in &self.assignments { - dup_assignments - .entry(field.name.clone()) - .and_modify(|counter| *counter += 1) - .or_insert(0); - if !schema.owned_types.contains_key(&field.id) { - errors - .push(ImplInconsistency::SchemaAssignmentAbsent(field.name.clone(), field.id)); - } - } - - dup_assignments - .iter() - .filter(|(_, &count)| count > 1) - .for_each(|(field_name, &count)| { - errors.push(ImplInconsistency::RepeatedAssignments(field_name.clone(), count)); - }); - - for name in iface.valencies.keys() { - if self.valencies.iter().all(|field| &field.name != name) { - errors.push(ImplInconsistency::IfaceValencyAbsent(name.clone())); - } - } - for field in &self.valencies { - dup_valencies - .entry(field.name.clone()) - .and_modify(|counter| *counter += 1) - .or_insert(0); - - if !schema.valency_types.contains(&field.id) { - errors.push(ImplInconsistency::SchemaValencyAbsent(field.name.clone(), field.id)); - } - } - dup_valencies - .iter() - .filter(|(_, &count)| count > 1) - .for_each(|(field_name, &count)| { - errors.push(ImplInconsistency::RepeatedValencies(field_name.clone(), count)); - }); - - for name in iface.transitions.keys() { - if self.transitions.iter().all(|field| &field.name != name) { - errors.push(ImplInconsistency::IfaceTransitionAbsent(name.clone())); - } - } - for field in &self.transitions { - dup_transitions - .entry(field.name.clone()) - .and_modify(|counter| *counter += 1) - .or_insert(0); - - if !schema.transitions.contains_key(&field.id) { - errors - .push(ImplInconsistency::SchemaTransitionAbsent(field.name.clone(), field.id)); - } - } - - dup_transitions - .iter() - .filter(|(_, &count)| count > 1) - .for_each(|(field_name, &count)| { - errors.push(ImplInconsistency::RepeatedTransitions(field_name.clone(), count)); - }); - - for name in iface.extensions.keys() { - if self.extensions.iter().all(|field| &field.name != name) { - errors.push(ImplInconsistency::IfaceExtensionAbsent(name.clone())); - } - } - for field in &self.extensions { - dup_extensions - .entry(field.name.clone()) - .and_modify(|counter| *counter += 1) - .or_insert(0); - - if !schema.extensions.contains_key(&field.id) { - errors.push(ImplInconsistency::SchemaExtensionAbsent(field.name.clone(), field.id)); - } - } - - dup_extensions - .iter() - .filter(|(_, &count)| count > 1) - .for_each(|(field_name, &count)| { - errors.push(ImplInconsistency::RepeatedExtensions(field_name.clone(), count)); - }); - - for var in &self.errors { - if iface.errors.keys().all(|name| name != &var.name) { - errors.push(ImplInconsistency::IfaceErrorAbsent(var.name.clone())); - } - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } -} diff --git a/src/interface/inheritance.rs b/src/interface/inheritance.rs deleted file mode 100644 index 518c0595..00000000 --- a/src/interface/inheritance.rs +++ /dev/null @@ -1,737 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// 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. -// -// 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::confinement::{Confined, TinyOrdMap, TinyOrdSet}; -use rgb::{ - AssignmentType, ExtensionType, GlobalStateType, Occurrences, OpFullType, OpSchema, Schema, - TransitionType, ValencyType, -}; -use strict_encoding::{FieldName, TypeName}; - -use crate::interface::{ - ExtensionIface, GenesisIface, Iface, IfaceImpl, Modifier, OpName, OwnedIface, TransitionIface, -}; - -#[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 InheritanceFailure { - /// invalid schema - no match with root schema requirements for global state - /// type #{0}. - GlobalStateMismatch(GlobalStateType), - /// invalid schema - no match with root schema requirements for assignment - /// type #{0}. - AssignmentTypeMismatch(AssignmentType), - /// invalid schema - no match with root schema requirements for valency - /// type #{0}. - ValencyTypeMismatch(ValencyType), - /// invalid schema - no match with root schema requirements for transition - /// type #{0}. - TransitionTypeMismatch(TransitionType), - /// invalid schema - no match with root schema requirements for extension - /// type #{0}. - ExtensionTypeMismatch(ExtensionType), - - /// invalid schema - no match with root schema requirements for global state - /// type #{1} used in {0}. - OpGlobalStateMismatch(OpFullType, GlobalStateType), - /// invalid schema - no match with root schema requirements for input - /// type #{1} used in {0}. - OpInputMismatch(OpFullType, AssignmentType), - /// invalid schema - no match with root schema requirements for redeem - /// type #{1} used in {0}. - OpRedeemMismatch(OpFullType, ValencyType), - /// invalid schema - no match with root schema requirements for assignment - /// type #{1} used in {0}. - OpAssignmentsMismatch(OpFullType, AssignmentType), - /// invalid schema - no match with root schema requirements for valency - /// type #{1} used in {0}. - OpValencyMismatch(OpFullType, ValencyType), -} - -pub trait CheckInheritance { - fn check_inheritance(&self, root: &Self) -> Result<(), Vec>; -} - -impl CheckInheritance for Schema { - fn check_inheritance(&self, root: &Schema) -> Result<(), Vec> { - let mut status = vec![]; - - for (global_type, data_format) in &self.global_types { - match root.global_types.get(global_type) { - None => status.push(InheritanceFailure::GlobalStateMismatch(*global_type)), - Some(root_data_format) if root_data_format != data_format => { - status.push(InheritanceFailure::GlobalStateMismatch(*global_type)) - } - _ => {} - }; - } - - for (assignments_type, state_schema) in &self.owned_types { - match root.owned_types.get(assignments_type) { - None => status.push(InheritanceFailure::AssignmentTypeMismatch(*assignments_type)), - Some(root_state_schema) if root_state_schema != state_schema => { - status.push(InheritanceFailure::AssignmentTypeMismatch(*assignments_type)) - } - _ => {} - }; - } - - for valencies_type in &self.valency_types { - if !root.valency_types.contains(valencies_type) { - status.push(InheritanceFailure::ValencyTypeMismatch(*valencies_type)); - } - } - - self.genesis - .check_schema_op_inheritance(OpFullType::Genesis, &root.genesis) - .map_err(|e| status.extend(e)) - .ok(); - - for (type_id, transition_schema) in &self.transitions { - if let Some(root_transition_schema) = root.transitions.get(type_id) { - transition_schema - .check_schema_op_inheritance( - OpFullType::StateTransition(*type_id), - root_transition_schema, - ) - .map_err(|e| status.extend(e)) - .ok(); - } else { - status.push(InheritanceFailure::TransitionTypeMismatch(*type_id)); - } - } - for (type_id, extension_schema) in &self.extensions { - if let Some(root_extension_schema) = root.extensions.get(type_id) { - extension_schema - .check_schema_op_inheritance( - OpFullType::StateExtension(*type_id), - root_extension_schema, - ) - .map_err(|e| status.extend(e)) - .ok(); - } else { - status.push(InheritanceFailure::ExtensionTypeMismatch(*type_id)); - } - } - - if status.is_empty() { - Ok(()) - } else { - Err(status) - } - } -} - -/// Trait used for internal schema validation against some root schema -pub(crate) trait CheckSchemaOpInheritance { - fn check_schema_op_inheritance( - &self, - op_type: OpFullType, - root: &Self, - ) -> Result<(), Vec>; -} - -impl CheckSchemaOpInheritance for T -where T: OpSchema -{ - fn check_schema_op_inheritance( - &self, - op_type: OpFullType, - root: &Self, - ) -> Result<(), Vec> { - let mut status = vec![]; - - for (type_id, occ) in self.globals() { - match root.globals().get(type_id) { - None => status.push(InheritanceFailure::OpGlobalStateMismatch(op_type, *type_id)), - Some(root_occ) if occ != root_occ => { - status.push(InheritanceFailure::OpGlobalStateMismatch(op_type, *type_id)) - } - _ => {} - }; - } - - if let Some(inputs) = self.inputs() { - let root_inputs = root.inputs().expect("generic guarantees"); - for (type_id, occ) in inputs { - match root_inputs.get(type_id) { - None => status.push(InheritanceFailure::OpInputMismatch(op_type, *type_id)), - Some(root_occ) if occ != root_occ => { - status.push(InheritanceFailure::OpInputMismatch(op_type, *type_id)) - } - _ => {} - }; - } - } - - for (type_id, occ) in self.assignments() { - match root.assignments().get(type_id) { - None => status.push(InheritanceFailure::OpAssignmentsMismatch(op_type, *type_id)), - Some(root_occ) if occ != root_occ => { - status.push(InheritanceFailure::OpAssignmentsMismatch(op_type, *type_id)) - } - _ => {} - }; - } - - if let Some(redeems) = self.redeems() { - let root_redeems = root.redeems().expect("generic guarantees"); - for type_id in redeems { - if !root_redeems.contains(type_id) { - status.push(InheritanceFailure::OpRedeemMismatch(op_type, *type_id)); - } - } - } - - for type_id in self.valencies() { - if !root.valencies().contains(type_id) { - status.push(InheritanceFailure::OpValencyMismatch(op_type, *type_id)); - } - } - - if status.is_empty() { - Ok(()) - } else { - Err(status) - } - } -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Error)] -#[display("{iface} {err}")] -pub struct InheritError { - err: ExtensionError, - iface: TypeName, -} - -#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Error)] -#[display(doc_comments)] -pub enum ExtensionError { - /// too many metadata fields defined. - MetaOverflow, - /// too many global state types defined. - GlobalOverflow, - /// global state '{0}' has different data type from the parent interface. - GlobalType(FieldName), - /// global state '{0}' has fewer occurrences than in the parent interface. - GlobalOcc(FieldName), - /// too many assignment types defined. - AssignmentOverflow, - /// assignment '{0}' has different data type from the parent interface. - AssignmentType(FieldName), - /// assignment '{0}' has fewer occurrences than in the parent interface. - AssignmentOcc(FieldName), - /// global state '{0}' has lower visibility than in the parent interface. - AssignmentPublic(FieldName), - /// too many valency types defined. - ValencyOverflow, - /// valency '{0}' has fewer occurrences than in the parent interface. - ValencyOcc(FieldName), - /// too many state transitions. - TransitionOverflow, - /// too many state extensions. - ExtensionOverflow, - /// too many error types defined. - ErrorOverflow, - /// inherited interface tries to override the parent default operation. - DefaultOverride, - /// {0} in the parent interface is final and can't be overridden. - OpFinal(OpName), - /// {0} must use `override` keyword to modify the parent version. - OpNoOverride(OpName), - /// too many {1} types defined in {0}. - OpOverflow(OpName, &'static str), - /// {0} tries to override the parent default assignment. - OpDefaultOverride(OpName), - /// {0} tries to override '{2}' {1}. - OpOcc(OpName, &'static str, FieldName), - /// too deep inheritance; it is not allowed for any interface to have more - /// than 255 parents it inherits from, including all grandparents. - InheritanceOverflow, -} - -impl OwnedIface { - pub fn is_superset(self, other: OwnedIface) -> bool { - if self == Self::Any { - return true; - } - if self == Self::AnyData && matches!(other, Self::Data(_)) { - return true; - } - self == other - } -} - -impl Modifier { - pub fn is_final(self) -> bool { self == Self::Final } - pub fn can_be_overridden_by(self, other: Modifier) -> bool { - matches!((self, other), (Self::Abstract | Self::Override, Self::Override | Self::Final)) - } -} - -impl Iface { - pub fn expect_inherit( - name: impl Into, - ifaces: impl IntoIterator, - ) -> Iface { - let name = name.into(); - match Self::inherit(name.clone(), ifaces) { - Ok(iface) => iface, - Err(msgs) => { - eprintln!("Unable to construct interface {name}:"); - for msg in msgs { - eprintln!("- {msg}") - } - panic!(); - } - } - } - - pub fn inherit( - name: impl Into, - ifaces: impl IntoIterator, - ) -> Result> { - let name = name.into(); - let mut iter = ifaces.into_iter(); - let mut iface = iter - .next() - .expect("at least one interface must be provided for the inheritance"); - for ext in iter { - let ext_name = ext.name.clone(); - iface = iface.extended(ext, name.clone()).map_err(|err| { - err.into_iter() - .map(|e| InheritError { - err: e, - iface: ext_name.clone(), - }) - .collect::>() - })?; - } - Ok(iface) - } - - pub fn expect_extended(self, ext: Iface, name: impl Into) -> Iface { - let prev_name = self.name.clone(); - let ext_name = ext.name.clone(); - match self.extended(ext, name) { - Ok(iface) => iface, - Err(msgs) => { - eprintln!("Unable to extend {prev_name} with {ext_name}:"); - for msg in msgs { - eprintln!("- {msg}") - } - panic!(); - } - } - } - - pub fn extended( - mut self, - ext: Iface, - name: impl Into, - ) -> Result> { - let orig_id = self.iface_id(); - let ext_id = ext.iface_id(); - let name = name.into(); - - let mut errors = vec![]; - - self.metadata - .extend(ext.metadata) - .map_err(|_| errors.push(ExtensionError::MetaOverflow)) - .ok(); - - for (name, e) in ext.global_state { - match self.global_state.get_mut(&name) { - None => { - if self - .global_state - .insert(name, e) - .map_err(|_| errors.push(ExtensionError::GlobalOverflow)) - .is_err() - { - break; - } - } - Some(orig) => { - if orig.sem_id.is_some() && e.sem_id != orig.sem_id { - errors.push(ExtensionError::GlobalType(name)); - } else if orig.required & !e.required { - errors.push(ExtensionError::GlobalOcc(name)); - } else { - *orig = e; - } - } - } - } - - for (name, e) in ext.assignments { - match self.assignments.get_mut(&name) { - None => { - if self - .assignments - .insert(name, e) - .map_err(|_| errors.push(ExtensionError::AssignmentOverflow)) - .is_err() - { - break; - } - } - Some(orig) => { - if !orig.owned_state.is_superset(e.owned_state) { - errors.push(ExtensionError::AssignmentType(name)); - } else if orig.required & !e.required { - errors.push(ExtensionError::AssignmentOcc(name)); - } else if orig.public & !e.public { - errors.push(ExtensionError::AssignmentPublic(name)); - } else { - *orig = e; - } - } - } - } - - for (name, e) in ext.valencies { - match self.valencies.get_mut(&name) { - None => { - if self - .valencies - .insert(name, e) - .map_err(|_| errors.push(ExtensionError::ValencyOverflow)) - .is_err() - { - break; - } - } - Some(orig) => { - if orig.required & !e.required { - errors.push(ExtensionError::ValencyOcc(name)); - } else { - *orig = e; - } - } - } - } - - self.clone() - .genesis - .extended(ext.genesis) - .map(|genesis| self.genesis = genesis) - .map_err(|errs| errors.extend(errs)) - .ok(); - - for (name, op) in ext.transitions { - match self.transitions.remove(&name) { - Ok(None) if op.optional => continue, - Ok(None) => { - if self - .transitions - .insert(name, op) - .map_err(|_| errors.push(ExtensionError::TransitionOverflow)) - .is_err() - { - break; - } - } - Ok(Some(orig)) => { - orig.extended(op, name.clone()) - .map(|op| self.transitions.insert(name, op).expect("same size")) - .map_err(|errs| errors.extend(errs)) - .ok(); - } - Err(_) => unreachable!(), - } - } - - for (name, op) in ext.extensions { - match self.extensions.remove(&name) { - Ok(None) if op.optional => continue, - Ok(None) => { - if self - .extensions - .insert(name, op) - .map_err(|_| errors.push(ExtensionError::TransitionOverflow)) - .is_err() - { - break; - } - } - Ok(Some(orig)) => { - orig.extended(op, name.clone()) - .map(|op| self.extensions.insert(name, op).expect("same size")) - .map_err(|errs| errors.extend(errs)) - .ok(); - } - Err(_) => unreachable!(), - } - } - - // We allow replacing error messages - self.errors - .extend(ext.errors) - .map_err(|_| errors.push(ExtensionError::ErrorOverflow)) - .ok(); - - if ext.default_operation.is_some() { - if self.default_operation.is_some() && self.default_operation != ext.default_operation { - errors.push(ExtensionError::DefaultOverride); - } else { - self.default_operation = ext.default_operation - } - } - - self.name = name; - self.inherits - .push(orig_id) - .and_then(|_| self.inherits.extend(ext.inherits)) - .and_then(|_| self.inherits.push(ext_id)) - .map_err(|_| errors.push(ExtensionError::InheritanceOverflow)) - .ok(); - - if errors.is_empty() { - Ok(self) - } else { - Err(errors) - } - } -} - -fn check_occs( - orig: &mut TinyOrdMap, - ext: impl IntoIterator, - op: OpName, - state: &'static str, - errors: &mut Vec, -) { - for (name, occ) in ext { - match orig.get_mut(&name) { - None => { - if orig - .insert(name, occ) - .map_err(|_| errors.push(ExtensionError::OpOverflow(op.clone(), state))) - .is_err() - { - break; - } - } - Some(orig) => { - if orig.min_value() > occ.min_value() { - errors.push(ExtensionError::OpOcc(op.clone(), state, name)); - } else { - *orig = occ; - } - } - } - } -} - -fn check_presence( - orig: &mut TinyOrdSet, - ext: impl IntoIterator, - op: OpName, - state: &'static str, - errors: &mut Vec, -) { - for name in ext { - if orig - .push(name) - .map_err(|_| errors.push(ExtensionError::OpOverflow(op.clone(), state))) - .is_err() - { - break; - } - } -} - -impl GenesisIface { - pub fn extended(mut self, ext: Self) -> Result> { - let mut errors = vec![]; - - let op = OpName::Genesis; - if self.modifier.is_final() { - errors.push(ExtensionError::OpFinal(op.clone())); - } else if !self.modifier.can_be_overridden_by(ext.modifier) { - errors.push(ExtensionError::OpNoOverride(op.clone())); - } - - self.metadata - .extend(ext.metadata) - .map_err(|_| errors.push(ExtensionError::OpOverflow(OpName::Genesis, "metadata"))) - .ok(); - check_occs(&mut self.globals, ext.globals, op.clone(), "global", &mut errors); - check_occs(&mut self.assignments, ext.assignments, op.clone(), "assignment", &mut errors); - - check_presence(&mut self.valencies, ext.valencies, op.clone(), "valency", &mut errors); - check_presence(&mut self.errors, ext.errors, op.clone(), "error", &mut errors); - - if errors.is_empty() { - Ok(self) - } else { - Err(errors) - } - } -} - -impl TransitionIface { - pub fn extended(mut self, ext: Self, op_name: FieldName) -> Result> { - let mut errors = vec![]; - - let op = OpName::Transition(op_name); - if self.modifier.is_final() { - errors.push(ExtensionError::OpFinal(op.clone())); - } else if !self.modifier.can_be_overridden_by(ext.modifier) { - errors.push(ExtensionError::OpNoOverride(op.clone())); - } - self.optional = self.optional.max(ext.optional); - - self.metadata - .extend(ext.metadata) - .map_err(|_| errors.push(ExtensionError::OpOverflow(op.clone(), "metadata"))) - .ok(); - check_occs(&mut self.globals, ext.globals, op.clone(), "global", &mut errors); - check_occs(&mut self.assignments, ext.assignments, op.clone(), "assignment", &mut errors); - check_occs(&mut self.inputs, ext.inputs, op.clone(), "input", &mut errors); - - check_presence(&mut self.valencies, ext.valencies, op.clone(), "valency", &mut errors); - check_presence(&mut self.errors, ext.errors, op.clone(), "error", &mut errors); - - if ext.default_assignment.is_some() { - if self.default_assignment.is_some() - && self.default_assignment != ext.default_assignment - { - errors.push(ExtensionError::OpDefaultOverride(op.clone())); - } else { - self.default_assignment = ext.default_assignment - } - } - - if errors.is_empty() { - Ok(self) - } else { - Err(errors) - } - } -} - -impl ExtensionIface { - pub fn extended(mut self, ext: Self, op_name: FieldName) -> Result> { - let mut errors = vec![]; - - let op = OpName::Transition(op_name); - if self.modifier.is_final() { - errors.push(ExtensionError::OpFinal(op.clone())); - } else if !self.modifier.can_be_overridden_by(ext.modifier) { - errors.push(ExtensionError::OpNoOverride(op.clone())); - } - self.optional = self.optional.max(ext.optional); - - self.metadata - .extend(ext.metadata) - .map_err(|_| errors.push(ExtensionError::OpOverflow(op.clone(), "metadata"))) - .ok(); - check_occs(&mut self.globals, ext.globals, op.clone(), "global", &mut errors); - check_occs(&mut self.assignments, ext.assignments, op.clone(), "assignment", &mut errors); - - check_presence(&mut self.valencies, ext.valencies, op.clone(), "valency", &mut errors); - check_presence(&mut self.redeems, ext.redeems, op.clone(), "input", &mut errors); - check_presence(&mut self.errors, ext.errors, op.clone(), "error", &mut errors); - - if ext.default_assignment.is_some() { - if self.default_assignment.is_some() - && self.default_assignment != ext.default_assignment - { - errors.push(ExtensionError::OpDefaultOverride(op.clone())); - } else { - self.default_assignment = ext.default_assignment - } - } - - if errors.is_empty() { - Ok(self) - } else { - Err(errors) - } - } -} - -impl IfaceImpl { - pub fn abstracted(mut self, base: &Iface, parent: &Iface) -> Option { - assert_eq!(self.iface_id, base.iface_id()); - let parent_id = parent.iface_id(); - if !base.inherits.contains(&parent_id) { - return None; - } - - self.metadata = Confined::from_iter_checked(base.metadata.keys().filter_map(|name| { - self.metadata - .iter() - .find(|i| parent.metadata.contains_key(name) && &i.name == name) - .cloned() - })); - - self.global_state = - Confined::from_iter_checked(base.global_state.keys().filter_map(|name| { - self.global_state - .iter() - .find(|i| parent.global_state.contains_key(name) && &i.name == name) - .cloned() - })); - - self.assignments = - Confined::from_iter_checked(base.assignments.keys().filter_map(|name| { - self.assignments - .iter() - .find(|i| parent.assignments.contains_key(name) && &i.name == name) - .cloned() - })); - - self.valencies = Confined::from_iter_checked(base.assignments.keys().filter_map(|name| { - self.valencies - .iter() - .find(|i| parent.valencies.contains_key(name) && &i.name == name) - .cloned() - })); - - self.transitions = - Confined::from_iter_checked(base.transitions.keys().filter_map(|name| { - self.transitions - .iter() - .find(|i| parent.transitions.contains_key(name) && &i.name == name) - .cloned() - })); - - self.extensions = Confined::from_iter_checked(base.extensions.keys().filter_map(|name| { - self.extensions - .iter() - .find(|i| parent.extensions.contains_key(name) && &i.name == name) - .cloned() - })); - - self.iface_id = parent_id; - - Some(self) - } -} diff --git a/src/interface/mod.rs b/src/interface/mod.rs deleted file mode 100644 index 301783d5..00000000 --- a/src/interface/mod.rs +++ /dev/null @@ -1,67 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// 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. -// -// 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. - -//! RGB contract interface provides a mapping between identifiers of RGB schema- -//! defined contract state and operation types to a human-readable and -//! standardized wallet APIs. - -mod iface; -mod iimpl; -mod contract; -mod builder; -mod filter; -pub(crate) mod resolver; -mod contractum; -mod inheritance; - -pub use builder::{BuilderError, ContractBuilder, TransitionBuilder}; -pub use contract::{ - AllocatedState, AttachAllocation, ContractError, ContractIface, ContractOp, DataAllocation, - FungibleAllocation, OpDirection, OwnedAllocation, RightsAllocation, -}; -pub use contractum::IfaceDisplay; -pub use filter::{AssignmentsFilter, FilterExclude, FilterIncludeAll}; -pub use iface::{ - ArgMap, AssignIface, ExtensionIface, GenesisIface, GlobalIface, Iface, IfaceClass, IfaceId, - IfaceInconsistency, IfaceRef, IfaceWrapper, Modifier, OpName, OwnedIface, Req, TransitionIface, - ValencyIface, -}; -pub use iimpl::{IfaceImpl, ImplId, NamedField, NamedType, NamedVariant, SchemaTypeIndex}; -pub use inheritance::{CheckInheritance, ExtensionError, InheritanceFailure}; - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = crate::LIB_NAME_RGB_STD, tags = repr, into_u8, try_from_u8)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -#[repr(u8)] -#[non_exhaustive] -pub enum VerNo { - #[display("v0", alt = "0")] - V0 = 0, - - #[default] - #[display("v1", alt = "1")] - V1 = 1, -} diff --git a/src/lib.rs b/src/lib.rs index 746c7ac4..b61f5748 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,16 +38,14 @@ extern crate serde_crate as serde; pub extern crate rgbinvoice as invoice; pub mod stl; -pub mod interface; pub mod containers; pub mod persistence; -mod contract; +pub mod contract; +pub mod indexers; pub mod info; pub use bp::{Outpoint, Txid}; -pub use contract::{ - KnownState, MergeReveal, MergeRevealError, OutputAssignment, TypedAssignsExt, WitnessInfo, -}; +pub use contract::{KnownState, MergeReveal, MergeRevealError, OutputAssignment, WitnessInfo}; pub use invoice::{Allocation, Amount, CoinAmount, OwnedFraction, Precision, TokenIndex}; pub use rgb::prelude::*; pub use rgb::rgbasm; diff --git a/src/persistence/index.rs b/src/persistence/index.rs index ce2c0ebb..a72b683c 100644 --- a/src/persistence/index.rs +++ b/src/persistence/index.rs @@ -23,12 +23,12 @@ use std::collections::BTreeSet; use std::error::Error; use std::fmt::Debug; -use amplify::confinement::{self, TinyOrdSet}; +use amplify::confinement::{self, SmallOrdSet}; use bp::{Outpoint, Txid}; use nonasync::persistence::{CloneNoPersistence, Persisting}; use rgb::{ - Assign, AssignmentType, BundleId, ContractId, ExposedState, Extension, Genesis, GenesisSeal, - GraphSeal, OpId, Operation, Opout, TransitionBundle, TypedAssigns, + Assign, AssignmentType, BundleId, ContractId, ExposedState, Genesis, GenesisSeal, GraphSeal, + OpId, Operation, Opout, TransitionBundle, TypedAssigns, }; use crate::containers::{ConsignmentExt, ToWitnessId, WitnessBundle}; @@ -166,16 +166,13 @@ impl Index

{ .register_contract(contract_id) .map_err(IndexError::WriteProvider)?; self.index_genesis(contract_id, consignment.genesis())?; - for extension in consignment.extensions() { - self.index_extension(contract_id, extension)?; - } for WitnessBundle { pub_witness, - anchored_bundle, + anchor: _, + bundle, } in consignment.bundled_witnesses() { let witness_id = pub_witness.to_witness_id(); - let bundle = anchored_bundle.bundle(); self.index_bundle(contract_id, bundle, witness_id)?; } @@ -198,39 +195,6 @@ impl Index

{ self.provider .index_genesis_assignments(id, vec, opid, *type_id)?; } - TypedAssigns::Attachment(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } - } - } - Ok(()) - } - - fn index_extension( - &mut self, - id: ContractId, - extension: &Extension, - ) -> Result<(), IndexError

> { - let opid = extension.id(); - for (type_id, assign) in extension.assignments.iter() { - match assign { - TypedAssigns::Declarative(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } - TypedAssigns::Fungible(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } - TypedAssigns::Structured(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } - TypedAssigns::Attachment(vec) => { - self.provider - .index_genesis_assignments(id, vec, opid, *type_id)?; - } } } Ok(()) @@ -250,8 +214,7 @@ impl Index

{ for (opid, transition) in &bundle.known_transitions { self.provider.register_operation(*opid, bundle_id)?; for input in &transition.inputs { - self.provider - .register_spending(input.prev_out.op, bundle_id)?; + self.provider.register_spending(input.op, bundle_id)?; } for (type_id, assign) in transition.assignments.iter() { match assign { @@ -282,15 +245,6 @@ impl Index

{ witness_id, )?; } - TypedAssigns::Attachment(vec) => { - self.provider.index_transition_assignments( - contract_id, - vec, - *opid, - *type_id, - witness_id, - )?; - } } } } @@ -338,7 +292,7 @@ impl Index

{ pub(super) fn bundle_ids_children_of_op( &self, opid: OpId, - ) -> Result, IndexError

> { + ) -> Result, IndexError

> { Ok(self.provider.bundle_ids_children_of_op(opid)?) } @@ -402,7 +356,7 @@ pub trait IndexReadProvider { fn bundle_ids_children_of_op( &self, opid: OpId, - ) -> Result, IndexReadError>; + ) -> Result, IndexReadError>; fn bundle_info( &self, diff --git a/src/persistence/memory.rs b/src/persistence/memory.rs index df2d2222..88a27d30 100644 --- a/src/persistence/memory.rs +++ b/src/persistence/memory.rs @@ -28,39 +28,35 @@ use std::{iter, mem}; use aluvm::library::{Lib, LibId}; use amplify::confinement::{ - self, Confined, LargeOrdMap, LargeOrdSet, MediumBlob, MediumOrdMap, MediumOrdSet, SmallOrdMap, - TinyOrdMap, TinyOrdSet, + self, LargeOrdMap, LargeOrdSet, MediumOrdSet, SmallOrdMap, SmallOrdSet, TinyOrdMap, }; use amplify::num::u24; use bp::dbc::tapret::TapretCommitment; use bp::{Outpoint, Txid}; use commit_verify::{CommitId, Conceal}; use nonasync::persistence::{CloneNoPersistence, Persistence, PersistenceError, Persisting}; +use rgb::validation::DbcProof; use rgb::vm::{ ContractStateAccess, ContractStateEvolve, GlobalContractState, GlobalOrd, GlobalStateIter, OrdOpRef, UnknownGlobalStateType, WitnessOrd, }; use rgb::{ - Assign, AssignmentType, Assignments, AssignmentsRef, AttachId, AttachState, BundleId, - ContractId, DataState, ExposedSeal, ExposedState, Extension, FungibleState, Genesis, - GenesisSeal, GlobalStateType, GraphSeal, Identity, OpId, Operation, Opout, OutputSeal, - RevealedAttach, RevealedData, RevealedValue, Schema, SchemaId, SecretSeal, Transition, + Assign, AssignmentType, Assignments, AssignmentsRef, BundleId, ContractId, ExposedSeal, + ExposedState, FungibleState, Genesis, GenesisSeal, GlobalStateType, GraphSeal, OpId, Operation, + Opout, OutputSeal, RevealedData, RevealedValue, Schema, SchemaId, SecretSeal, Transition, TransitionBundle, TypedAssigns, VoidState, }; use strict_encoding::{StrictDeserialize, StrictSerialize}; use strict_types::TypeSystem; use super::{ - ContractIfaceError, ContractStateRead, ContractStateWrite, IndexInconsistency, IndexProvider, - IndexReadError, IndexReadProvider, IndexWriteError, IndexWriteProvider, SchemaIfaces, - StashInconsistency, StashProvider, StashProviderError, StashReadProvider, StashWriteProvider, - StateInconsistency, StateProvider, StateReadProvider, StateWriteProvider, StoreTransaction, -}; -use crate::containers::{ - AnchorSet, ContentId, ContentRef, ContentSigs, SealWitness, SigBlob, Supplement, TrustLevel, + ContractStateRead, ContractStateWrite, IndexInconsistency, IndexProvider, IndexReadError, + IndexReadProvider, IndexWriteError, IndexWriteProvider, StashInconsistency, StashProvider, + StashProviderError, StashReadProvider, StashWriteProvider, StateInconsistency, StateProvider, + StateReadProvider, StateWriteProvider, StoreTransaction, }; +use crate::containers::SealWitness; use crate::contract::{GlobalOut, KnownState, OpWitness, OutputAssignment}; -use crate::interface::{Iface, IfaceClass, IfaceId, IfaceImpl, IfaceRef}; use crate::LIB_NAME_RGB_STORAGE; #[derive(Debug, Display, Error, From)] @@ -87,19 +83,13 @@ pub struct MemStash { #[strict_type(skip)] persistence: Option>, - schemata: TinyOrdMap, - ifaces: TinyOrdMap, - geneses: TinyOrdMap, - suppl: TinyOrdMap>, + schemata: TinyOrdMap, + geneses: SmallOrdMap, bundles: LargeOrdMap, - extensions: LargeOrdMap, witnesses: LargeOrdMap, - attachments: SmallOrdMap, - secret_seals: MediumOrdSet, + secret_seals: LargeOrdSet, type_system: TypeSystem, - identities: SmallOrdMap, libs: SmallOrdMap, - sigs: SmallOrdMap, } impl StrictSerialize for MemStash {} @@ -110,18 +100,12 @@ impl MemStash { Self { persistence: none!(), schemata: empty!(), - ifaces: empty!(), geneses: empty!(), - suppl: empty!(), bundles: empty!(), - extensions: empty!(), witnesses: empty!(), - attachments: empty!(), secret_seals: empty!(), type_system: none!(), - identities: empty!(), libs: empty!(), - sigs: empty!(), } } } @@ -131,18 +115,12 @@ impl CloneNoPersistence for MemStash { Self { persistence: None, schemata: self.schemata.clone(), - ifaces: self.ifaces.clone(), geneses: self.geneses.clone(), - suppl: self.suppl.clone(), bundles: self.bundles.clone(), - extensions: self.extensions.clone(), witnesses: self.witnesses.clone(), - attachments: self.attachments.clone(), secret_seals: self.secret_seals.clone(), type_system: self.type_system.clone(), - identities: self.identities.clone(), libs: self.libs.clone(), - sigs: self.sigs.clone(), } } } @@ -183,99 +161,20 @@ impl StashReadProvider for MemStash { .ok_or_else(|| StashInconsistency::LibAbsent(id).into()) } - fn ifaces(&self) -> Result, Self::Error> { - Ok(self.ifaces.values()) - } - - fn iface(&self, iface: impl Into) -> Result<&Iface, StashProviderError> { - let iref = iface.into(); - match iref { - IfaceRef::Name(ref name) => self.ifaces.values().find(|iface| &iface.name == name), - IfaceRef::Id(ref id) => self.ifaces.get(id), - } - .ok_or_else(|| StashInconsistency::IfaceAbsent(iref).into()) - } - - fn schemata(&self) -> Result, Self::Error> { + fn schemata(&self) -> Result, Self::Error> { Ok(self.schemata.values()) } - fn schemata_by( - &self, - ) -> Result, Self::Error> { - Ok(self - .schemata - .values() - .filter(|schema_ifaces| self.impl_for::(schema_ifaces).is_ok())) - } - - fn impl_for<'a, C: IfaceClass + 'a>( - &'a self, - schema_ifaces: &'a SchemaIfaces, - ) -> Result<&'a IfaceImpl, StashProviderError> { - schema_ifaces - .iimpls - .values() - .find(|iimpl| C::IFACE_IDS.contains(&iimpl.iface_id)) - .or_else(|| { - C::IFACE_IDS.iter().find_map(|id| { - let iface = self.iface(*id).ok()?; - iface.find_abstractable_impl(schema_ifaces) - }) - }) - .ok_or_else(move || { - ContractIfaceError::NoAbstractImpl( - C::IFACE_IDS[0], - schema_ifaces.schema.schema_id(), - ) - .into() - }) - } - fn schema( - &self, - schema_id: SchemaId, - ) -> Result<&SchemaIfaces, StashProviderError> { + fn schema(&self, schema_id: SchemaId) -> Result<&Schema, StashProviderError> { self.schemata .get(&schema_id) .ok_or_else(|| StashInconsistency::SchemaAbsent(schema_id).into()) } - fn get_trust(&self, identity: &Identity) -> Result { - Ok(self.identities.get(identity).copied().unwrap_or_default()) - } - - fn supplement(&self, content_ref: ContentRef) -> Result, Self::Error> { - Ok(self.suppl.get(&content_ref).and_then(|s| s.first())) - } - - fn supplements( - &self, - content_ref: ContentRef, - ) -> Result, Self::Error> { - Ok(self - .suppl - .get(&content_ref) - .cloned() - .unwrap_or_default() - .into_iter()) - } - - fn sigs_for(&self, content_id: &ContentId) -> Result, Self::Error> { - Ok(self.sigs.get(content_id)) - } - fn geneses(&self) -> Result, Self::Error> { Ok(self.geneses.values()) } - fn geneses_by(&self) -> Result, Self::Error> { - Ok(self.schemata_by::()?.flat_map(|schema_ifaces| { - self.geneses - .values() - .filter(|genesis| schema_ifaces.schema.schema_id() == genesis.schema_id) - })) - } - fn genesis( &self, contract_id: ContractId, @@ -302,16 +201,6 @@ impl StashReadProvider for MemStash { .ok_or(StashInconsistency::BundleAbsent(bundle_id).into()) } - fn extension_ids(&self) -> Result, Self::Error> { - Ok(self.extensions.keys().copied()) - } - - fn extension(&self, op_id: OpId) -> Result<&Extension, StashProviderError> { - self.extensions - .get(&op_id) - .ok_or(StashInconsistency::OperationAbsent(op_id).into()) - } - fn witness(&self, witness_id: Txid) -> Result<&SealWitness, StashProviderError> { self.witnesses .get(&witness_id) @@ -322,10 +211,10 @@ impl StashReadProvider for MemStash { Ok(self .witnesses .iter() - .filter_map(|(witness_id, witness)| match &witness.anchor { - AnchorSet::Tapret(anchor) => Some((*witness_id, TapretCommitment { - mpc: anchor.mpc_proof.commit_id(), - nonce: anchor.dbc_proof.path_proof.nonce(), + .filter_map(|(witness_id, witness)| match &witness.dbc_proof { + DbcProof::Tapret(tapret_proof) => Some((*witness_id, TapretCommitment { + mpc: witness.merkle_block.commit_id(), + nonce: tapret_proof.path_proof.nonce(), })), _ => None, })) @@ -350,64 +239,18 @@ impl StashWriteProvider for MemStash { fn replace_schema(&mut self, schema: Schema) -> Result { let schema_id = schema.schema_id(); if !self.schemata.contains_key(&schema_id) { - self.schemata.insert(schema_id, SchemaIfaces::new(schema))?; - return Ok(true); - } - Ok(false) - } - - fn replace_iface(&mut self, iface: Iface) -> Result { - let iface_id = iface.iface_id(); - if !self.ifaces.contains_key(&iface_id) { - self.ifaces.insert(iface_id, iface)?; + self.schemata.insert(schema_id, schema)?; return Ok(true); } Ok(false) } - fn replace_iimpl(&mut self, iimpl: IfaceImpl) -> Result { - let schema_ifaces = self - .schemata - .get_mut(&iimpl.schema_id) - .expect("unknown schema"); - let iface = self.ifaces.get(&iimpl.iface_id).expect("unknown interface"); - let iface_name = iface.name.clone(); - let present = schema_ifaces.iimpls.contains_key(&iface_name); - schema_ifaces.iimpls.insert(iface_name, iimpl)?; - Ok(!present) - } - - fn set_trust( - &mut self, - identity: Identity, - trust: TrustLevel, - ) -> Result<(), confinement::Error> { - self.identities.insert(identity, trust)?; - Ok(()) - } - - fn add_supplement(&mut self, suppl: Supplement) -> Result<(), Self::Error> { - match self.suppl.get_mut(&suppl.content_id) { - None => { - self.suppl.insert(suppl.content_id, tiny_bset![suppl])?; - } - Some(suppls) => suppls.push(suppl)?, - } - Ok(()) - } - fn replace_genesis(&mut self, genesis: Genesis) -> Result { let contract_id = genesis.contract_id(); let present = self.geneses.insert(contract_id, genesis)?.is_some(); Ok(!present) } - fn replace_extension(&mut self, extension: Extension) -> Result { - let opid = extension.id(); - let present = self.extensions.insert(opid, extension)?.is_some(); - Ok(!present) - } - fn replace_bundle(&mut self, bundle: TransitionBundle) -> Result { let bundle_id = bundle.bundle_id(); let present = self.bundles.insert(bundle_id, bundle)?.is_some(); @@ -420,15 +263,6 @@ impl StashWriteProvider for MemStash { Ok(!present) } - fn replace_attachment( - &mut self, - id: AttachId, - attach: MediumBlob, - ) -> Result { - let present = self.attachments.insert(id, attach)?.is_some(); - Ok(!present) - } - fn consume_types(&mut self, types: TypeSystem) -> Result<(), Self::Error> { Ok(self.type_system.extend(types)?) } @@ -438,29 +272,6 @@ impl StashWriteProvider for MemStash { Ok(!present) } - fn import_sigs(&mut self, content_id: ContentId, sigs: I) -> Result<(), Self::Error> - where I: IntoIterator { - let sigs = sigs.into_iter().filter(|(id, _)| { - match self.identities.get(id) { - Some(level) => *level, - None => { - let level = TrustLevel::default(); - // We ignore if the identities are full - self.identities.insert(id.clone(), level).ok(); - level - } - } - .should_accept() - }); - if let Some(prev_sigs) = self.sigs.get_mut(&content_id) { - prev_sigs.extend(sigs)?; - } else { - let sigs = Confined::try_from_iter(sigs)?; - self.sigs.insert(content_id, ContentSigs::from(sigs)).ok(); - } - Ok(()) - } - fn add_secret_seal(&mut self, seal: GraphSeal) -> Result { let present = self.secret_seals.contains(&seal); self.secret_seals.push(seal)?; @@ -483,7 +294,7 @@ pub struct MemState { witnesses: LargeOrdMap, invalid_bundles: LargeOrdSet, - contracts: TinyOrdMap, + contracts: SmallOrdMap, } impl StrictSerialize for MemState {} @@ -560,7 +371,6 @@ impl StateReadProvider for MemState { || unfiltered.rights.iter().any(|a| a.witness == id) || unfiltered.fungibles.iter().any(|a| a.witness == id) || unfiltered.data.iter().any(|a| a.witness == id) - || unfiltered.attach.iter().any(|a| a.witness == id) }) .map(|(id, ord)| (*id, *ord)) .collect(); @@ -571,14 +381,6 @@ impl StateReadProvider for MemState { }) } - fn is_valid_witness(&self, witness_id: Txid) -> Result { - let ord = self - .witnesses - .get(&witness_id) - .ok_or(StateInconsistency::AbsentWitness(witness_id))?; - Ok(ord.is_valid()) - } - fn witnesses(&self) -> LargeOrdMap { self.witnesses.clone() } fn invalid_bundles(&self) -> LargeOrdSet { self.invalid_bundles.clone() } @@ -670,7 +472,7 @@ impl StateWriteProvider for MemState { #[strict_type(lib = LIB_NAME_RGB_STORAGE)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] pub struct MemGlobalState { - known: LargeOrdMap, + known: LargeOrdMap, limit: u24, } @@ -710,7 +512,6 @@ pub struct MemContractState { rights: LargeOrdSet>, fungibles: LargeOrdSet>, data: LargeOrdSet>, - attach: LargeOrdSet>, } impl MemContractState { @@ -719,7 +520,7 @@ impl MemContractState { schema .global_types .iter() - .map(|(ty, glob)| (*ty, MemGlobalState::new(glob.max_items))), + .map(|(ty, glob)| (*ty, MemGlobalState::new(glob.global_state_schema.max_items))), ); MemContractState { schema_id: schema.schema_id(), @@ -728,7 +529,6 @@ impl MemContractState { rights: empty!(), fungibles: empty!(), data: empty!(), - attach: empty!(), } } @@ -742,10 +542,10 @@ impl MemContractState { .expect("global map must be initialized from the schema"); for (idx, s) in state.iter().enumerate() { let out = GlobalOut { - opid, - nonce: op.nonce(), index: idx as u16, op_witness: OpWitness::from(op), + nonce: op.nonce(), + opid, }; map.known .insert(out, s.clone()) @@ -810,9 +610,6 @@ impl MemContractState { TypedAssigns::Structured(assignments) => { process(&mut self.data, assignments, bundle_id, opid, *ty, witness_id) } - TypedAssigns::Attachment(assignments) => { - process(&mut self.attach, assignments, bundle_id, opid, *ty, witness_id) - } } } } @@ -835,12 +632,12 @@ impl> ContractStateAccess for MemContract { &self, ty: GlobalStateType, ) -> Result, UnknownGlobalStateType> { - type Src<'a> = &'a BTreeMap; - type FilteredIter<'a> = Box + 'a>; + type Src<'a> = &'a BTreeMap; + type FilteredIter<'a> = Box + 'a>; struct Iter<'a> { src: Src<'a>, iter: FilteredIter<'a>, - last: Option<(GlobalOrd, &'a DataState)>, + last: Option<(GlobalOrd, &'a RevealedData)>, depth: u24, constructor: Box) -> FilteredIter<'a> + 'a>, } @@ -852,7 +649,7 @@ impl> ContractStateAccess for MemContract { } } impl<'a> GlobalStateIter for Iter<'a> { - type Data = &'a DataState; + type Data = &'a RevealedData; fn size(&mut self) -> u24 { let iter = self.swap(); // TODO: Consuming iterator just to count items is highly inefficient, but I do @@ -903,10 +700,6 @@ impl> ContractStateAccess for MemContract { let ord = self.filter.get(&id)?; GlobalOrd::transition(out.opid, out.index, ty, out.nonce, *ord) } - OpWitness::Extension(id, ty) => { - let ord = self.filter.get(&id)?; - GlobalOrd::extension(out.opid, out.index, ty, out.nonce, *ord) - } }; Some((ord, data)) }) @@ -950,14 +743,14 @@ impl> ContractStateAccess for MemContract { }) .filter(|assignment| assignment.check_witness(&self.filter)) .filter(|assignment| assignment.check_bundle(&self.invalid_bundles)) - .map(|assignment| assignment.state.value) + .map(|assignment| assignment.state.into()) } fn data( &self, outpoint: Outpoint, ty: AssignmentType, - ) -> impl DoubleEndedIterator> { + ) -> impl DoubleEndedIterator> { self.unfiltered .borrow() .data @@ -967,29 +760,13 @@ impl> ContractStateAccess for MemContract { }) .filter(|assignment| assignment.check_witness(&self.filter)) .filter(|assignment| assignment.check_bundle(&self.invalid_bundles)) - .map(|assignment| &assignment.state.value) - } - - fn attach( - &self, - outpoint: Outpoint, - ty: AssignmentType, - ) -> impl DoubleEndedIterator> { - self.unfiltered - .borrow() - .attach - .iter() - .filter(move |assignment| { - assignment.seal.to_outpoint() == outpoint && assignment.opout.ty == ty - }) - .filter(|assignment| assignment.check_witness(&self.filter)) - .filter(|assignment| assignment.check_bundle(&self.invalid_bundles)) - .map(|assignment| &assignment.state.file) + .map(|assignment| &assignment.state) } } impl ContractStateEvolve for MemContract { type Context<'ctx> = (&'ctx Schema, ContractId); + type Error = MemError; fn init(context: Self::Context<'_>) -> Self { Self { @@ -999,7 +776,7 @@ impl ContractStateEvolve for MemContract { } } - fn evolve_state(&mut self, op: OrdOpRef) -> Result<(), confinement::Error> { + fn evolve_state(&mut self, op: OrdOpRef) -> Result<(), Self::Error> { fn writer(me: &mut MemContract) -> MemContractWriter { MemContractWriter { writer: Box::new( @@ -1023,18 +800,7 @@ impl ContractStateEvolve for MemContract { let mut writer = writer(self); writer.add_transition(transition, witness_id, ord, bundle_id) } - OrdOpRef::Extension(extension, witness_id, ord) => { - let mut writer = writer(self); - writer.add_extension(extension, witness_id, ord) - } - } - .map_err(|err| { - // TODO: remove once evolve_state would accept arbitrary errors - match err { - MemError::Persistence(_) => unreachable!("only confinement errors are possible"), - MemError::Confinement(e) => e, - } - })?; + }?; Ok(()) } } @@ -1080,16 +846,6 @@ impl> ContractStateRead for MemContract { .filter(|assignment| assignment.check_witness(&self.filter)) .filter(|assignment| assignment.check_bundle(&self.invalid_bundles)) } - - #[inline] - fn attach_all(&self) -> impl Iterator> { - self.unfiltered - .borrow() - .attach - .iter() - .filter(|assignment| assignment.check_witness(&self.filter)) - .filter(|assignment| assignment.check_bundle(&self.invalid_bundles)) - } } pub struct MemContractWriter<'mem> { @@ -1125,22 +881,6 @@ impl ContractStateWrite for MemContractWriter<'_> { .add_operation(OrdOpRef::Transition(transition, witness_id, ord, bundle_id)); Ok(()) } - - /// # Panics - /// - /// If state extension violates RGB consensus rules and wasn't checked - /// against the schema before adding to the history. - fn add_extension( - &mut self, - extension: &Extension, - witness_id: Txid, - ord: WitnessOrd, - ) -> Result<(), Self::Error> { - (self.writer)(witness_id, ord)?; - self.contract - .add_operation(OrdOpRef::Extension(extension, witness_id, ord)); - Ok(()) - } } ////////// @@ -1164,8 +904,8 @@ impl From for IndexWriteError { serde(crate = "serde_crate", rename_all = "camelCase") )] pub struct ContractIndex { - public_opouts: MediumOrdSet, - outpoint_opouts: MediumOrdMap>, + public_opouts: LargeOrdSet, + outpoint_opouts: LargeOrdMap>, } #[derive(Getters, Debug)] @@ -1177,12 +917,12 @@ pub struct MemIndex { #[strict_type(skip)] persistence: Option>, - op_bundle_children_index: MediumOrdMap>, - op_bundle_index: MediumOrdMap, - bundle_contract_index: MediumOrdMap, - bundle_witness_index: MediumOrdMap>, - contract_index: TinyOrdMap, - terminal_index: MediumOrdMap>, + op_bundle_children_index: LargeOrdMap>, + op_bundle_index: LargeOrdMap, + bundle_contract_index: LargeOrdMap, + bundle_witness_index: LargeOrdMap>, + contract_index: SmallOrdMap, + terminal_index: LargeOrdMap>, } impl StrictSerialize for MemIndex {} @@ -1322,7 +1062,7 @@ impl IndexReadProvider for MemIndex { fn bundle_ids_children_of_op( &self, opid: OpId, - ) -> Result, IndexReadError> { + ) -> Result, IndexReadError> { self.op_bundle_children_index .get(&opid) .ok_or(IndexInconsistency::BundleAbsent(opid).into()) @@ -1420,7 +1160,7 @@ impl IndexWriteProvider for MemIndex { } None => { self.op_bundle_children_index - .insert(opid, tiny_bset!(bundle_id))?; + .insert(opid, small_bset!(bundle_id))?; } } Ok(present) @@ -1523,7 +1263,7 @@ impl MemIndex { let _ = self.terminal_index.insert(seal, existing_opouts); } None => { - self.terminal_index.insert(seal, tiny_bset![opout])?; + self.terminal_index.insert(seal, medium_bset![opout])?; } } Ok(()) diff --git a/src/persistence/mod.rs b/src/persistence/mod.rs index 321f7b14..75c164fc 100644 --- a/src/persistence/mod.rs +++ b/src/persistence/mod.rs @@ -47,16 +47,16 @@ pub use memory::{ MemContract, MemContractState, MemError, MemGlobalState, MemIndex, MemStash, MemState, }; pub use stash::{ - ProviderError as StashProviderError, SchemaIfaces, Stash, StashDataError, StashError, - StashInconsistency, StashProvider, StashReadProvider, StashWriteProvider, + ProviderError as StashProviderError, Stash, StashDataError, StashError, StashInconsistency, + StashProvider, StashReadProvider, StashWriteProvider, }; pub use state::{ - ContractStateRead, ContractStateWrite, PersistedState, State, StateError, StateInconsistency, - StateProvider, StateReadProvider, StateWriteProvider, + ContractStateRead, ContractStateWrite, State, StateError, StateInconsistency, StateProvider, + StateReadProvider, StateWriteProvider, }; pub use stock::{ - ComposeError, ConsignError, ContractIfaceError, FasciaError, InputError as StockInputError, - Stock, StockError, StockErrorAll, StockErrorMem, UpdateRes, + ComposeError, ConsignError, FasciaError, InputError as StockInputError, Stock, StockError, + StockErrorAll, StockErrorMem, UpdateRes, }; pub trait StoreTransaction { diff --git a/src/persistence/stash.rs b/src/persistence/stash.rs index 0221d488..ae406457 100644 --- a/src/persistence/stash.rs +++ b/src/persistence/stash.rs @@ -19,38 +19,31 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeMap; use std::error::Error; use std::fmt::Debug; use aluvm::library::{Lib, LibId}; -use amplify::confinement::{Confined, MediumBlob, TinyOrdMap}; -use amplify::{confinement, ByteArray}; -use bp::dbc::anchor::MergeError; +use amplify::confinement::Confined; +use amplify::ByteArray; use bp::dbc::tapret::TapretCommitment; -use bp::dbc::Anchor; use bp::seals::txout::CloseMethod; -use commit_verify::mpc; -use commit_verify::mpc::MerkleBlock; +use commit_verify::mpc::{self, MerkleBlock}; use nonasync::persistence::{CloneNoPersistence, Persisting}; -use rgb::validation::{DbcProof, Scripts}; +use rgb::validation::Scripts; use rgb::{ - AttachId, BundleId, ChainNet, ContractId, Extension, Genesis, GraphSeal, Identity, OpId, - Operation, Schema, SchemaId, TransitionBundle, Txid, + BundleId, ChainNet, ContractId, Genesis, GraphSeal, Identity, OpId, Schema, SchemaId, + TransitionBundle, TransitionType, Txid, }; -use strict_encoding::{FieldName, TypeName}; use strict_types::typesys::UnknownType; -use strict_types::TypeSystem; +use strict_types::{FieldName, TypeSystem}; use crate::containers::{ - AnchorSet, Consignment, ConsignmentExt, ContentId, ContentRef, ContentSigs, Kit, SealWitness, - SigBlob, Supplement, TrustLevel, WitnessBundle, + Consignment, ConsignmentExt, Kit, SealWitness, SealWitnessMergeError, WitnessBundle, }; -use crate::interface::{ - ContractBuilder, Iface, IfaceClass, IfaceId, IfaceImpl, IfaceRef, TransitionBuilder, -}; -use crate::persistence::{ContractIfaceError, StoreTransaction}; -use crate::{MergeReveal, MergeRevealError, SecretSeal, LIB_NAME_RGB_STD}; +use crate::contract::{ContractBuilder, TransitionBuilder}; +use crate::persistence::StoreTransaction; +use crate::{MergeReveal, MergeRevealError, SecretSeal}; #[derive(Debug, Display, Error, From)] #[display(inner)] @@ -71,7 +64,7 @@ pub enum StashError { /// Errors caused by invalid input arguments. #[from] #[from(UnknownType)] - #[from(MergeError)] + #[from(SealWitnessMergeError)] #[from(MergeRevealError)] #[from(mpc::InvalidProof)] Data(StashDataError), @@ -82,8 +75,6 @@ pub enum StashError { pub enum ProviderError { #[from] Inconsistency(StashInconsistency), - #[from] - Iface(ContractIfaceError), Connectivity(E), } @@ -92,7 +83,6 @@ impl From::Error>> for match err { ProviderError::Inconsistency(e) => StashError::Inconsistency(e), ProviderError::Connectivity(e) => StashError::ReadProvider(e), - ProviderError::Iface(e) => StashError::Data(StashDataError::NoAbstractIface(e)), } } } @@ -103,18 +93,12 @@ pub enum StashInconsistency { /// library {0} is unknown; perhaps you need to import it first. LibAbsent(LibId), - /// interface {0} is unknown; perhaps you need to import it first. - IfaceAbsent(IfaceRef), - /// contract {0} is unknown. Probably you haven't imported the contract yet. ContractAbsent(ContractId), /// schema {0} is unknown. SchemaAbsent(SchemaId), - /// interface {0::<0} is not implemented for the schema {1::<0}. - IfaceImplAbsent(IfaceId, SchemaId), - /// transition {0} is absent. OperationAbsent(OpId), @@ -135,7 +119,7 @@ pub enum StashInconsistency { #[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] #[display(doc_comments)] pub enum StashDataError { - /// schema {0} and related interfaces use too many AluVM libraries. + /// schema {0} uses too many AluVM libraries. TooManyLibs(SchemaId), #[from] @@ -148,48 +132,11 @@ pub enum StashDataError { #[from] #[display(inner)] - Merge(MergeError), + Merge(SealWitnessMergeError), #[from] #[display(inner)] MergeReveal(MergeRevealError), - - /// schema {0} doesn't implement interface {1}. - NoIfaceImpl(SchemaId, IfaceId), - - #[from] - #[display(inner)] - NoAbstractIface(ContractIfaceError), -} - -#[derive(Clone, Eq, PartialEq, Debug)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_RGB_STD)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", rename_all = "camelCase") -)] -pub struct SchemaIfaces { - pub schema: Schema, - pub iimpls: TinyOrdMap, -} - -impl SchemaIfaces { - pub fn new(schema: Schema) -> Self { - SchemaIfaces { - schema, - iimpls: none!(), - } - } - - pub fn get(&self, id: IfaceId) -> Option<&IfaceImpl> { - self.iimpls.values().find(|iimpl| iimpl.iface_id == id) - } - - pub fn contains(&self, id: IfaceId) -> bool { - self.iimpls.values().any(|iimpl| iimpl.iface_id == id) - } } #[derive(Debug)] @@ -224,37 +171,16 @@ impl Stash

{ #[doc(hidden)] pub(super) fn as_provider_mut(&mut self) -> &mut P { &mut self.provider } - pub(super) fn ifaces(&self) -> Result + '_, StashError

> { - self.provider.ifaces().map_err(StashError::ReadProvider) - } - pub(super) fn iface(&self, iface: impl Into) -> Result<&Iface, StashError

> { - Ok(self.provider.iface(iface)?) - } - pub(super) fn schemata( - &self, - ) -> Result + '_, StashError

> { + pub(super) fn schemata(&self) -> Result + '_, StashError

> { self.provider.schemata().map_err(StashError::ReadProvider) } - pub(super) fn schema(&self, schema_id: SchemaId) -> Result<&SchemaIfaces, StashError

> { + pub(super) fn schema(&self, schema_id: SchemaId) -> Result<&Schema, StashError

> { Ok(self.provider.schema(schema_id)?) } - pub(super) fn impl_for<'a, C: IfaceClass + 'a>( - &'a self, - schema_ifaces: &'a SchemaIfaces, - ) -> Result<&'a IfaceImpl, StashError

> { - Ok(self.provider.impl_for::(schema_ifaces)?) - } pub(super) fn geneses(&self) -> Result + '_, StashError

> { self.provider.geneses().map_err(StashError::ReadProvider) } - pub(super) fn geneses_by<'a, C: IfaceClass + 'a>( - &'a self, - ) -> Result + 'a, StashError

> { - self.provider - .geneses_by::() - .map_err(StashError::ReadProvider) - } pub(super) fn genesis(&self, contract_id: ContractId) -> Result<&Genesis, StashError

> { Ok(self.provider.genesis(contract_id)?) } @@ -265,41 +191,8 @@ impl Stash

{ Ok(self.provider.witness(witness_id)?) } - pub(super) fn supplements( - &self, - content_ref: ContentRef, - ) -> Result + '_, StashError

> { - self.provider - .supplements(content_ref) - .map_err(StashError::ReadProvider) - } - - pub(super) fn sigs_for( - &self, - content_id: &ContentId, - ) -> Result, StashError

> { - self.provider - .sigs_for(content_id) - .map_err(StashError::ReadProvider) - } - - pub(super) fn supplement( - &self, - content_ref: ContentRef, - ) -> Result, StashError

> { - self.provider - .supplement(content_ref) - .map_err(StashError::ReadProvider) - } - - pub(super) fn extract<'a>( - &self, - schema: &Schema, - ifaces: impl IntoIterator, - ) -> Result<(TypeSystem, Scripts), StashError

> { - let type_iter = schema - .types() - .chain(ifaces.into_iter().flat_map(Iface::types)); + pub(super) fn extract(&self, schema: &Schema) -> Result<(TypeSystem, Scripts), StashError

> { + let type_iter = schema.types(); let types = self .provider .type_system() @@ -321,103 +214,40 @@ impl Stash

{ &self, issuer: Identity, schema_id: SchemaId, - iface: impl Into, chain_net: ChainNet, ) -> Result> { - let schema_ifaces = self.schema(schema_id)?; - let iface = self.iface(iface)?; - let iface_id = iface.iface_id(); - let iimpl = schema_ifaces - .get(iface_id) - .ok_or(StashDataError::NoIfaceImpl(schema_id, iface_id))?; - - let (types, scripts) = self.extract(&schema_ifaces.schema, [iface])?; - - let builder = ContractBuilder::with( - issuer, - iface.clone(), - schema_ifaces.schema.clone(), - iimpl.clone(), - types, - scripts, - chain_net, - ); + let schema = self.schema(schema_id)?; + + let (types, scripts) = self.extract(schema)?; + + let builder = ContractBuilder::with(issuer, schema.clone(), types, scripts, chain_net); Ok(builder) } pub(super) fn transition_builder( &self, contract_id: ContractId, - iface: impl Into, - transition_name: Option>, + transition_name: impl Into, ) -> Result> { - let schema_ifaces = self.provider.contract_schema(contract_id)?; - let iface = self.iface(iface)?; - let schema = &schema_ifaces.schema; - let iimpl = schema_ifaces - .get(iface.iface_id()) - .ok_or(StashDataError::NoIfaceImpl(schema.schema_id(), iface.iface_id()))?; - - let (types, _) = self.extract(&schema_ifaces.schema, [iface])?; - - let builder = if let Some(transition_name) = transition_name { - TransitionBuilder::named_transition( - contract_id, - iface.clone(), - schema.clone(), - iimpl.clone(), - transition_name.into(), - types, - ) - } else { - TransitionBuilder::default_transition( - contract_id, - iface.clone(), - schema.clone(), - iimpl.clone(), - types, - ) - } - .expect("internal inconsistency"); + let schema = self.provider.contract_schema(contract_id)?; + let (types, _) = self.extract(schema)?; + + let transition_type = schema.transition_type(transition_name); + let builder = TransitionBuilder::with(contract_id, schema.clone(), transition_type, types); Ok(builder) } - pub(super) fn blank_builder( + pub(super) fn transition_builder_raw( &self, contract_id: ContractId, - iface: impl Into, + transition_type: TransitionType, ) -> Result> { - let schema_ifaces = self.provider.contract_schema(contract_id)?; - let iface = self.iface(iface)?; - let schema = &schema_ifaces.schema; - if schema_ifaces.iimpls.is_empty() { - return Err(StashDataError::NoIfaceImpl(schema.schema_id(), iface.iface_id()).into()); - } + let schema = self.provider.contract_schema(contract_id)?; - let (types, _) = self.extract(&schema_ifaces.schema, [iface])?; - - let builder = if let Some(iimpl) = schema_ifaces.get(iface.iface_id()) { - TransitionBuilder::blank_transition( - contract_id, - iface.clone(), - schema.clone(), - iimpl.clone(), - types, - ) - } else { - let (default_iface_name, default_iimpl) = - schema_ifaces.iimpls.first_key_value().unwrap(); - let default_iface = self.iface(default_iface_name.clone())?; - - TransitionBuilder::blank_transition( - contract_id, - default_iface.clone(), - schema.clone(), - default_iimpl.clone(), - types, - ) - }; + let (types, _) = self.extract(schema)?; + + let builder = TransitionBuilder::with(contract_id, schema.clone(), transition_type, types); Ok(builder) } @@ -432,35 +262,11 @@ impl Stash

{ .map_err(StashError::WriteProvider)?; } - // TODO: filter most trusted signers for schema in kit.schemata { self.provider .replace_schema(schema) .map_err(StashError::WriteProvider)?; } - for iface in kit.ifaces { - self.provider - .replace_iface(iface) - .map_err(StashError::WriteProvider)?; - } - for iimpl in kit.iimpls { - self.provider - .replace_iimpl(iimpl) - .map_err(StashError::WriteProvider)?; - } - - // TODO: filter out non-trusted signers - for suppl in kit.supplements { - self.provider - .add_supplement(suppl) - .map_err(StashError::WriteProvider)?; - } - - for (content_id, sigs) in kit.signatures { - // TODO: Filter sigs by trust level - // Do not bother if we can't import all the sigs - self.provider.import_sigs(content_id, sigs).ok(); - } Ok(()) } @@ -484,53 +290,26 @@ impl Stash

{ let contract_id = consignment.contract_id(); let genesis = match self.genesis(contract_id) { - Ok(g) => g.clone().merge_reveal(consignment.genesis)?, + Ok(g) => { + let mut g = g.clone(); + g.merge_reveal(&consignment.genesis)?; + g + } Err(_) => consignment.genesis, }; self.provider .replace_genesis(genesis) .map_err(StashError::WriteProvider)?; - for extension in consignment.extensions { - let opid = extension.id(); - let extension = match self.provider.extension(opid) { - Ok(e) => e.clone().merge_reveal(extension)?, - Err(_) => extension, - }; - self.provider - .replace_extension(extension) - .map_err(StashError::WriteProvider)?; - } - for witness_bundles in consignment.bundles { self.consume_witness_bundle(contract_id, witness_bundles)?; } - for (id, attach) in consignment.attachments { - self.provider - .replace_attachment(id, attach) - .map_err(StashError::WriteProvider)?; - } - - let (ifaces, iimpls): (BTreeSet<_>, BTreeSet<_>) = consignment - .ifaces - .release() - .into_iter() - .fold((bset!(), bset!()), |(mut keys, mut values), (k, v)| { - keys.insert(k); - values.insert(v); - (keys, values) - }); - self.consume_kit(Kit { version: consignment.version, - ifaces: Confined::from_checked(ifaces), schemata: tiny_bset![consignment.schema], - iimpls: Confined::from_checked(iimpls), - supplements: consignment.supplements, types: consignment.types, scripts: Confined::from_checked(consignment.scripts.release()), - signatures: consignment.signatures, }) } @@ -539,53 +318,34 @@ impl Stash

{ contract_id: ContractId, witness_bundle: WitnessBundle, ) -> Result<(), StashError

> { - let WitnessBundle { - pub_witness, - anchored_bundle, - } = witness_bundle; - - // TODO: Save pub witness transaction SPVs - - let eanchor = anchored_bundle.eanchor(); - let bundle = anchored_bundle.into_bundle(); + let bundle = witness_bundle.bundle(); + let eanchor = witness_bundle.eanchor(); let bundle_id = bundle.bundle_id(); - self.consume_bundle(bundle)?; + self.consume_bundle(bundle.clone())?; let proto = mpc::ProtocolId::from_byte_array(contract_id.to_byte_array()); let msg = mpc::Message::from_byte_array(bundle_id.to_byte_array()); let merkle_block = MerkleBlock::with(&eanchor.mpc_proof, proto, msg)?; - let anchor = Anchor::new(merkle_block, eanchor.dbc_proof); - - let anchor = match anchor { - Anchor { - dbc_proof: DbcProof::Opret(opret), - mpc_proof, - .. - } => AnchorSet::Opret(Anchor::new(mpc_proof, opret)), - Anchor { - dbc_proof: DbcProof::Tapret(opret), - mpc_proof, - .. - } => AnchorSet::Tapret(Anchor::new(mpc_proof, opret)), - }; + let witness = SealWitness { - public: pub_witness.clone(), - anchor, + public: witness_bundle.pub_witness.clone(), + merkle_block, + dbc_proof: eanchor.dbc_proof, }; - self.consume_witness(witness)?; + self.consume_witness(&witness)?; Ok(()) } - pub(crate) fn consume_witness(&mut self, witness: SealWitness) -> Result> { + pub(crate) fn consume_witness(&mut self, witness: &SealWitness) -> Result> { let witness = match self.provider.witness(witness.witness_id()).cloned() { - Ok(mut w) => { - w.public = w.public.clone().merge_reveal(witness.public)?; - w.anchor = w.anchor.clone().merge_reveal(witness.anchor)?; + Ok(w) => { + let mut w = w.clone(); + w.merge_reveal(witness)?; w } - Err(_) => witness, + Err(_) => witness.clone(), }; self.provider @@ -598,7 +358,11 @@ impl Stash

{ bundle: TransitionBundle, ) -> Result> { let bundle = match self.provider.bundle(bundle.bundle_id()).cloned() { - Ok(b) => b.merge_reveal(bundle)?, + Ok(b) => { + let mut b = b.clone(); + b.merge_reveal(&bundle)?; + b + } Err(_) => bundle, }; self.provider @@ -648,42 +412,22 @@ pub trait StashReadProvider { fn type_system(&self) -> Result<&TypeSystem, Self::Error>; fn lib(&self, id: LibId) -> Result<&Lib, ProviderError>; - fn ifaces(&self) -> Result, Self::Error>; - fn iface(&self, iface: impl Into) -> Result<&Iface, ProviderError>; - fn schemata(&self) -> Result, Self::Error>; - fn schema(&self, schema_id: SchemaId) -> Result<&SchemaIfaces, ProviderError>; - fn schemata_by( - &self, - ) -> Result, Self::Error>; - fn impl_for<'a, C: IfaceClass + 'a>( - &'a self, - schema_ifaces: &'a SchemaIfaces, - ) -> Result<&'a IfaceImpl, ProviderError>; + fn schemata(&self) -> Result, Self::Error>; + fn schema(&self, schema_id: SchemaId) -> Result<&Schema, ProviderError>; fn geneses(&self) -> Result, Self::Error>; - fn geneses_by(&self) -> Result, Self::Error>; fn genesis(&self, contract_id: ContractId) -> Result<&Genesis, ProviderError>; fn contract_schema( &self, contract_id: ContractId, - ) -> Result<&SchemaIfaces, ProviderError> { + ) -> Result<&Schema, ProviderError> { let genesis = self.genesis(contract_id)?; self.schema(genesis.schema_id) } - fn get_trust(&self, identity: &Identity) -> Result; - fn supplement(&self, content_ref: ContentRef) -> Result, Self::Error>; - fn supplements( - &self, - content_ref: ContentRef, - ) -> Result, Self::Error>; - - fn sigs_for(&self, content_id: &ContentId) -> Result, Self::Error>; fn witness_ids(&self) -> Result, Self::Error>; fn bundle_ids(&self) -> Result, Self::Error>; fn bundle(&self, bundle_id: BundleId) -> Result<&TransitionBundle, ProviderError>; - fn extension_ids(&self) -> Result, Self::Error>; - fn extension(&self, op_id: OpId) -> Result<&Extension, ProviderError>; fn witness(&self, witness_id: Txid) -> Result<&SealWitness, ProviderError>; fn taprets(&self) -> Result, Self::Error>; @@ -695,25 +439,12 @@ pub trait StashWriteProvider: StoreTransaction { type Error: Error; fn replace_schema(&mut self, schema: Schema) -> Result; - fn replace_iface(&mut self, iface: Iface) -> Result; - fn replace_iimpl(&mut self, iimpl: IfaceImpl) -> Result; fn replace_genesis(&mut self, genesis: Genesis) -> Result; - fn replace_extension(&mut self, extension: Extension) -> Result; fn replace_bundle(&mut self, bundle: TransitionBundle) -> Result; fn replace_witness(&mut self, witness: SealWitness) -> Result; - fn replace_attachment(&mut self, id: AttachId, attach: MediumBlob) - -> Result; fn replace_lib(&mut self, lib: Lib) -> Result; fn consume_types(&mut self, types: TypeSystem) -> Result<(), Self::Error>; - fn set_trust( - &mut self, - identity: Identity, - trust: TrustLevel, - ) -> Result<(), confinement::Error>; - fn add_supplement(&mut self, suppl: Supplement) -> Result<(), Self::Error>; - fn import_sigs(&mut self, content_id: ContentId, sigs: I) -> Result<(), Self::Error> - where I: IntoIterator; fn add_secret_seal(&mut self, seal: GraphSeal) -> Result; } diff --git a/src/persistence/state.rs b/src/persistence/state.rs index c41132ae..2a66ae3e 100644 --- a/src/persistence/state.rs +++ b/src/persistence/state.rs @@ -20,19 +20,16 @@ // limitations under the License. use std::borrow::Borrow; -use std::collections::BTreeMap; use std::error::Error; use std::fmt::Debug; -use std::iter; use amplify::confinement::{LargeOrdMap, LargeOrdSet}; -use invoice::Amount; use nonasync::persistence::{CloneNoPersistence, Persisting}; use rgb::validation::{ResolveWitness, WitnessResolverError}; use rgb::vm::{ContractStateAccess, WitnessOrd}; use rgb::{ - AttachState, BundleId, ContractId, DataState, Extension, Genesis, Operation, RevealedAttach, - RevealedData, RevealedValue, Schema, SchemaId, Transition, TransitionBundle, Txid, VoidState, + BundleId, ContractId, Genesis, RevealedData, RevealedValue, Schema, SchemaId, Transition, + TransitionBundle, Txid, VoidState, }; use crate::containers::{ConsignmentExt, ToWitnessId}; @@ -74,16 +71,6 @@ pub enum StateInconsistency { AbsentWitness(Txid), } -#[derive(Clone, Eq, PartialEq, Debug, Hash)] -pub enum PersistedState { - Void, - Amount(Amount), - // TODO: Use RevealedData - Data(DataState, u128), - // TODO: Use RevealedAttach - Attachment(AttachState, u64), -} - #[derive(Debug)] pub struct State { provider: P, @@ -129,18 +116,27 @@ impl State

{ pub fn select_valid_witness( &self, witness_ids: impl IntoIterator>, - ) -> Result> { - for witness_id in witness_ids { - let witness_id = *witness_id.borrow(); - if self - .provider - .is_valid_witness(witness_id) - .map_err(StateError::ReadProvider)? - { - return Ok(witness_id); - } + ) -> Result<(Txid, WitnessOrd), StateError

> { + let witnesses = self.as_provider().witnesses(); + let mut best_candidate = None; + for id in witness_ids { + let id = *id.borrow(); + let Some(&ord) = witnesses.get(&id) else { + return Err(StateError::Inconsistency(StateInconsistency::AbsentWitness(id))); + }; + best_candidate = match best_candidate { + Some((_, curr_ord)) if ord < curr_ord => Some((id, ord)), + None => Some((id, ord)), + _ => best_candidate, + }; + } + + let (best_id, best_ord) = best_candidate.expect("one witness ID should always be there"); + if best_ord == WitnessOrd::Archived { + Err(StateError::AbsentValidWitness) + } else { + Ok((best_id, best_ord)) } - Err(StateError::AbsentValidWitness) } pub fn update_from_bundle( @@ -176,12 +172,6 @@ impl State

{ .as_provider_mut() .register_contract(consignment.schema(), consignment.genesis()) .map_err(StateError::WriteProvider)?; - let mut extension_idx = consignment - .extensions() - .map(Extension::id) - .zip(iter::repeat(false)) - .collect::>(); - let mut ordered_extensions = BTreeMap::new(); for witness_bundle in consignment.bundled_witnesses() { let bundle = witness_bundle.bundle(); let bundle_id = bundle.bundle_id(); @@ -194,35 +184,8 @@ impl State

{ state .add_transition(transition, witness_id, witness_ord, bundle_id) .map_err(StateError::WriteProvider)?; - for (id, used) in &mut extension_idx { - if *used { - continue; - } - for input in &transition.inputs { - if input.prev_out.op == *id { - *used = true; - if let Some((_, witness_ord2)) = ordered_extensions.get_mut(id) { - if *witness_ord2 < witness_ord { - *witness_ord2 = witness_ord; - } - } else { - ordered_extensions.insert(*id, (witness_id, witness_ord)); - } - } - } - } } } - for extension in consignment.extensions() { - if let Some((witness_id, witness_ord)) = ordered_extensions.get(&extension.id()) { - state - .add_extension(extension, *witness_id, *witness_ord) - .map_err(StateError::WriteProvider)?; - } - // Otherwise consignment includes state extensions which are not - // used in transaction graph. This must not be the case for the - // validated consignments. - } Ok(()) } @@ -277,8 +240,6 @@ pub trait StateReadProvider { contract_id: ContractId, ) -> Result, Self::Error>; - fn is_valid_witness(&self, witness_id: Txid) -> Result; - fn witnesses(&self) -> LargeOrdMap; fn invalid_bundles(&self) -> LargeOrdSet; @@ -316,7 +277,6 @@ pub trait ContractStateRead: ContractStateAccess { fn rights_all(&self) -> impl Iterator>; fn fungible_all(&self) -> impl Iterator>; fn data_all(&self) -> impl Iterator>; - fn attach_all(&self) -> impl Iterator>; } pub trait ContractStateWrite { @@ -331,11 +291,4 @@ pub trait ContractStateWrite { witness_ord: WitnessOrd, bundle_id: BundleId, ) -> Result<(), Self::Error>; - - fn add_extension( - &mut self, - extension: &Extension, - witness_id: Txid, - witness_ord: WitnessOrd, - ) -> Result<(), Self::Error>; } diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index 103bd160..13b6e60a 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -26,42 +26,37 @@ use std::error::Error; use std::fmt::Debug; use std::num::NonZeroU32; -use amplify::confinement::{Confined, LargeOrdSet, U24}; -use amplify::Wrapper; -use bp::seals::txout::CloseMethod; -use bp::{Outpoint, Txid, Vout}; -use chrono::Utc; -use invoice::{Amount, Beneficiary, InvoiceState, NonFungible, RgbInvoice}; +use amplify::confinement::{Confined, LargeOrdSet}; +use bp::dbc::{Anchor, Proof}; +use bp::{Outpoint, Txid}; use nonasync::persistence::{CloneNoPersistence, PersistenceError, PersistenceProvider}; -use rgb::validation::{DbcProof, ResolveWitness, WitnessResolverError}; +use rgb::validation::{ResolveWitness, UnsafeHistoryMap, WitnessResolverError}; use rgb::vm::WitnessOrd; use rgb::{ - validation, AssignmentType, BundleId, ChainNet, ContractId, DataState, GraphSeal, Identity, - OpId, Operation, Opout, OutputSeal, SchemaId, SecretSeal, Transition, + validation, AssignmentType, BundleId, ChainNet, ContractId, GraphSeal, Identity, OpId, + Operation, Opout, OutputSeal, Schema, SchemaId, SecretSeal, Transition, TransitionType, + UnrelatedTransition, }; -use strict_encoding::FieldName; +use strict_types::FieldName; use super::{ ContractStateRead, Index, IndexError, IndexInconsistency, IndexProvider, IndexReadProvider, - IndexWriteProvider, MemIndex, MemStash, MemState, PersistedState, SchemaIfaces, Stash, - StashDataError, StashError, StashInconsistency, StashProvider, StashReadProvider, - StashWriteProvider, State, StateError, StateInconsistency, StateProvider, StateReadProvider, - StateWriteProvider, StoreTransaction, + IndexWriteProvider, MemIndex, MemStash, MemState, Stash, StashDataError, StashError, + StashInconsistency, StashProvider, StashReadProvider, StashWriteProvider, State, StateError, + StateInconsistency, StateProvider, StateReadProvider, StateWriteProvider, StoreTransaction, }; use crate::containers::{ - AnchorSet, AnchoredBundleMismatch, Batch, BuilderSeal, ClientBundle, Consignment, ContainerVer, - ContentId, ContentRef, Contract, Fascia, Kit, SealWitness, SupplItem, SupplSub, Transfer, - TransitionInfo, TransitionInfoError, UnrelatedTransition, ValidConsignment, ValidContract, - ValidKit, ValidTransfer, VelocityHint, WitnessBundle, SUPPL_ANNOT_VELOCITY, + Consignment, ContainerVer, Contract, Fascia, Kit, Transfer, TransitionInfoError, + ValidConsignment, ValidContract, ValidKit, ValidTransfer, WitnessBundle, }; -use crate::info::{ContractInfo, IfaceInfo, SchemaInfo}; -use crate::interface::{ - BuilderError, ContractBuilder, ContractIface, Iface, IfaceClass, IfaceId, IfaceRef, - IfaceWrapper, TransitionBuilder, +use crate::contract::{ + AllocatedState, BuilderError, ContractBuilder, ContractData, IssuerWrapper, SchemaWrapper, + TransitionBuilder, }; +use crate::info::{ContractInfo, SchemaInfo}; use crate::MergeRevealError; -pub type ContractAssignments = HashMap>; +pub type ContractAssignments = HashMap>; #[derive(Debug, Display, Error, From)] #[display(inner)] @@ -156,11 +151,6 @@ impl From From Self { Self::InvalidInput(err.into()) } } -impl From - for StockError -{ - fn from(err: AnchoredBundleMismatch) -> Self { Self::InvalidInput(err.into()) } -} - #[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] #[display(doc_comments)] pub enum ComposeError { - /// no outputs available to store state of type {1} with velocity class - /// '{0}'. - NoBlankOrChange(VelocityHint, AssignmentType), + /// no outputs available to store state of type {0} + NoExtraOrChange(AssignmentType), /// the provided PSBT doesn't pay any sats to the RGB beneficiary address. NoBeneficiaryOutput, @@ -224,15 +203,9 @@ pub enum ComposeError { /// expired invoice. InvoiceExpired, - /// Invoice requesting chain-network pair {0} but contract commits to a different one ({1}) - InvoiceBeneficiaryWrongChainNet(ChainNet, ChainNet), - /// the invoice contains no contract information. NoContract, - /// the invoice contains no interface information. - NoIface, - /// the invoice requirements can't be fulfilled using available assets or /// smart contract state. InsufficientState, @@ -245,9 +218,9 @@ pub enum ComposeError { #[display(inner)] Transition(TransitionInfoError), - /// the operation produces too many blank state transitions which can't fit + /// the operation produces too many extra state transitions which can't fit /// the container requirements. - TooManyBlanks, + TooManyExtras, #[from] #[display(inner)] @@ -279,20 +252,6 @@ impl From fn from(err: FasciaError) -> Self { Self::InvalidInput(err) } } -#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] -#[display(doc_comments)] -pub enum ContractIfaceError { - /// no known implementations of {0::<0} parent interfaces for - /// the schema {1::<0}. - NoAbstractImpl(IfaceId, SchemaId), -} - -impl From - for StockError -{ - fn from(err: ContractIfaceError) -> Self { Self::InvalidInput(err) } -} - #[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] #[display(inner)] pub enum InputError { @@ -302,8 +261,6 @@ pub enum InputError { Consign(ConsignError), #[from] Fascia(FasciaError), - #[from] - ContractIface(ContractIfaceError), } macro_rules! stock_err_conv { @@ -345,19 +302,14 @@ impl From for ConsignError { impl From for FasciaError { fn from(_: Infallible) -> Self { unreachable!() } } -impl From for ContractIfaceError { - fn from(_: Infallible) -> Self { unreachable!() } -} stock_err_conv!(Infallible, ComposeError); stock_err_conv!(Infallible, ConsignError); stock_err_conv!(Infallible, FasciaError); -stock_err_conv!(Infallible, ContractIfaceError); stock_err_conv!(Infallible, InputError); stock_err_conv!(ComposeError, InputError); stock_err_conv!(ConsignError, InputError); stock_err_conv!(FasciaError, InputError); -stock_err_conv!(ContractIfaceError, InputError); pub type StockErrorMem = StockError; pub type StockErrorAll = StockError; @@ -476,28 +428,10 @@ impl Stock { #[doc(hidden)] pub fn as_index_provider_mut(&mut self) -> &mut P { self.index.as_provider_mut() } - pub fn ifaces(&self) -> Result + '_, StockError> { - let names = self - .stash - .ifaces()? - .map(|iface| (iface.iface_id(), iface.name.clone())) - .collect::>(); - Ok(self.stash.ifaces()?.map(move |iface| { - let suppl = self - .stash - .supplement(ContentRef::Iface(iface.iface_id())) - .ok() - .flatten(); - IfaceInfo::new(iface, &names, suppl) - })) - } - pub fn iface(&self, iface: impl Into) -> Result<&Iface, StockError> { - Ok(self.stash.iface(iface)?) - } pub fn schemata(&self) -> Result + '_, StockError> { Ok(self.stash.schemata()?.map(SchemaInfo::with)) } - pub fn schema(&self, schema_id: SchemaId) -> Result<&SchemaIfaces, StockError> { + pub fn schema(&self, schema_id: SchemaId) -> Result<&Schema, StockError> { Ok(self.stash.schema(schema_id)?) } @@ -507,23 +441,6 @@ impl Stock { Ok(self.stash.geneses()?.map(ContractInfo::with)) } - #[allow(clippy::multiple_bound_locations, clippy::type_complexity)] - pub fn contracts_by<'a, C: IfaceClass + 'a>( - &'a self, - ) -> Result< - impl Iterator< - Item = > as IfaceWrapper>>::Info, - > + 'a, - StockError, - > { - Ok(self.stash.geneses_by::()?.filter_map(|genesis| { - self.contract_iface_class::(genesis.contract_id()) - .as_ref() - .map(> as IfaceWrapper>>::info) - .ok() - })) - } - /// Iterates over ids of all contract assigning state to the provided set of /// output seals. pub fn contracts_assigning( @@ -541,11 +458,11 @@ impl Stock { fn contract_raw( &self, contract_id: ContractId, - ) -> Result<(&SchemaIfaces, H::ContractRead<'_>, ContractInfo), StockError> { + ) -> Result<(&Schema, H::ContractRead<'_>, ContractInfo), StockError> { let state = self.state.contract_state(contract_id)?; let schema_id = state.schema_id(); - let schema_ifaces = self.stash.schema(schema_id)?; - Ok((schema_ifaces, state, self.contract_info(contract_id)?)) + let schema = self.stash.schema(schema_id)?; + Ok((schema, state, self.contract_info(contract_id)?)) } pub fn contract_info( @@ -564,46 +481,26 @@ impl Stock { .map_err(StockError::from) } - #[allow(clippy::multiple_bound_locations, clippy::type_complexity)] - pub fn contract_iface_class( + pub fn contract_wrapper( &self, contract_id: ContractId, - ) -> Result>, StockError> { - let (schema_ifaces, state, info) = self.contract_raw(contract_id)?; - let iimpl = self.stash.impl_for::(schema_ifaces)?; - - let iface = self.stash.iface(iimpl.iface_id)?; - let (types, _) = self.stash.extract(&schema_ifaces.schema, [iface])?; - - Ok(C::Wrapper::with(ContractIface { - state, - schema: schema_ifaces.schema.clone(), - iface: iimpl.clone(), - types, - info, - })) + ) -> Result>, StockError> { + let contract_data = self.contract_data(contract_id)?; + Ok(C::Wrapper::with(contract_data)) } - /// Returns the best matching abstract interface to a contract. - pub fn contract_iface( + /// Returns the contract data for the given contract ID + pub fn contract_data( &self, contract_id: ContractId, - iface: impl Into, - ) -> Result>, StockError> { - let (schema_ifaces, state, info) = self.contract_raw(contract_id)?; - let iface = self.stash.iface(iface)?; - let iface_id = iface.iface_id(); - - let iimpl = iface.find_abstractable_impl(schema_ifaces).ok_or_else(|| { - ContractIfaceError::NoAbstractImpl(iface_id, schema_ifaces.schema.schema_id()) - })?; + ) -> Result>, StockError> { + let (schema, state, info) = self.contract_raw(contract_id)?; - let (types, _) = self.stash.extract(&schema_ifaces.schema, [iface])?; + let (types, _) = self.stash.extract(schema)?; - Ok(ContractIface { + Ok(ContractData { state, - schema: schema_ifaces.schema.clone(), - iface: iimpl.clone(), + schema: schema.clone(), types, info, }) @@ -619,24 +516,23 @@ impl Stock { let state = self.contract_state(contract_id)?; let mut res = - HashMap::>::with_capacity(outputs.len()); + HashMap::>::with_capacity(outputs.len()); for item in state.fungible_all() { let outpoint = item.seal.into(); if outputs.contains::(&outpoint) { res.entry(item.seal) .or_default() - .insert(item.opout, PersistedState::Amount(item.state.value.into())); + .insert(item.opout, AllocatedState::Amount(item.state)); } } for item in state.data_all() { let outpoint = item.seal.into(); if outputs.contains::(&outpoint) { - res.entry(item.seal).or_default().insert( - item.opout, - PersistedState::Data(item.state.value.clone(), item.state.salt), - ); + res.entry(item.seal) + .or_default() + .insert(item.opout, AllocatedState::Data(item.state.clone())); } } @@ -645,17 +541,7 @@ impl Stock { if outputs.contains::(&outpoint) { res.entry(item.seal) .or_default() - .insert(item.opout, PersistedState::Void); - } - } - - for item in state.attach_all() { - let outpoint = item.seal.into(); - if outputs.contains::(&outpoint) { - res.entry(item.seal).or_default().insert( - item.opout, - PersistedState::Attachment(item.state.clone().into(), item.state.salt), - ); + .insert(item.opout, AllocatedState::Void); } } @@ -666,47 +552,38 @@ impl Stock { &self, issuer: impl Into, schema_id: SchemaId, - iface: impl Into, chain_net: ChainNet, ) -> Result> { Ok(self .stash - .contract_builder(issuer.into(), schema_id, iface, chain_net)?) + .contract_builder(issuer.into(), schema_id, chain_net)?) } pub fn transition_builder( &self, contract_id: ContractId, - iface: impl Into, - transition_name: Option>, + transition_name: impl Into, ) -> Result> { Ok(self .stash - .transition_builder(contract_id, iface, transition_name)?) + .transition_builder(contract_id, transition_name)?) } - pub fn blank_builder( + pub fn transition_builder_raw( &self, contract_id: ContractId, - iface: impl Into, + transition_type: TransitionType, ) -> Result> { - Ok(self.stash.blank_builder(contract_id, iface)?) + Ok(self + .stash + .transition_builder_raw(contract_id, transition_type)?) } pub fn export_schema(&self, schema_id: SchemaId) -> Result> { let mut kit = Kit::default(); - let schema_ifaces = self.schema(schema_id)?; - kit.schemata - .push(schema_ifaces.schema.clone()) - .expect("single item"); - for name in schema_ifaces.iimpls.keys() { - let iface = self.stash.iface(name.clone())?; - kit.ifaces.push(iface.clone()).expect("type guarantees"); - } - kit.iimpls - .extend(schema_ifaces.iimpls.values().cloned()) - .expect("type guarantees"); - let (types, scripts) = self.stash.extract(&schema_ifaces.schema, &kit.ifaces)?; + let schema = self.schema(schema_id)?; + kit.schemata.push(schema.clone()).expect("single item"); + let (types, scripts) = self.stash.extract(schema)?; kit.scripts .extend(scripts.into_values()) .expect("type guarantees"); @@ -742,20 +619,6 @@ impl Stock { ) -> Result, StockError> { let outputs = outputs.as_ref(); - // Initialize supplements with btree set - let mut supplements = bset![]; - // Initialize signatures with btree map - let mut signatures = bmap! {}; - // Get genesis signature by contract id - self.stash - .sigs_for(&ContentId::Genesis(contract_id))? - .map(|genesis_sig| { - signatures.insert(ContentId::Genesis(contract_id), genesis_sig.clone()) - }); - // Get genesis supplement by contract id - self.stash - .supplement(ContentRef::Genesis(contract_id))? - .map(|genesis_suppl| supplements.insert(genesis_suppl.clone())); // 1. Collect initial set of anchored bundles // 1.1. Get all public outputs let mut opouts = self.index.public_opouts(contract_id)?; @@ -768,7 +631,7 @@ impl Stock { opouts.extend(self.index.opouts_by_terminals(secret_seal.into_iter())?); // 1.3. Collect all state transitions assigning state to the provided outpoints - let mut anchored_bundles = BTreeMap::::new(); + let mut bundles = BTreeMap::::new(); let mut transitions = BTreeMap::::new(); let mut terminals = BTreeMap::::new(); for opout in opouts { @@ -800,338 +663,66 @@ impl Stock { } } - if let Entry::Vacant(entry) = anchored_bundles.entry(bundle_id) { - entry.insert(self.client_bundle(bundle_id)?); + if let Entry::Vacant(entry) = bundles.entry(bundle_id) { + entry.insert(self.witness_bundle(bundle_id)?); } } + let is_asset_replacement = + |tt: TransitionType, at: AssignmentType| -> bool { tt.is_replace() && at.is_asset() }; + // 2. Collect all state transitions between terminals and genesis let mut ids = vec![]; for transition in transitions.values() { - ids.extend(transition.inputs().iter().map(|input| input.prev_out.op)); + ids.extend(transition.inputs().iter().map(|input| { + (input.op, is_asset_replacement(transition.transition_type, input.ty)) + })); } - while let Some(id) = ids.pop() { + while let Some((id, asset_replacement)) = ids.pop() { if id == contract_id { continue; // we skip genesis since it will be present anywhere } let transition = self.transition(id)?; - ids.extend(transition.inputs().iter().map(|input| input.prev_out.op)); - transitions.insert(id, transition.clone()); + if !asset_replacement { + ids.extend(transition.inputs().iter().map(|input| { + (input.op, is_asset_replacement(transition.transition_type, input.ty)) + })); + } let bundle_id = self.index.bundle_id_for_op(transition.id())?; - anchored_bundles + bundles .entry(bundle_id) - .or_insert(self.client_bundle(bundle_id)?.clone()) + .or_insert(self.witness_bundle(bundle_id)?.clone()) + .bundle .reveal_transition(transition.clone())?; } let genesis = self.stash.genesis(contract_id)?.clone(); - // Get schema signature by schema id - self.stash - .sigs_for(&ContentId::Schema(genesis.schema_id))? - .map(|schema_signature| { - signatures.insert(ContentId::Schema(genesis.schema_id), schema_signature.clone()) - }); - // Get schema supplement by schema id - self.stash - .supplement(ContentRef::Schema(genesis.schema_id))? - .map(|schema_suppl| supplements.insert(schema_suppl.clone())); - - let schema_ifaces = self.stash.schema(genesis.schema_id)?.clone(); - let mut ifaces = BTreeMap::new(); - for (iface_id, iimpl) in schema_ifaces.iimpls { - let iface = self.stash.iface(iface_id)?; - // Get iface and iimpl signatures by iface id and iimpl id - self.stash - .sigs_for(&ContentId::Iface(iface.iface_id()))? - .map(|iface_signature| { - signatures.insert(ContentId::Iface(iface.iface_id()), iface_signature.clone()) - }); - self.stash - .sigs_for(&ContentId::IfaceImpl(iimpl.impl_id()))? - .map(|iimpl_signature| { - signatures - .insert(ContentId::IfaceImpl(iimpl.impl_id()), iimpl_signature.clone()) - }); - // Get iface and iimpl supplement by iface id and iimpl id - self.stash - .supplement(ContentRef::Iface(iface.iface_id()))? - .map(|iface_suppl| supplements.insert(iface_suppl.clone())); - - self.stash - .supplement(ContentRef::IfaceImpl(iimpl.impl_id()))? - .map(|iimpl_suppl| supplements.insert(iimpl_suppl.clone())); - - ifaces.insert(iface.clone(), iimpl); - } - let ifaces = Confined::from_checked(ifaces); - - let mut bundles = BTreeMap::::new(); - for anchored_bundle in anchored_bundles.into_values() { - let witness_ids = self.index.bundle_info(anchored_bundle.bundle_id())?.0; - let witness_id = self.state.select_valid_witness(witness_ids)?; - let pub_witness = self.stash.witness(witness_id)?.public.clone(); - let wb = WitnessBundle::with(pub_witness, anchored_bundle); - let res = bundles.insert(witness_id, wb); - debug_assert!(res.is_none()); - } + + let schema = self.stash.schema(genesis.schema_id)?.clone(); + let bundles = Confined::try_from_iter(bundles.into_values()) .map_err(|_| ConsignError::TooManyBundles)?; let terminals = Confined::try_from(terminals).map_err(|_| ConsignError::TooManyTerminals)?; - let (types, scripts) = self.stash.extract(&schema_ifaces.schema, ifaces.keys())?; + let (types, scripts) = self.stash.extract(&schema)?; let scripts = Confined::from_iter_checked(scripts.into_values()); - let supplements = - Confined::try_from(supplements).map_err(|_| ConsignError::TooManySupplements)?; - let signatures = - Confined::try_from(signatures).map_err(|_| ConsignError::TooManySignatures)?; // TODO: Conceal everything we do not need - // TODO: Add known sigs to the consignment Ok(Consignment { - version: ContainerVer::V2, + version: ContainerVer::V0, transfer: TRANSFER, - schema: schema_ifaces.schema, - ifaces, + schema, genesis, terminals, bundles, - extensions: none!(), - attachments: none!(), - signatures, - supplements, types, scripts, }) } - /// Composes a batch of state transitions updating state for the provided - /// set of previous outputs, satisfying requirements of the invoice, paying - /// the change back and including the necessary blank state transitions. - #[allow(clippy::result_large_err)] - pub fn compose( - &self, - invoice: &RgbInvoice, - prev_outputs: impl IntoIterator>, - beneficiary_vout: Option>, - allocator: impl Fn(ContractId, AssignmentType, VelocityHint) -> Option, - ) -> Result> { - self.compose_deterministic( - invoice, - prev_outputs, - beneficiary_vout, - u64::MAX, - allocator, - |_, _| rand::random(), - ) - } - - /// Composes a batch of state transitions updating state for the provided - /// set of previous outputs, satisfying requirements of the invoice, paying - /// the change back and including the necessary blank state transitions. - #[allow(clippy::too_many_arguments, clippy::result_large_err)] - pub fn compose_deterministic( - &self, - invoice: &RgbInvoice, - prev_outputs: impl IntoIterator>, - beneficiary_vout: Option>, - priority: u64, - allocator: impl Fn(ContractId, AssignmentType, VelocityHint) -> Option, - seal_blinder: impl Fn(ContractId, AssignmentType) -> u64, - ) -> Result> { - let prev_outputs = prev_outputs - .into_iter() - .map(|o| o.into()) - .collect::>(); - - #[allow(clippy::type_complexity)] - let output_for_assignment = - |id: ContractId, - assignment_type: AssignmentType| - -> Result, StockError> { - let mut suppl = self.stash.supplements(ContentRef::Genesis(id))?; - let velocity = suppl - .next() - .and_then(|suppl| { - suppl - .get( - SupplSub::Assignment, - SupplItem::TypeNo(assignment_type.to_inner()), - SUPPL_ANNOT_VELOCITY, - ) - .transpose() - .ok() - .flatten() - }) - .unwrap_or_default(); - let vout = allocator(id, assignment_type, velocity) - .ok_or(ComposeError::NoBlankOrChange(velocity, assignment_type))?; - let seal = GraphSeal::with_blinded_vout(vout, seal_blinder(id, assignment_type)); - Ok(BuilderSeal::Revealed(seal)) - }; - - // 1. Prepare the data - if let Some(expiry) = invoice.expiry { - if expiry < Utc::now().timestamp() { - return Err(ComposeError::InvoiceExpired.into()); - } - } - let contract_id = invoice.contract.ok_or(ComposeError::NoContract)?; - let iface = invoice.iface.as_ref().ok_or(ComposeError::NoIface)?; - let mut main_builder = - self.transition_builder(contract_id, iface.clone(), invoice.operation.clone())?; - let assignment_name = invoice - .assignment - .as_ref() - .or_else(|| main_builder.default_assignment().ok()) - .ok_or(BuilderError::NoDefaultAssignment)? - .clone(); - let assignment_id = main_builder - .assignments_type(&assignment_name) - .ok_or(BuilderError::InvalidStateField(assignment_name.clone()))?; - - let contract_genesis = self.stash.genesis(contract_id)?; - let contract_chain_net = contract_genesis.chain_net; - let invoice_chain_net = invoice.chain_network(); - if contract_chain_net != invoice_chain_net { - return Err(ComposeError::InvoiceBeneficiaryWrongChainNet( - invoice_chain_net, - contract_chain_net, - ) - .into()); - } - - let beneficiary = match (invoice.beneficiary.into_inner(), beneficiary_vout) { - (Beneficiary::BlindedSeal(seal), None) => BuilderSeal::Concealed(seal), - (Beneficiary::BlindedSeal(_), Some(_)) => { - return Err(ComposeError::BeneficiaryVout.into()); - } - (Beneficiary::WitnessVout(_), Some(vout)) => { - let blinding = seal_blinder(contract_id, assignment_id); - let seal = GraphSeal::with_blinded_vout(vout, blinding); - BuilderSeal::Revealed(seal) - } - (Beneficiary::WitnessVout(_), None) => { - return Err(ComposeError::NoBeneficiaryOutput.into()); - } - }; - - // 2. Prepare transition - let mut main_inputs = Vec::::new(); - let mut sum_inputs = Amount::ZERO; - let mut data_inputs = vec![]; - - for (output, list) in - self.contract_assignments_for(contract_id, prev_outputs.iter().copied())? - { - main_inputs.push(output); - for (opout, state) in list { - main_builder = main_builder.add_input(opout, state.clone())?; - if opout.ty != assignment_id { - let seal = output_for_assignment(contract_id, opout.ty)?; - main_builder = main_builder.add_owned_state_raw(opout.ty, seal, state)?; - } else if let PersistedState::Amount(value) = state { - sum_inputs += value; - } else if let PersistedState::Data(value, _) = state { - data_inputs.push(value); - } - } - } - // Add payments to beneficiary and change - match invoice.owned_state.clone() { - InvoiceState::Amount(amt) => { - // Pay beneficiary - if sum_inputs < amt { - return Err(ComposeError::InsufficientState.into()); - } - - if amt > Amount::ZERO { - main_builder = - main_builder.add_fungible_state_raw(assignment_id, beneficiary, amt)?; - } - - // Pay change - if sum_inputs > amt { - let change_seal = output_for_assignment(contract_id, assignment_id)?; - main_builder = main_builder.add_fungible_state_raw( - assignment_id, - change_seal, - sum_inputs - amt, - )?; - } - } - InvoiceState::Data(data) => match data { - NonFungible::RGB21(allocation) => { - let lookup_state = DataState::from(allocation); - if !data_inputs.into_iter().any(|x| x == lookup_state) { - return Err(ComposeError::InsufficientState.into()); - } - - let seal = seal_blinder(contract_id, assignment_id); - main_builder = - main_builder.add_data_raw(assignment_id, beneficiary, allocation, seal)?; - } - }, - _ => { - todo!( - "only PersistedState::Amount and PersistedState::Allocation are currently \ - supported" - ) - } - } - - // 3. Prepare other transitions - // Enumerate state - let mut blank_state = - HashMap::>>::new(); - for id in self.contracts_assigning(prev_outputs.iter().copied())? { - // Skip current contract - if id == contract_id { - continue; - } - let state = self.contract_assignments_for(id, prev_outputs.iter().copied())?; - let entry = blank_state.entry(id).or_default(); - for (seal, assigns) in state { - entry.entry(seal).or_default().extend(assigns); - } - } - - // Construct blank transitions - let mut blanks = Confined::, 0, { U24 - 1 }>::with_capacity(blank_state.len()); - for (id, list) in blank_state { - let mut blank_builder = self.blank_builder(id, iface.clone())?; - let mut outputs = Vec::with_capacity(list.len()); - for (output, assigns) in list { - outputs.push(output); - for (opout, state) in assigns { - let seal = output_for_assignment(id, opout.ty)?; - blank_builder = blank_builder - .add_input(opout, state.clone())? - .add_owned_state_raw(opout.ty, seal, state)? - } - } - if !blank_builder.has_inputs() { - continue; - } - let transition = blank_builder.complete_transition()?; - let info = TransitionInfo::new(transition, outputs) - .map_err(|_| ComposeError::TooManyInputs)?; - blanks.push(info).map_err(|_| ComposeError::TooManyBlanks)?; - } - - if !main_builder.has_inputs() { - return Err(ComposeError::InsufficientState.into()); - } - - let main = TransitionInfo::new(main_builder.complete_transition()?, main_inputs) - .map_err(|_| ComposeError::TooManyInputs)?; - let mut batch = Batch { main, blanks }; - batch.set_priority(priority); - Ok(batch) - } - fn store_transaction( &mut self, f: impl FnOnce( @@ -1218,8 +809,7 @@ impl Stock { ) -> Result<(), StockError> { self.store_transaction(move |stash, state, index| { let witness_id = fascia.witness_id(); - stash - .consume_witness(SealWitness::new(fascia.witness.clone(), fascia.anchor.clone()))?; + stash.consume_witness(&fascia.seal_witness)?; for (contract_id, bundle) in fascia.into_bundles() { let ids1 = bundle @@ -1227,7 +817,11 @@ impl Stock { .keys() .copied() .collect::>(); - let ids2 = bundle.input_map.values().copied().collect::>(); + let ids2 = bundle + .input_map + .values() + .flat_map(|opids| opids.to_unconfined()) + .collect::>(); if !ids1.is_subset(&ids2) { return Err(FasciaError::InvalidBundle(contract_id, bundle.bundle_id()).into()); } @@ -1249,35 +843,26 @@ impl Stock { .ok_or(ConsignError::Concealed(bundle_id, opid).into()) } - fn client_bundle(&self, bundle_id: BundleId) -> Result> { + fn witness_bundle(&self, bundle_id: BundleId) -> Result> { let (witness_ids, contract_id) = self.index.bundle_info(bundle_id)?; - let bundle = self.stash.bundle(bundle_id)?.clone(); - let witness_id = self.state.select_valid_witness(witness_ids)?; + let (witness_id, _) = self.state.select_valid_witness(witness_ids)?; let witness = self.stash.witness(witness_id)?; - let (merkle_block, dbc, close_method) = match &witness.anchor { - AnchorSet::Tapret(tapret) => ( - &tapret.mpc_proof, - DbcProof::Tapret(tapret.dbc_proof.clone()), - CloseMethod::TapretFirst, - ), - AnchorSet::Opret(opret) => { - (&opret.mpc_proof, DbcProof::Opret(opret.dbc_proof), CloseMethod::OpretFirst) - } - }; - let Ok(mpc_proof) = merkle_block.to_merkle_proof(contract_id.into()) else { + let pub_witness = witness.public.clone(); + let Ok(mpc_proof) = witness.merkle_block.to_merkle_proof(contract_id.into()) else { return Err(StashInconsistency::WitnessMissesContract( witness_id, bundle_id, contract_id, - close_method, + witness.dbc_proof.method(), ) .into()); }; + let anchor = Anchor::new(mpc_proof, witness.dbc_proof.clone()); // TODO: Conceal all transitions except the one we need - Ok(ClientBundle::new(mpc_proof, dbc, bundle)) + Ok(WitnessBundle::with(pub_witness, anchor, bundle)) } pub fn store_secret_seal(&mut self, seal: GraphSeal) -> Result> { @@ -1317,7 +902,7 @@ impl Stock { // recursively visit bundle ancestors for transition in bundle.known_transitions.values() { for input in &transition.inputs { - let input_opid = input.prev_out.op; + let input_opid = input.op; let input_bundle_id = match self.index.bundle_id_for_op(input_opid) { Ok(id) => Some(id), Err(IndexError::Inconsistency(IndexInconsistency::BundleAbsent(_))) => { @@ -1357,7 +942,7 @@ impl Stock { Ok(bundle_ids) => bundle_ids, Err(IndexError::Inconsistency(IndexInconsistency::BundleAbsent(_))) => { // this transition has no children yet - tiny_bset![] + small_bset![] } Err(e) => return Err(e.into()), }; @@ -1395,8 +980,7 @@ impl Stock { // save witnesses that became valid or invalid if let Some(valid) = bundle_valid { let seal_witness = self.stash.witness(*id)?; - let anchor_set = seal_witness.anchor.clone(); - let bundle_ids: BTreeSet<_> = anchor_set.known_bundle_ids().collect(); + let bundle_ids: BTreeSet<_> = seal_witness.known_bundle_ids().collect(); if valid { became_valid_witnesses.insert(*id, bundle_ids); } else { @@ -1486,6 +1070,80 @@ impl Stock { self.state.commit_transaction()?; Ok(UpdateRes { succeeded, failed }) } + + fn _check_bundle_history( + &self, + bundle_id: &BundleId, + safe_height: NonZeroU32, + contract_history: &mut HashMap>>, + ) -> Result<(), StockError> { + let (bundle_witness_ids, contract_id) = self.index.bundle_info(*bundle_id)?; + let (witness_id, ord) = self.state.select_valid_witness(bundle_witness_ids)?; + match ord { + WitnessOrd::Mined(witness_pos) => { + let witness_height = witness_pos.height(); + if witness_height > safe_height { + contract_history + .entry(contract_id) + .or_default() + .entry(witness_height.into()) + .or_default() + .insert(witness_id); + } + } + WitnessOrd::Tentative | WitnessOrd::Ignored | WitnessOrd::Archived => { + contract_history + .entry(contract_id) + .or_default() + .entry(0) + .or_default() + .insert(witness_id); + } + } + + // recursively check bundle ancestors + let bundle = self.stash.bundle(*bundle_id)?.clone(); + for transition in bundle.known_transitions.values() { + for input in &transition.inputs { + let input_opid = input.op; + let input_bundle_id = match self.index.bundle_id_for_op(input_opid) { + Ok(id) => Some(id), + Err(IndexError::Inconsistency(IndexInconsistency::BundleAbsent(_))) => { + // reached genesis + None + } + Err(e) => return Err(e.into()), + }; + + if let Some(input_bundle_id) = input_bundle_id { + self._check_bundle_history(&input_bundle_id, safe_height, contract_history)?; + } + } + } + + Ok(()) + } + + pub fn get_outpoint_unsafe_history( + &self, + outpoint: Outpoint, + safe_height: NonZeroU32, + ) -> Result, StockError> { + let mut contract_history: HashMap>> = HashMap::new(); + + for id in self.contracts_assigning([outpoint])? { + let state = self.contract_assignments_for(id, [outpoint])?; + for opid in state + .iter() + .flat_map(|(_, assigns)| assigns.keys().map(|opout| opout.op)) + { + let bundle_id = self.index.bundle_id_for_op(opid)?; + self._check_bundle_history(&bundle_id, safe_height, &mut contract_history)?; + } + } + + Ok(contract_history) + } } #[derive(Clone, Eq, PartialEq, Debug)] @@ -1496,11 +1154,9 @@ pub struct UpdateRes { #[cfg(test)] mod test { - use std::str::FromStr; - use baid64::FromBaid64Str; + use bp::Vout; use commit_verify::{Conceal, DigestExt, Sha256}; - use strict_encoding::TypeName; use super::*; use crate::containers::ConsignmentExt; @@ -1516,7 +1172,7 @@ mod test { ContractId::from_baid64_str("rgb:qFuT6DN8-9AuO95M-7R8R8Mc-AZvs7zG-obum1Va-BRnweKk") .unwrap(); if let Ok(transfer) = stock.consign::(contract_id, [], Some(secret_seal), None) { - println!("{:?}", transfer.supplements) + println!("{:?}", transfer) } } @@ -1541,45 +1197,15 @@ mod test { } } - #[test] - fn test_blank_builder_ifaceid() { - let stock = Stock::in_memory(); - let hasher = Sha256::default(); - let iface_id = IfaceId::from(hasher.clone()); - let bytes_hash = hasher.finish(); - let contract_id = ContractId::copy_from_slice(bytes_hash).unwrap(); - if let Ok(builder) = stock.blank_builder(contract_id, IfaceRef::Id(iface_id)) { - println!("{:?}", builder.transition_type()) - } - } - - #[test] - fn test_blank_builder_ifacename() { - let stock = Stock::in_memory(); - let hasher = Sha256::default(); - let bytes_hash = hasher.finish(); - let contract_id = ContractId::copy_from_slice(bytes_hash).unwrap(); - if let Ok(builder) = - stock.blank_builder(contract_id, IfaceRef::Name(TypeName::from_str("RGB20").unwrap())) - { - println!("{:?}", builder.transition_type()) - } - } - #[test] fn test_transition_builder() { let stock = Stock::in_memory(); let hasher = Sha256::default(); - let iface_id = IfaceId::from(hasher.clone()); let bytes_hash = hasher.finish(); let contract_id = ContractId::copy_from_slice(bytes_hash).unwrap(); - if let Ok(builder) = stock.transition_builder( - contract_id, - IfaceRef::Id(iface_id), - Some(FieldName::from_str("transfer").unwrap()), - ) { + if let Ok(builder) = stock.transition_builder(contract_id, "transfer") { println!("{:?}", builder.transition_type()) } } diff --git a/src/stl/mod.rs b/src/stl/mod.rs index d2d84c82..b1fb70f2 100644 --- a/src/stl/mod.rs +++ b/src/stl/mod.rs @@ -31,13 +31,14 @@ use error::Error; pub use invoice::LIB_NAME_RGB_CONTRACT; pub use mime::{MediaRegName, MediaType}; pub use specs::{ - Article, AssetSpec, Attachment, BurnMeta, ContractSpec, ContractTerms, Details, IssueMeta, - Name, RicardianContract, Ticker, + Article, AssetSpec, Attachment, AttachmentName, AttachmentType, BurnMeta, ContractSpec, + ContractTerms, Details, EmbeddedMedia, IssueMeta, Name, OpidRejectUrl, RicardianContract, + Ticker, TokenData, }; pub use stl::{ - aluvm_stl, bp_core_stl, bp_tx_stl, commit_verify_stl, rgb_commit_stl, rgb_contract_stl, - rgb_logic_stl, rgb_std_stl, rgb_storage_stl, StandardTypes, LIB_ID_RGB_COMMIT, - LIB_ID_RGB_CONTRACT, LIB_ID_RGB_LOGIC, LIB_ID_RGB_STD, LIB_ID_RGB_STORAGE, + aluvm_stl, bp_consensus_stl, bp_core_stl, bp_tx_stl, commit_verify_stl, rgb_commit_stl, + rgb_contract_stl, rgb_logic_stl, rgb_std_stl, rgb_storage_stl, StandardTypes, + LIB_ID_RGB_COMMIT, LIB_ID_RGB_CONTRACT, LIB_ID_RGB_LOGIC, LIB_ID_RGB_STD, LIB_ID_RGB_STORAGE, }; pub const LIB_NAME_RGB_STD: &str = "RGBStd"; diff --git a/src/stl/specs.rs b/src/stl/specs.rs index f51afc5d..3db573f8 100644 --- a/src/stl/specs.rs +++ b/src/stl/specs.rs @@ -21,17 +21,21 @@ #![allow(unused_braces)] // caused by rustc unable to understand strict_dumb +use std::collections::BTreeMap; use std::fmt::{self, Debug, Formatter}; use std::hash::{Hash, Hasher}; use std::str::FromStr; -use amplify::confinement::{Confined, NonEmptyString, SmallOrdSet, SmallString, U8}; +use amplify::ascii::AsciiString; +use amplify::confinement::{ + Confined, NonEmptyString, NonEmptyVec, SmallBlob, SmallOrdSet, SmallString, U8, +}; use amplify::Bytes32; -use invoice::Precision; +use invoice::{Precision, TokenIndex}; use strict_encoding::stl::{Alpha, AlphaNum, AsciiPrintable}; use strict_encoding::{ InvalidRString, RString, StrictDeserialize, StrictDumb, StrictEncode, StrictSerialize, - StrictType, + StrictType, TypedWrite, }; use strict_types::StrictVal; @@ -408,3 +412,209 @@ impl ContractTerms { Self { text, media } } } + +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct EmbeddedMedia { + #[strict_type(rename = "type")] + #[cfg_attr(feature = "serde", serde(rename = "type"))] + pub ty: MediaType, + pub data: SmallBlob, +} + +impl EmbeddedMedia { + pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { + let ty = MediaType::from_strict_val_unchecked(value.unwrap_struct("type")); + let data = SmallBlob::from_iter_checked( + value.unwrap_struct("data").unwrap_bytes().iter().copied(), + ); + + Self { ty, data } + } +} + +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT, dumb = { AttachmentType::with(0, "dumb") })] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct AttachmentType { + pub id: u8, + pub name: AttachmentName, +} + +impl AttachmentType { + pub fn with(id: u8, name: &'static str) -> AttachmentType { + AttachmentType { + id, + name: AttachmentName::from(name), + } + } +} + +#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From)] +#[wrapper(Deref, Display)] +#[derive(StrictType, StrictDumb, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT, dumb = { AttachmentName::from("dumb") })] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct AttachmentName(Confined); +impl StrictEncode for AttachmentName { + fn strict_encode(&self, writer: W) -> std::io::Result { + let iter = self + .0 + .as_bytes() + .iter() + .map(|c| AsciiPrintable::try_from(*c).unwrap()); + writer + .write_newtype::(&NonEmptyVec::::try_from_iter(iter).unwrap()) + } +} + +// TODO: Ensure all constructors filter invalid characters +impl FromStr for AttachmentName { + type Err = InvalidRString; + + fn from_str(s: &str) -> Result { + let s = AsciiString::from_ascii(s.as_bytes())?; + let s = Confined::try_from_iter(s.chars())?; + Ok(Self(s)) + } +} + +impl From<&'static str> for AttachmentName { + fn from(s: &'static str) -> Self { Self::from_str(s).expect("invalid attachment name") } +} + +impl TryFrom for AttachmentName { + type Error = InvalidRString; + + fn try_from(name: String) -> Result { + let name = AsciiString::from_ascii(name.as_bytes())?; + let s = Confined::try_from(name)?; + Ok(Self(s)) + } +} + +impl Debug for AttachmentName { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_tuple("AttachmentName") + .field(&self.as_str()) + .finish() + } +} + +#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct TokenData { + pub index: TokenIndex, + pub ticker: Option, + pub name: Option, + pub details: Option

, + pub preview: Option, + pub media: Option, + pub attachments: Confined, 0, 20>, + pub reserves: Option, +} + +impl StrictSerialize for TokenData {} +impl StrictDeserialize for TokenData {} + +impl TokenData { + pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { + let index = TokenIndex::from( + value + .unwrap_struct("index") + .unwrap_num() + .unwrap_uint::(), + ); + let ticker = value + .unwrap_struct("ticker") + .unwrap_option() + .map(|x| Ticker::from_str(&x.unwrap_string()).expect("invalid uda ticker")); + + let name = value + .unwrap_struct("name") + .unwrap_option() + .map(|x| Name::from_str(&x.unwrap_string()).expect("invalid uda name")); + + let details = value + .unwrap_struct("details") + .unwrap_option() + .map(|x| Details::from_str(&x.unwrap_string()).expect("invalid uda details")); + + let preview = value + .unwrap_struct("preview") + .unwrap_option() + .map(EmbeddedMedia::from_strict_val_unchecked); + let media = value + .unwrap_struct("media") + .unwrap_option() + .map(Attachment::from_strict_val_unchecked); + + let attachments = if let StrictVal::Map(list) = value.unwrap_struct("attachments") { + Confined::from_iter_checked( + list.iter() + .map(|(k, v)| (k.unwrap_uint(), Attachment::from_strict_val_unchecked(v))), + ) + } else { + Confined::default() + }; + + let reserves = value + .unwrap_struct("reserves") + .unwrap_option() + .map(ProofOfReserves::from_strict_val_unchecked); + Self { + index, + ticker, + name, + details, + preview, + media, + attachments, + reserves, + } + } +} + +#[derive(Wrapper, Clone, Eq, PartialEq, Hash, From)] +#[wrapper(Deref, Display, FromStr)] +#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_RGB_CONTRACT)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct OpidRejectUrl(RString); + +impl StrictSerialize for OpidRejectUrl {} +impl StrictDeserialize for OpidRejectUrl {} + +impl_ident_type!(OpidRejectUrl); +impl_ident_subtype!(OpidRejectUrl); + +impl OpidRejectUrl { + pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { + OpidRejectUrl::from_str(&value.unwrap_string()).unwrap() + } +} diff --git a/src/stl/stl.rs b/src/stl/stl.rs index 62554f30..3b484ab9 100644 --- a/src/stl/stl.rs +++ b/src/stl/stl.rs @@ -19,19 +19,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use bp::bc::stl::bp_tx_stl; +pub use bp::bc::stl::{bp_consensus_stl, bp_tx_stl}; pub use bp::stl::bp_core_stl; #[allow(unused_imports)] pub use commit_verify::stl::{commit_verify_stl, LIB_ID_COMMIT_VERIFY}; use invoice::{Allocation, Amount}; pub use rgb::stl::{aluvm_stl, rgb_commit_stl, rgb_logic_stl, LIB_ID_RGB_COMMIT, LIB_ID_RGB_LOGIC}; +use rgb::Schema; use strict_types::stl::{std_stl, strict_types_stl}; use strict_types::typesys::SystemBuilder; use strict_types::{CompileError, LibBuilder, SemId, SymbolicSys, TypeLib, TypeSystem}; use super::{ - AssetSpec, BurnMeta, ContractSpec, ContractTerms, Error, IssueMeta, MediaType, - LIB_NAME_RGB_CONTRACT, LIB_NAME_RGB_STORAGE, + AssetSpec, AttachmentType, BurnMeta, ContractSpec, ContractTerms, EmbeddedMedia, Error, + IssueMeta, MediaType, OpidRejectUrl, TokenData, LIB_NAME_RGB_CONTRACT, LIB_NAME_RGB_STORAGE, }; use crate::containers::{Contract, Kit, Transfer}; use crate::persistence::{MemIndex, MemStash, MemState}; @@ -41,28 +42,30 @@ use crate::LIB_NAME_RGB_STD; /// Strict types id for the library providing standard data types which may be /// used in RGB smart contracts. pub const LIB_ID_RGB_STORAGE: &str = - "stl:AOyFCu23-oOZoMMm-ErRT1U!-rpjrpSt-IAXu8FP-s1NpBXQ#spark-sandra-alice"; + "stl:HWQT7tdF-Lqa1hg5-irH6cgG-Ot7VIra-ZFcTzDK-NPRnpDc#chess-open-nepal"; /// Strict types id for the library providing standard data types which may be /// used in RGB smart contracts. pub const LIB_ID_RGB_CONTRACT: &str = - "stl:!r5yXt4a-v3XXv0M-E9Z6eoh-BFZweik-fxS6CB4-8AaO!MM#rover-annual-disney"; + "stl:1uyMC~lT-xPK57Lr-IgIhB0r-WxYd9io-2wZav_s-6TbR4LY#nuclear-liquid-sonic"; /// Strict types id for the library representing of RGB StdLib data types. pub const LIB_ID_RGB_STD: &str = - "stl:68OpONV0-a6jRyu4-WwnfWw$-NmcHSI0-kpc!Ppp-YBckCAo#lazarus-list-uniform"; + "stl:LxiMjmBl-MRIFHb1-pitHq43-IPC2~cM-SHQA3hl-mGfDECY#studio-cycle-analyze"; fn _rgb_std_stl() -> Result { - LibBuilder::new(libname!(LIB_NAME_RGB_STD), tiny_bset! { + // TODO: wait for fix in strict_types to use LibBuilder::with + #[allow(deprecated)] + LibBuilder::new(libname!(LIB_NAME_RGB_STD), [ std_stl().to_dependency(), strict_types_stl().to_dependency(), commit_verify_stl().to_dependency(), - bp_tx_stl().to_dependency(), + bp_consensus_stl().to_dependency(), bp_core_stl().to_dependency(), aluvm_stl().to_dependency(), rgb_commit_stl().to_dependency(), rgb_logic_stl().to_dependency(), - }) + ]) .transpile::() .transpile::() .transpile::() @@ -70,10 +73,10 @@ fn _rgb_std_stl() -> Result { } fn _rgb_contract_stl() -> Result { - LibBuilder::new(libname!(LIB_NAME_RGB_CONTRACT), tiny_bset! { - std_stl().to_dependency(), - bp_tx_stl().to_dependency() - }) + LibBuilder::with(libname!(LIB_NAME_RGB_CONTRACT), [ + std_stl().to_dependency_types(), + bp_consensus_stl().to_dependency_types(), + ]) .transpile::() .transpile::() .transpile::() @@ -83,11 +86,17 @@ fn _rgb_contract_stl() -> Result { .transpile::() .transpile::() .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() .compile() } fn _rgb_storage_stl() -> Result { - LibBuilder::new(libname!(LIB_NAME_RGB_STORAGE), tiny_bset! { + // TODO: wait for fix in strict_types to use LibBuilder::with + #[allow(deprecated)] + LibBuilder::new(libname!(LIB_NAME_RGB_STORAGE), [ std_stl().to_dependency(), strict_types_stl().to_dependency(), commit_verify_stl().to_dependency(), @@ -96,8 +105,8 @@ fn _rgb_storage_stl() -> Result { aluvm_stl().to_dependency(), rgb_commit_stl().to_dependency(), rgb_logic_stl().to_dependency(), - rgb_std_stl().to_dependency() - }) + rgb_std_stl().to_dependency(), + ]) .transpile::() .transpile::() .transpile::() @@ -122,18 +131,9 @@ pub fn rgb_storage_stl() -> TypeLib { #[derive(Debug)] pub struct StandardTypes(SymbolicSys); -impl Default for StandardTypes { - fn default() -> Self { StandardTypes::new() } -} - impl StandardTypes { - pub fn new() -> Self { - Self::try_with([std_stl(), bp_tx_stl(), rgb_contract_stl()]) - .expect("error in standard RGBContract type system") - } - pub fn with(lib: TypeLib) -> Self { - Self::try_with([std_stl(), bp_tx_stl(), rgb_contract_stl(), lib]) + Self::try_with([std_stl(), bp_consensus_stl(), rgb_contract_stl(), lib]) .expect("error in standard RGBContract type system") } @@ -147,7 +147,9 @@ impl StandardTypes { Ok(Self(sys)) } - pub fn type_system(&self) -> TypeSystem { self.0.as_types().clone() } + pub fn type_system(&self, schema: Schema) -> TypeSystem { + self.0.as_types().extract(schema.types()).unwrap() + } pub fn get(&self, name: &'static str) -> SemId { *self.0.resolve(name).unwrap_or_else(|| { diff --git a/stl/IfaceStd.con b/stl/IfaceStd.con deleted file mode 100644 index 37380a20..00000000 --- a/stl/IfaceStd.con +++ /dev/null @@ -1,252 +0,0 @@ -@version(1) -@timestamp(1711405444) -interface NamedAsset - global spec: RGBContract.AssetSpec - global terms: RGBContract.AssetTerms - - genesis: abstract - globals: spec, terms - - -@version(1) -@timestamp(1711405444) -interface RenameableAsset - - public updateRight: Rights - - genesis: override - assigns: updateRight - - transition rename: required, final - globals: spec - assigns: updateRight(?) - default: updateRight - inputs: updateRight - - -@version(1) -@timestamp(1711405444) -interface FungibleAsset - global issuedSupply: RGBContract.Amount - - owned assetOwner(*): Zk64 - - error nonEqualAmounts - "the sum of spent assets doesn't equal to the sum of assets in outputs" - error supplyMismatch - "supply specified as a global parameter doesn't match the issued supply allocated to the asset owners" - - genesis: override - errors: insufficientReserves, invalidProof, supplyMismatch - globals: issuedSupply - assigns: assetOwner(*) - - transition transfer: required, default, abstract - errors: nonEqualAmounts - assigns: assetOwner(+) - default: assetOwner - inputs: assetOwner(+) - - -@version(1) -@timestamp(1711405444) -interface FixedAsset - - owned assetOwner(+): Zk64 - - genesis: override - errors: insufficientReserves, invalidProof, supplyMismatch - assigns: assetOwner(+) - - -@version(1) -@timestamp(1711405444) -interface BurnableAsset - global burnedSupply(*): RGBContract.Amount - - public burnRight(+): Rights - - error insufficientCoverage - "the claimed amount of burned assets is not covered by the assets in the operation inputs" - - genesis: override - assigns: burnRight(+) - - transition burn: required, final - errors: insufficientCoverage, invalidProof, supplyMismatch - meta: RGBContract.BurnMeta - globals: burnedSupply - assigns: burnRight(*) - inputs: burnRight - - -@version(1) -@timestamp(1711405444) -interface InflatableAsset - global issuedSupply(+): RGBContract.Amount - - public inflationAllowance(*): Zk64 - - error issueExceedsAllowance - "you try to issue more assets than allowed by the contract terms" - - genesis: override - assigns: inflationAllowance(+) - - transition issue: required, abstract - errors: issueExceedsAllowance, supplyMismatch - globals: issuedSupply - assigns: assetOwner(*), inflationAllowance(*) - default: assetOwner - inputs: inflationAllowance(+) - - -@version(1) -@timestamp(1711405444) -interface ReplaceableAsset - global burnedSupply(*): RGBContract.Amount - global replacedSupply(*): RGBContract.Amount - - public burnEpoch(+): Rights - public burnRight(*): Rights - - error insufficientCoverage - "the claimed amount of burned assets is not covered by the assets in the operation inputs" - - genesis: override - assigns: burnEpoch - - transition burn: required, final - errors: insufficientCoverage, invalidProof, supplyMismatch - meta: RGBContract.BurnMeta - globals: burnedSupply - assigns: burnRight(?) - inputs: burnRight - - transition openEpoch: required, final - assigns: burnEpoch(?), burnRight - default: burnRight - inputs: burnEpoch - - transition replace: required, final - errors: insufficientCoverage, invalidProof, nonEqualAmounts, supplyMismatch - meta: RGBContract.BurnMeta - globals: replacedSupply - assigns: assetOwner(*), burnRight(?) - default: assetOwner - inputs: burnRight - - -@version(1) -@timestamp(1711405444) -interface ReservableAsset - - error insufficientReserves - "reserve is insufficient to cover the issued assets" - error invalidProof - "the provided proof is invalid" - - genesis: override - errors: insufficientReserves, invalidProof - meta: RGBContract.IssueMeta - - transition issue: override - errors: insufficientReserves, invalidProof - meta: RGBContract.IssueMeta - default: assetOwner - inputs: - - -@version(1) -@timestamp(1711405444) -interface NonFungibleToken - global attachmentTypes(*): RGB21.AttachmentType - global tokens(*): RGB21.TokenData - - owned assetOwner(*): RGB21.Allocation - - error fractionOverflow - "the amount of fractional token in outputs exceeds 1" - error invalidAttachmentType - "attachment has a type which is not allowed for the token" - error nonEqualValues - "the sum of spent token fractions doesn't equal to the sum of token fractions in outputs" - error nonFractionalToken - "attempt to transfer a fraction of non-fractionable token" - - genesis: override - errors: fractionOverflow, invalidAttachmentType - globals: attachmentTypes(*), tokens(*) - assigns: assetOwner(*) - - transition transfer: required, default, final - errors: fractionOverflow, nonEqualValues, nonFractionalToken - assigns: assetOwner(+) - default: assetOwner - inputs: assetOwner(+) - - -@version(1) -@timestamp(1711405444) -interface EngravableNft - global engravings(*): RGB21.EngravingData - - error nonEngravableToken - "attempt to engrave on a token which prohibit engraving" - - genesis: override - - transition engrave: required, final - errors: fractionOverflow, nonEngravableToken, nonEqualValues, nonFractionalToken - globals: engravings - assigns: assetOwner(+) - default: assetOwner - inputs: assetOwner(+) - - -@version(1) -@timestamp(1711405444) -interface UniqueNft - global attachmentTypes: RGB21.AttachmentType - global tokens: RGB21.TokenData - - owned assetOwner(+): RGB21.Allocation - - genesis: override - globals: attachmentTypes, tokens - assigns: assetOwner(+) - - -@version(1) -@timestamp(1711405444) -interface LimitedNft - global attachmentTypes(+): RGB21.AttachmentType - global tokens(+): RGB21.TokenData - - owned assetOwner(+): RGB21.Allocation - - genesis: override - globals: attachmentTypes(+), tokens(+) - assigns: assetOwner(+) - - -@version(1) -@timestamp(1711405444) -interface IssuableNft - - public inflationAllowance(+): RGB21.ItemsCount - - error issueExceedsAllowance - "you try to issue more assets than allowed by the contract terms" - - genesis: override - assigns: inflationAllowance(+) - - transition issue: required, abstract - errors: fractionOverflow, insufficientReserves, invalidAttachmentType, invalidProof, issueExceedsAllowance - globals: attachmentTypes(*), tokens(*) - assigns: assetOwner(*), inflationAllowance(*) - default: assetOwner - inputs: inflationAllowance(+) - - diff --git a/stl/RGBContract@0.11.0.sta b/stl/RGBContract@0.11.0.sta index 50e247d3..26537f19 100644 --- a/stl/RGBContract@0.11.0.sta +++ b/stl/RGBContract@0.11.0.sta @@ -1,52 +1,66 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:!r5yXt4a-v3XXv0M-E9Z6eoh-BFZweik-fxS6CB4-8AaO!MM#rover-annual-disney +Id: stl:1uyMC~lT-xPK57Lr-IgIhB0r-WxYd9io-2wZav_s-6TbR4LY#nuclear-liquid-sonic Name: RGBContract Dependencies: - Std#ralph-blue-lucky, - Bitcoin#signal-color-cipher -Check-SHA256: 6347d5f0a4c36a074fd3b6abb98041f64798a4a233e1742a352edc330dddbf3d + Std#delete-roman-hair, + Bitcoin#quiz-patent-exit +Check-SHA256: cd08b8b1d553bb24f87554499a11ec5f7b9268f8ea1835e9243c54e2864ebb4a -3sOfyLvL<$a$#e10?I5NZ-bfLFbqC#o>4E?M+l67UG^w8*<_XZ#%uyqCj(P-Wc6$lVk7oBr%DNv+($;q -`HHK!gIHa)*%m(-e#9sm3I{@IbYpL6ZUP5FX>?<6X>J1mA>%$n#j0HLDJN5-IKgM_J7b(p+0MPGk2Gl) +3sOfyLvL<$a$#e10)mO_O%DrjRIhYP1?a)oog)LLTw}}6rDvG=`c^zKY6DYrWWh(oW+jcb^C>NgzlT_m +3wFmfDB@ZlUF_{Gi(YuS4F^JLbYpL6ZUP5FX>?<6X>J1mA>%$n#j0HLDJN5-IKgM_J7b(p+0MPGk2Gl) y2(Rz1Xgc#bfbbo^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1Rs>XdX=LbXK+Rkw`Mu(V|7oQWGN(Z+ AyvH&RuaL#N1_Q*>km07$+g7b@t4MVjY>G@u4Q3HlB(d+LiLJm-R=h;`?dxDG*c V`*tna%paKVPb4$UtT8V#RWVYMMP0s#-L?ApehHE`!Nx1aisd$7U5G>2tjOcXkkuuZGt0!^mXvL0b>G|!UaKWaA;xq7YGF1t^|4b)vt7`JJJH?>OpeZskt`?6&l-r#0;SdL2Phn -VN-2kY-|(&3PEgaZ)0I}X>V=?0s&*k#ka7f`< -Z^7s3P_GJP!FFFM4E? -M+l67UG^w8*<_XZ#%uyqCxRn@^mXvL0b>G|!T<;Y$}AplgPGkh3_fq3 -Q7_j=2#kPT_9!;lWR>~GYywm#UtT8V#RWVYMMP0s#-L?ApehHE`!Nx1aisd$7U5G>00000000009{>OV +VN-2kY-||-3PEgaZ)0I}X>V=?0s&*k#ka7f`< +Z^7s3P_GJP!FFFML0b>G|!T<;Yf{E)*4-0TquXIZV +=)u>WBLk*fW6RH_XPEi=Ry;9kUtT8V#RWVYMMP0s#-L?ApehHE`!Nx1aisd$7U5G>00000000009{>OV 000002|;snWpq<;Wn%^e26Sm-Yh`i)TX!suv0v9m0LPL+_79KRH|I99{YEOV7tT#ZPWpkW1a4t%WdVR* #k^Az$U%@qU7>2Bz={du0O&G0&#r1CLJBFZ06hm}WprU_Y;ynv0ssVVZ*FA(00035b8l^B00jX7KPz&# #IG7-47St%2#c>Z5R>jkTb_MKDq#SE1Nsg8a>I`c#0nSFF19TD^=GS9xE uuG0V@n0eeL3DIsV`yzV!Z000000RR600000001QKKZgg^CV{}t+Wn%^e2Vrt_X=7|<00aU61a5C`WdHyG0R(ezZDjxj0ReXZ -@I5NQHT;&p7LREnfs~VQpmrfL_JCQxeEQkVIXfYN5c23F83hGCI$$Y9m4l -DXjoK2V`Y*VQFl000aU61a5C`WdHyG0R(ezZDjxj0RcZNa<{~<8ep?nYaleMc%`0D|O6 -*W?Lsa%E#_b7^mG0bK*c7mcZoem^?%L*to!bRZoO^d~aUzM`;8jz95VA`L@tZgg^CV{}wya&2=40t9qr -cys|6%am^tlg}6qop{{FTg974FaQ3n`}K{nn9PGH_DcZ;ZDnL>VE_aI00eGtZe;)f009JZZ*64&1pxs= -s(;1y^<+=wqOM*VsgOd=>xYy=<4kft^@4w~Gv0~^L}hegX>4-^0RRX90RaF2000000RI300000000~KR -b9H4+WprT%0SIzsb7gXNWpe-t0S?j{I~j%e^V!Z000000RR60 -0000001QoKWNBeiWoJ%dZDj=k00ja9$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#`4m;t2@#H=ITLm*{QiV2NfFIf5Z%-00;p*(W0Hqt(%d1CNN)#sHFQL7%(bMbH%I*cn#*O0A6zd00000 -0000#0000000009O=VnH0sEektM3d!V}qV`yP= -b7gb@1OfmAZf|a7000011aog~WdH>M0UWS(jugTGj1K^e=F-$2o*6gc%@3Ir#hQL8;m&)Yy9iBbZDm7f -VR8d41Z8+*Y#{__VRL9B24rt+Y+-UF17U4&CIoP7b#p5OWMOk?Edyk4bS?yXWpZyY18;6+F#~jWZ!!gR -XmVv`GX!RDb#gQWW@&b1H3M^Lcs2!dWp-t5Hw9&BXJ~Xd1a4_=WjO_7VRB`3UIuJ$WMOk?UjboZ0b*hS -V`BkiWC3Mm0cK_aXJ-LuXaQ+y0cvUiYij{)YyoX;0d8&qZ*Ku`Z~<{~0djHyb8`W7bOCjB0d{r)cXt7J -cma8N0eX4_PGN0j1pxpB0s_h`9&dx0-7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3}KjBNr;@ghiU?gEXK9 -KMDE{F?;HZBRuDVqlk6qmbd^20?I5NZ-bfLFbqC#o>4E?M+l67UG^w8*<_XZ#%uyqCrG{{7b@t4MVjY> -G@u4Q3HlB(d+LiLJm-R=h;`?dxBvhE0000004D$d0000001Z!fZe?Ufa$#e1X>V=?0RR992~cunV`+0~ -Z*Bt<3u$g-X?AIIX<}?;00d-ZV`%{eV`Xl1X#xdpX>4q10|{hhV`)ukY;0)+3S(t%bZJd#Y;0)-1#M|# -a&HC+WMyM%O=)9tZwCrvWo~q7O=)9tZwLf#VQy~;2xMhrX-;8oZwd)xWo~q7PGN3u3j}a!V{Z%yWMyM% -P-$at4GCjqZggo-X=85=1!iS!bZ-v{WMyM%MrCbuZx9M&Wo~q7MrCbuZxIAxbaZbL4^VP%Z)Q(sQe|^x -a&~2N1_A_iba-z9^=uPjBlbC`N(qzPM@Gr{imSMTSY5T*7C#t%#3&jH=xRXCTqXIv;)MTcr4cfxK`S9u -y$)6q!N22#m0-mN1#oh2Z)N}p002M$0000000030{{R300000HQfXsha%5>?ZbNTwbaG*1bOiwb2mk>9 -0000000030{{R3000006RB2;tWpV`p00ja9$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#f+K+R -b@1)9wcJs8k=}EVt)knrbu3HWBLk*fW6RH_XPEi=Ry;9kNWLQ% +D(Hkon&*Qwpawq)`VKLB>Wd>h=Ype%b?2720RR91000006aWAK000004ncHuVPj}*Wo~p-d2nS00s?7d +00035ZeeX@0Zy@TnA*;6t215lmk3S~(t;6Y7Z=sJCn}C_bsn*7Z3seja&Ap!bYTVo3SxC~ZcuV>Z)S4< +2>}k$8ao+<`1M~J|HmdBRUd1sOY#QI#7O)0BZUJ2b#21aJj($Hn^F!mAeRLol +5%ecA&%UCtOO8MBUm^`dZ*FvQVPkYuWpZtE1_A_hWq5P}7|WDz5|hsu4xM=1##_akM=$^Wt^4(jv6#$* +DE3PM1#M+yX<+~a0ssVVZ*FA(00035b8l^B00jX7L#ltp_Vr{><)W@$8mW*%&FhDhLgP$wKlOrtu`}L^ +2SjCbVQFl01pxpE00992000000093000000000d|ZDM6)WMyPcWn^h#1_A_hd2nR`u?^n-fFP~dpvnj- +AyBKaJW)+{-ce}5$#DguerIN21Y}`!VE_mK06+i$000000096000000000R|b8~fNO=Wap1_20iWpib6 +c4cz_2>}k$8ao+<`1M~J|HmdBRUd1sOY#QI#7OJ{2V-bqa&u*L00aU61a5C`WdHyG +0R(ezZDjxj0RbGab&eFm0E`a+jONnR9-bLD;mr@36vdi;DdEn0pt}f7X>DagXkl^#Ed*tFV{9P=Xkl|` +BL-w|Y;0k2Bm-e>a3%zBY;|)h1Y}`zXe|R|Z*(pMdS!BNFavLHWibPEcW*KUbZByAWite3Z*_7s1ZHV= +Wi0dH>saBu-}aRG920dsQ!baVlAbpdvE0e5!+cz6MMc>#KQ1WsXXWd#8M +1p)$siR(=d3vg7gbV~*3!PlK51EySK%g?1}nECovJTYoWz9SbZ=!8X@=Yuq$20sb<4l#S`iz7Vef}@Ca +=a#qt2m*qM>rD>}a8$2!O9kk`*PSB+rd(so&!uOW`TABoF=|M@BNr;@ghiU?gEXK9KMDE{F?;HZBRuDV +qlk6qmbd@_00000001Wd00000000e7aA{;xWol((bX9U}1pxpB0s?}G>rD>}a8$2!O9kk`*PSB+rd(so +&!uOW`TABoF=|M@BNr;@ghiU?gEXK9KMDE{F?;HZBRuDVqlk6qmbd^20)mO_O%DrjRIhYP1?a)oog)LL +Tw}}6rDvG=`c^zKYDm5#7b@t4MVjY>G@u4Q3HlB(d+LiLJm-R=h;`?dxBvhE0000006!l90000001Z!f +Ze?Ufa$#e1X>V=?0RR992~cunV`+0~Z*Bt<3u$g-X?AIIX<}?;00d-ZV`%{eV`Xl1X#xdpX>4q10|{hh +V`)ukY;0)+3S(t%bZJd#Y;0)-1#M|#a&HC+WMyM%O=)9tZwCrvWo~q7O=)9tZwLf#VQy~;2xMhrX-;8o +Zwd)xWo~q7PGN3u3j}a!V{Z%yWMyM%P-$at4GCjqZggo-X=85=1!iS!bZ-v{WMyM%MrCbuZx9M&Wo~q7 +MrCbuZxIAxbaZbL4^VP%Z)Q(sQe|^xa&~2N1_A_iba-z9!AHbqC5^W8DJ_b>hggsccE>d+;#wbF?CmX! +UU<0;=xRXCTqXIv;)MTcr4cfxK`S9uy$)6q!N22#m0-mN1#oh2Z)N}p002M$0000000030{{R300000H +QfXsha%5>?ZbNTwbaG*1bOiwb2mk>90000000030{{R3000006RB2;tWpV`p00ja9f{E)*4-0TquXIZV +=)u>WBLk*fW6RH_XPEi=Ry;9kf+K+Rb@1)9wcJs8k=}EVt)knrbu3HMd?cmZVrRzu`SjPv&tGy!?nCFm&fz)So=%sVIc1y9;Ha~%eBX=7_; +asUJZ00eGtZe;)f009JZZ*64&1pxtDcPx&vU)M(f$C5$z50Bb6=QgwbMk=ru&P_#5`hlthZeeX@00aU6 +1a5C`WdHyG0R(ezZDjxj0Rezs#k^Az$U%@qU7>2Bz={du0O&G0&#r1CLJBFZ06hm}WprU_Y;ynv0ssVV +Z*FA(00035b8l^B00jX7KPz&##IG7-47St%2#c>Z5R>jkTb_MKDq#SE<)W@$8mW*%&FhDhLgP$wKlOrtu`}L^00000000006aWAK000002y$g}WpZ|9a{vSa00eGtZe;)f +009JZZ*64&1pxsL(i%G%h4}Sf8vn;89aSG|t4s0*&BRFk%a^yrND0jfRBvl#Zb@!rWq1Vv000C -----END STRICT TYPE LIB----- diff --git a/stl/RGBContract@0.11.0.stl b/stl/RGBContract@0.11.0.stl index e8872884..f07eafa0 100644 Binary files a/stl/RGBContract@0.11.0.stl and b/stl/RGBContract@0.11.0.stl differ diff --git a/stl/RGBContract@0.11.0.sty b/stl/RGBContract@0.11.0.sty index 54324362..800a17ec 100644 --- a/stl/RGBContract@0.11.0.sty +++ b/stl/RGBContract@0.11.0.sty @@ -1,8 +1,8 @@ {- - Id: stl:!r5yXt4a-v3XXv0M-E9Z6eoh-BFZweik-fxS6CB4-8AaO!MM#rover-annual-disney + Id: stl:1uyMC~lT-xPK57Lr-IgIhB0r-WxYd9io-2wZav_s-6TbR4LY#nuclear-liquid-sonic Name: RGBContract Version: 0.11.0 - Description: Types for writing RGB contracts and interfaces + Description: Types for writing RGB schemata Author: Dr Maxim Orlovsky Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. License: Apache-2.0 @@ -11,13 +11,13 @@ @context typelib RGBContract -import Std#ralph-blue-lucky +import Std#delete-roman-hair use AsciiPrintable#ultra-sunset-format use AlphaNum#window-tractor-alamo use Alpha#citizen-bicycle-stretch use AlphaSmall#magnum-martin-soviet -import Bitcoin#signal-color-cipher +import Bitcoin#quiz-patent-exit use Vout#brush-gloria-heroic use Txid#shallow-light-reverse use Outpoint#logo-alamo-madam @@ -41,6 +41,12 @@ data AssetSpec : ticker Ticker @mnemonic(mono-bagel-falcon) data Attachment : type MediaType, digest [Byte ^ 32] +@mnemonic(resume-telex-tower) +data AttachmentName : [Std.AsciiPrintable ^ 1..0x14] + +@mnemonic(brave-costume-percent) +data AttachmentType : id U8, name AttachmentName + @mnemonic(ivory-speed-finish) data BurnMeta : burnProofs {ProofOfReserves} @@ -56,6 +62,9 @@ data ContractTerms : text RicardianContract, media Attachment? @mnemonic(trivial-halt-nobody) data Details : [Unicode ^ 1..0xff] +@mnemonic(mega-mayday-diana) +data EmbeddedMedia : type MediaType, data [Byte] + @mnemonic(alias-analog-icon) data IssueMeta : reserves {ProofOfReserves} @@ -85,6 +94,9 @@ data MimeChar : excl#33 | hash#35 | dollar | amp#38 @mnemonic(lexicon-monitor-madonna) data Name : Std.AsciiPrintable, [Std.AsciiPrintable ^ ..0x27] +@mnemonic(hair-laser-peru) +data OpidRejectUrl : Std.AsciiPrintable, [Std.AsciiPrintable ^ ..0x1f3f] + @mnemonic(mission-person-armor) data OwnedFraction : U64 @@ -105,6 +117,16 @@ data RicardianContract : [Unicode] @mnemonic(newton-corona-aloha) data Ticker : Std.Alpha, [Std.AlphaNum ^ ..0x7] +@mnemonic(sofia-cement-citrus) +data TokenData : index TokenIndex + , ticker Ticker? + , name Name? + , details Details? + , preview EmbeddedMedia? + , media Attachment? + , attachments {U8 -> ^ ..0x14 Attachment} + , reserves ProofOfReserves? + @mnemonic(giraffe-correct-modest) data TokenIndex : U32 diff --git a/stl/RGBStd@0.11.0.sta b/stl/RGBStd@0.11.0.sta index fc0bba19..eec7c74c 100644 --- a/stl/RGBStd@0.11.0.sta +++ b/stl/RGBStd@0.11.0.sta @@ -1,302 +1,138 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:YgyNu!Qt-mt5DMxt-GXH55TN-bmrTwZH-o11V0B$-$jxMrfE#juliet-vega-richard +Id: stl:LxiMjmBl-MRIFHb1-pitHq43-IPC2~cM-SHQA3hl-mGfDECY#studio-cycle-analyze Name: RGBStd Dependencies: - BPCore#symbol-tropic-grand, - StrictTypes#century-comrade-chess, - AluVM#congo-archive-folio, - CommitVerify#miller-pancake-elastic, - RGBCommit#raymond-open-organic, - Std#ralph-blue-lucky, - Bitcoin#signal-color-cipher -Check-SHA256: 48b79da50a92f08ef630d9ed1bb0ae4224154a3bef9f84a4187df086330af8cb + BPCore#juliet-super-dominic, + CommitVerify#violet-panther-herbert, + RGBCommit#support-iris-depend, + Std#delete-roman-hair, + AluVM#jargon-gorilla-poetic, + RGBLogic#colombo-famous-erosion, + Bitcoin#quiz-patent-exit, + StrictTypes#henry-heart-survive +Check-SHA256: 76ea5b0a8df953968faaba60a14b3b45cc165b3801da94cf5c4be4a19ae27e0b -22w{tQ*>kpA#kgq^`I&ZzC?)!&R01Y?(H9FO$CR6P1%k7c67A-20~CnZ*pZt>Z4!V_T!KNI`QJ|h6;Zj -^jB$MPK+?7Lu3>C`4HI)Q*?4^V{}w`aAk91a5aA+<>R2XhQO_4{AcS-HH^7AVzASV8M4NYxyCjHL2Pwa -O?m?z-)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCJaMwZEb0ER%LQ&W_h20XiL(ap`B(@2KpYTJ%x(D -C3d{wiWYg@TKk|G2{Q>&M?ynyZEb0E$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#15DT%6aZ| -SrJerP1pIOD57`7Ol|-ogQ6Pjg~y>s-v>!^VNPLfWv4Jz0xkJm$nc4yMWR2J-cc#Q6SofWC)gp7L6!Sc -3I$AQVo7AP4Jk3r!|EoW{Zi$060oMN(jLzPuNboiNpoRSWoOdj7+WWC1?EKi+6QrwlvP$n -l8x-M691f9z+~t)>6ivgX<}1lX9hx0LvM0r2>=0n2VDR_OBR)w8yCZ2EylR&t_^>1Sz?kFbz0>alMxYA -VQ_L~bWU$%Wl&*qbZ%vG54IneKN{_;j(f`H9IfkFzO$PGD6U0+e -W+%HuC5$^~^vuG3{`}-8x6fV={eh1!etXz_4^&}ra%FT-VRUFva&K>DECY>5OGottJZHLg1Ujv+c;>sahi4MJ>bZe&wsVQf@*X=FG*VlHu0(#Ro^Jj-_-pFL#XcJe4ySuOZRLzEUxZ3PijVQ_L~ -bW&+&XmmnyVQyn+M^4XN(CAD)cag{3QuryWpq$-Z*OL38SA{&vly$F -vzVnzHf7z~rv`86=_Ka^V5yX|y#`JSQ)OdvWpq%$n#j0HLDJN5-IKgM_J7b(p+0MPGk2Gl)y2(Rz1Xgc#bS10xxe^o?x}!PNUwajG -r*TW+dUY6G&@nZ7)X6RBh6__;a%pgMLV0v$b1}QF=!A)P#jpo4axu-4_As_7EzOC4+`8Vyy2R;!*$Y%* -a87SzWk_LjXf@g$6*(YoyWQNR!##&F>hhbX+H~JN$bujoP8PMf90*KrV{24tZDlxh1hGqe4n}Q9o)<@b -By=Qy_yc6@Jxi+hIw1E!bZZGyX=hVoa%pgMU#!_}aHwX>fFqJ7jQqgpV60Q!3=n#-@oxpi@}5@PW%Fv%B~$o;&jeRCrHybeHwl212eXGm<4cs7@Wu#FOK{ -KGSirhjWHCPRxjcYXnnabaS0mldQV=&ET6jM)-pXanm@-FK%_beB&TRo~t++rXB}ZX>@L7b91ADLi5Yl -(a@n1+Ku60FILp}Zw|!7cE!MGSxid=WmW`Kcxhy)e8zcXXXRJdMCHk1I^Yb;mDw5%F9Y9nz;zN&zQ>*g -RCrcpa;b%ccT=8d`>?<6$C@F;S3|*6`1-v+nBdcqJ?FPKcnV2wbY*gGVQf%qwlfK-7{9iX4Q|L-q$GzU -Mp|h#f#zWg5iW~CYZWKwE66NffE< -bz*B}dBk#SkB=zPdcl{-9gYp5n_@(q=Fnta{>SNfJhg}MqX$BHbY)X?a>aWgn!oosZgNI|twmNZeC(lY -Za*g7-2eQ3Yy;-pL;_TJ=xRXCTqXIv;)MTcr4cfxK`S9uy$)6q!N22#m0-mN2v2o%aBpdDbo`>HD!!5a -&4Q@0n2=*4!cKOosx|T?(Q^f3pcpQQSqE58Zfto_YYangZEb0ER%LQ&W_bnxIG#g>Clv)aMjKgwAH@`b -u1x<7g|G$};xvA~n-$_S3Qc8lYiwmmVRLAO(LK3V&vL%&i(~ao9rExlGMgPx_&tqtqVlwo1}@PHO=WUx -Y-Lb#Z*OLk_h5K%L=laq&yA1JoJ^{7>oKLkF4~iax8KK|47hp@Qe|^xa&~28LV0v$b1}=fEj#9D^K)f# -Cf|Xn@L3mU0Z2&n-dr?jcD1Ll0RawDWpib6c4cHjd30rSGVkgW4+YqPF=12xaaxrgbrDxyH3;v2Uql0Ev@(iYu*+LHGLwE58<4pL=vWpZ|9WI}m# -Wpg+QQb$5VZ*6U9bUOe8XadZr-SV>qb#7#AWeK)_65s1c;WeUUgB8EM+V1n+TF3m?Yd1DC`X&GvUv9(-1>WQHGZVX3kZ(?C=R$**)WpfPE&0f8wJi%%!Y}u>; -$65#kwiiC+oZF-Hf6=ZQ>wOwjd2nT9L349yXKr&sY-w&}Q)OXnRCrKyaug*zj!?y>j|-pde{GkuQzBXTAin>Id -F&9PAZ4eqJ|JRcX$Hf^zb8~5DZf#|5baO&%X>MdwWnpYocu;h5B%)2d$+)#qWOeU-&^BHT8-%*B3Y<=; -rA~cRW%6F~9YJ$*X=iR$Z)s#xbYXO5LTqVnWK(5fY*ctqbaEv{biTp4ZzpWVEhda;c-OlKZN9QQ?CZI; -=cI(fPVx{>cWz~5Q*>c;Wm98lWo=<5iOjwi&ipUJkjC-eqrzX2Ju@O|t6`=nY8`b4SeCJ1RUi64PH$rAZV^45~b+QcEHNeWbQVQzD2bZKvHEz*5Sr(qVbRr(sgSTLXWu*DC! -3`08H_Vqrgg&j6`AVG6;X=iRyWp-s@Y-MCtVQh6}LTqVnWK(5fY*ct@WG=F${ujV7L@=1(T$>wOY}Ov_ -b`4?P%YY`+Wb+o`y9rirX=GD$VRU6Oo>ox?`Aroor<$W|05z3@o%yggc; -Wi(O`t`n9TUcD*&5hFi^PVx{q1b@^7zTcrn*%qZTXbx0zVQzD2bZKvHRC#b^H9CeC{6$3z7L3&+{EW{G -yYZJ%0knKxE<9tS|D?sh5K?7!WnpY(WJYyvXK7+=Wj4Vyq57bK6Q|uUfIMEX^1}Vv6tLB!)|10-o)0pr -c?(ZtV|8+JWo~0-b2)ophRF9oualB}P71SaJfwx=uHX^JIK`}V>+d2nTJ%+!W_LE6rjH$cQ=8Ln)Sgi5RNhKKPi@=@5j -iV>*V`yb^xB4~9n`Dx!RtcK)nwJGnaBp>Vlv2~%1FNg3QJ<&wKF}2F)J=Uc -Km7gx`duV?R0NO^2vcKdWo=+kk4W| -0D0)1tC589WlkJ4(T@u?8)d_7GlQG%sFl!L349yXKqqu -c4c8~Wn@HQbYVhlX>MdwWnpYocxhy%7cwO5*n2s$3@K6WR=W11q{+)$o%x+F6XK_jJ2Mg?L349yXKqqu -c4c8~Wn@-iY;|QqY-w&}Q)OXnRCrKya;A(hkw;6)I>KU%$CX5lEZwTb6rTk%m8vvBgJ_74J{Jehz7Np5g;baSm9Ka?O}aEvKu^y*67(3wRv -ID`L1eu0Pjrm!gUE7k}@Xklq?PGxkhy!1S2^HuJ7Oiw7YF=1>so3EIu+3*)t78850@mnbwRC#b^WI=Ot -X=iS8LTqVnWK(5fY*ct@WVYylh8!q$B6|*YuiTY;OURW8#d%1{rxIXtTaY^?oCrx|Wo~q7ba~BGr9yo^ -9b7e4c;WkPIeZe&wsVQf@*X=Kv0L;LZ8 -3j1o=jC2tuhEYb*>|BZ=<&>MYmew2xdV>c?Wo~72X>-+$UkD7Ff~JZGMgrhZ&rP2gYrktY!x$bpv=qCl -=HdlOZg6#U)$WoGNrWpmymk!z-`g4hv-$6z_YxoLZ_neUP>BpbEf7FA*KKfDV^Y;R&=Y*Tb$bYE%WYMs;pyX<}?;RC#b^{4_<~U(XE-|Ev|Hdb$N7;9H9;8!%;3hl7uME$faw -4?}NmV`X7%Wn@8gbYWv?|7c^tcv66A`G>fII^CwqAYJB+ZKALhJOg5MaL2PhnVMAeXb4b1;7b@t4MVjY>G@u4Q3HlB( -d+LiLJm-R=h;`?dxDG*cV`*tna%paKVPb4$VTK~nd#>@6JWikDr@YkEA -s#9)9JJvRH-Qc7Q2s%Kf+=VCyOABEU3kOtrQ)O*QWJFFoaz*WZZ5##rf6bm&7qffY6*N`B##bI~HzDmr -7z##dWo%?qWo=1hQx*t>6v={gsJ=SZlTl1iF5eQ8IAl(q%E@>So406W2vm7+WlmvjWn_%h53p;7sgGx& -z)8&prN#D&cR=tS@df05SQ3Z*PZCvbZeeX@WJYOaY-Dp&Wo=1hYXqYdo~D%m7H6OD0<^0n_2##VWXRdj -y=DB@qgYOj1yf~hNo0M=LMPN>0NEy%g(UCHeUkYj{YR7-159lqXIqm$}teZO^;JC(UrZ-Ks{e+7M1* -ZDnLeX=Q9=b5mt)No1EHgR0RSPeIWLGZ_*YTjUMn3>33lep74@i%V@}#Ze4JZgp)|VRC6;+#Z*Ep$a%o|1baPW>ZAoPPfv$so3kRF1PV2}fOp_vjQ6FdFHId|K_%|4nb~iZ**aFX>V>$ -VQpmv0RRO80?I5NZ-bfLFbqC#o>4E?M+l67UG^w8*<_XZ#%uyqCnto_jB5_YJg;9E|1`d*r&;qSS3+uh -`0YNLave-Im;eX@$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#cxiZMvTM3tQ2*(p5s~Z{6V3Qi -K&W#-F~+s6raGiL0000000000{r~^~000003qfvfZ**aFX>V?G1pxpG0WnM89|TAhYfrNblQVQ`LpZXK -teHopy#|_NJkG`K5da7P06+i$00000009600000000000000000093000000000X?b8~5DZb@cgV`T;e -3U7CAWn@!yVRU5y-Vzs+-~y(u)KQ?3g=q&>T!Ej;9TxQjc0+10Fg2)p25@y^Y-wWx$}AplgPGkh3_fq3 -Q7_j=2#kPT_9!;lWR>~GYywm#VTK~nd#>CWCF@8 -9&dx0-7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3~AEBGG%U@MZ$v=XJ?|;InIPy66cFfOYp#JM2r7_Du+F -b!>ELaBO7)$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#VTK~nd#>0|;$!V^DH$Z)O5|10COKearHwcS=7M7YzYaI8*bv -hMOc?)(rkC#nUE*(LK3V&vL%&i(~ao9rExlGMgPx_&tqtqVlwo1}@PEWMX4ba&K>D0wHj#q4l6D4ZcK) -2hLYH81C&KXiWu&flb+s{C0G-{6|jDT+rxDK6vW;JU&?LxLM72H?wDC1Zo}=N}D)4mj+^WZe(m_0-u0r -OVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*KGX;3#jF_Psll$K3m0qvW>0&oDqqo0*?q^FKQ(!8W@fSmE -X=QG7LUnFrY-LnoaB^jIP;zf?W(ETYZE#~ya&K>D0(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@O -CWX;GxmM3|zUzx)^-Ue}@Gdf&9Z>i^jdP;%w2}rc(FkN>V^DH$Z)O4^aI2y9pehZ%M2QE^S2-B&?H_1O -1&4u6*^T^mbhP{rwjY>38tto&d&=e}S -s6B;>za@6O;ffY{-CFyg83{85c;k$ip&FC>-szQIuhHpZH#DQSzklv$OC3{SDwpvPLvL<#X=iS2Wo~q4 -VQh0{1`P*xWpZz4Ev5gyU5%_yeyFzybaG*Cb7p070?I5NZ-bfL -FbqC#o>4E?M+l67UG^w8*<_XZ#%uyqCt-#n(R;4&W&+>mb;*F>vukd;=m`ygb@x#_>`RmOO$l^ma&2jD -VQg~%3Id;iXiL(ap`B(@2KpYTJ%x(DC3d{wiWYg@TKk|G2{QwGleIk>g)RqK0VQ|Mwn6X+txo3vSYd;; -z)HQ~0$c(iaI2y9pehZ%M2QE^S2-B&?H_1O1&4u6*^T^mbhP|v8SA{&vly$FvzVnzHf7z~rv`86=_Ka^ -V5yX|y#`JI0000000030{{R3000007XJu|>b7^w|pMYpf(w(85W>N -(zHYS@qr5aYT1l*5hjLFM$znCiXr8co3@tL90z)X3T1e7Wo~n6Z*Fq{2?C#hXiL(ap`B(@2KpYTJ%x(D -C3d{wiWYg@TKk|G2{R^%%)S@S{4c_g#_`^x!e5a+Ga_oMVWuc-d(EoHF)siB0000000960|Nj60000MK -b#7#AWpe-t0VKb!>z@X6l5yio1?-YV)2V!clxMdOjzu+IFQjzqg#Z8m000000RR90{{R3000whoXk~3- -0-u0rOVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*KGdX);hRF9oualB}P71SaJfwx=uHX^JIK`}#x3$o4Af`kVHyQ&~TYCSRqgWgjZ$<5FZnjcuT6B5B6)POqpHC -TrHl4#QtZa;zni70000000000{{R30000003v+dFaBO95Wo~qH00{wOJ=2M>OG#EL&$!Mwbx&PZdlOljoA7|k;k>s6qoa5|8f~f~{V{&P5baMa+0%CAAe<9`Lptgpr6F_ -xjAC6(~TLj#*ewiHWCDNgmDd%EKc;pw+KsVi?D}qDSkO* -B!5Mb*xG|_(S5o&00;m8KmY&$000000RR900000000000000000RR6000000019(yXKrD1b#i5M015%( -)D=(>(T2L(qY0=?Nz4 -Ev5gyU5%_yeyFzybaG*Cb7p070?I5NZ-bfLFbqC#o>4E?M+l67UG^w8*<_XZ#%uyqCt-#n(R;4&W&+>m -b;*F>vukd;=m`ygb@x#_>`RmOO$l^ma&2jDVQg~%3Id;iXiL(ap`B(@2KpYTJ%x(DC3d{wiWYg@TKk|G -2{QwGleIk>g)RqK0VQ|Mwn6X+txo3vSYd;;z)HQ~0$c(iaI2y9pehZ%M2QE^S2-B&?H_1O1&4u6*^T^m -bhP|v8SA{&vly$FvzVnzHf7z~rv`86=_Ka^V5yX|y#`JI0000000030{{R3000007XJu|>b7^w|pMYpf -(w(85W>N(zHYS@qr5aYT1l*5hjLFM$znCiXr8co3@tL90z)X3T1e7 -Wo~n6Z*Fq{2?C#hXiL(ap`B(@2KpYTJ%x(DC3d{wiWYg@TKk|G2{R^%%)S@S{4c_g#_`^x!e5a+Ga_oM -VWuc-d(EoHF)siB0000000960|Nj60000MKb#7#AWpe-t0VKb!>z@X6l5yio1?-YV)2V!clxMdOjzu+I -FQjzqg#Z8m000000RR90{{R3000whoXk~3-0-u0rOVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*KGdX); -hRF9oualB}P71SaJfwx=uHX^JIK`}#x3$o4Af`kVHyQ -&~TYCSRqgWgjZ$<5FZnjcuT6B5B6)POqpHCTrHl4#QtZa;zni70000000000{{R30000003v+dFaBO95 -Wo~qH00{wOJ=2M>OG#EL&$!Mwbx&PZdlOljoA7|k;k>s6qoa5|8f~f~{ -V{&P5baMa+0%CAAe<9`Lptgpr6F_xjAC6(~TLj#*ewiHWCDNgmDd%EKc;pw+KsVi?D}qDSkO*B!5Mb*xG|_(S5o&00;m8KmY&$000000RR900000000000 -000000RR6000000019(yXKrD1b#i5M015%()D=(>(T2L(qY0=?N}Ss6B;>za@6O;ffY{-CFyg83{9#Qq$W5tE;F{ -pQrXd&=l*`O?@#x{Qdy?T_k!`1dtE`2WMq&WpinB00jX8pMYpf(w(85W>Np9m~TI>-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b0tIPiVPjm(ZiUQ7;QU9z@vLsQUy3 -b9HcVYybrT0cSFYzzA^b6`Drj_fC5M7<0km5x1u)VS{2*yf9yYl?p>|ZggdCbW&wz1OxyEb7N>_ZD9Zf -0Ro?ZXiL(ap`B(@2KpYTJ%x(DC3d{wiWYg@TKk|G2{V*Z)7t~9tEf?*r}jS36zkMYeK9}${s8)2BzjZ? -kPra}XJu|>b7^w`1pxw|fM`q7ouQp(QU>}Ss6B;>za@6O;ffY{-CFyg83{9=2rNlD$O59e#ogQsB77jP -l+h5j^*S;F1!-nsV`TsZ0RcP8z<~n@;VY|KA!vt$qMEp^75#kD_Tqj3WXX=Y(# -Wl3#tYybrT0anNlc)Z3!7CPHT_+Dq|&?jn_(4)LjFAF^$MA+G=`wK&FZggdCbW>?(a|Hna3Id;iXiL(a -p`B(@2KpYTJ%x(DC3d{wiWYg@TKk|G2{X3nfQB3>bs~EXcCXx(drQcb3B`Fx$)^%va$Ar)C7b~v#}{qT -DnK1gUZ=~4IPtBJuMnKCWEcQ$kD_ZvQg;gh000000000A000000000EMR;^&ZgXjGZb@cgV`T;j2yJg< -X=Z6~GYywm#VTK~nd#>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_00000 -00000{{R30000002WM<=Vqt7^015&{>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV* -{3!yZ{M3XW@z+pNHo-KZ`k;Xm -r`<4sJYKN!!u{G5u+^j1lf!PF4>GEG0000000000{{R30000003t@9}X=iS2Wo~qH015&{>Z4!V_T!KN -I`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ{M3XW@z+pNHo-KZ`k;Xmr`<4sJYKN!!u{G5u+^j1lf!PF4>GEG0000000000 -{{R30000002XbX(Wo2!100{y`>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ -{M3XW@z+pa{vhfMe3tp+xFv-0Xp&G?S=|} -9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0000000000{{R3000000 -24!+`Z*p@02?9mxqhH(h&Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ{M3XW@z+p}Ss6B;>za@6O;ffY{-CFyg -83{8s!8D=zpn(&o-7tVWUa<1Q{n`|;)uYyv!)~4rGOBq10000000030000000000BVRLh7XKrm}Zgg`1 -3IavyqhH(h}Ss6B;>za@6O;ffY{-CFyg83{8s!8D=zpn(&o-7tVWUa<1Q{n`|;)uYyv!)~4r -GOBq100000000300000000009c42H~ZewX>a{vhfMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r -8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0000000000{{R300000024!+`Z*p@02?9mxqhH(h -Nn`*70ssVVZ*FA(00035b8l^B00jX8Me3tp+xFv-0Xp&G -?S=|}9rRaeU`~uMrbA>C`}q*rYXqYdo~D%m7H6OD0<^0n_2##VWXRdjy=DB@qgYOj2y$g{b!l>CWCF@8 -9&dx0-7pM3Z=O*v*GCA9fL-<|HrZsA`NnJlR3~AEBGG%U@MZ$v=XJ?|;InIPy66cFfOYp#JM2r7_Du+F -b!>ELaBO7)$}AplgPGkh3_fq3Q7_j=2#kPT_9!;lWR>~GYywm#VTK~nd#>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HJt76^nC$%1sKzB<;EQA|)S-x88IWKN#S$#@T&w`gPt -X>Mp`a%psP00;p)%D{mG2;nQMTOnwNgyXhzrB~SH04;UKo5i(1Vxw^Y00000000300000000009bZKp6 -b97;CZ~y>E2yJC_VPs)+VE_sOMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+ -rTo-{AMw{vgzX#P!9p!}0yp?_0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*=q!&6rQG)02XJT -?*g=|B=zREie$*y(7k2+*P~cYjQ{`u000000RI300000001IbqZ(?C=Q*>c;WdI5SMe3tp+xFv-0Xp&G -?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0m=yGke?j1l!xqX -d>q7+-P0pRHy9#PwIC`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_0ZXaKh^f@$D{A?t -{IfX>#}PNp!L%7{0GY9xpq!KXGXMYp000000RI3000000010+sY-Mg^X=QT&3IavyqhH(hb7^w{b?qhoJW!8=sKG~^&Ni^C7tcO} -co=3CQC(GPVoWSC3v_Z}ZgXjLX>V?G015&{>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1 -V6JV*{3!yZ{M3XW@z+pD`aAk5~bZKvH00aU61a5C`WdHyG0R(ezZDjxj0RlzpqhH(hC`}q*r35LOoBKkGaY9#cS7Qj{WgyAGcS>>g~&^g7}Ss6B;>za@6O -;ffY{-CFyg83{AC=zxYCD0L!x4tB5Hm3vFbl?lapNXe%XU~*fKJ0+Y4NoHYVWl3ZO0RRU806-uB2}x#Q -V`WKgaBKz)2X}Ss6B;>za@6O;ffY{-CFyg83{9#Qq$W5tE;F{pQrXd&=l*`O?@#x{Qdy?T_k!`1dtF1X=Y(# -Wl3ZKJIcU;0|?p#+${pKVqYC33O>~Wpi|4ZEyepNC<6ZbYWy+bYTDq0lk5U -Vp0y6#Opn49V(cQc;WdI2QadI6- -(bd|-i#!&GYaF>qoh8arda{vheR)?jU+FZ2D -Lr`QR#xHIKjC^A48Li8o%k$8HEod=_0000000000{{R30000003v_Z}ZgXjLX>V?G00{v&KD$)QXhhr5^*YH=BF-=cyOsxg-v9sr000000RI300000000w1pa&K~T00{xZXXT7NJOW`Spw3o_*cmz+ -=1%_1gm*5-D79nn{HtC700000000300000000009WMy_`Y;SO7asr=#XiL(ap`B(@2KpYTJ%x(DC3d{w -iWYg@TKk|G2{X3nfQB3>bs~EXcCXx(drQcb3B`Fx$)^%va$Ar)C7cFHZE$Q!WCZ~L2LJ#-AOHhPX>#x3$o4Af`kVHyQ&~TYCSRqgV00000000300000000008b7N>_ZDDj_00{!0fM`q7ouQp(QU>}Ss6B;> -za@6O;ffY{-CFyg83{8vdtiph_du_cl6_7Jvu!-2h2yT^5yv>ite$I%(jAWg00000000300000000006 -X=!b6Y;yn!0fbj(2M`|V!Z000000RI300000001I<Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HLtfv$so3kRF1PV2}fOp_vjQ6FdFHId|lr&gK9B000000096000000000VeX=iR>bairNa{vkf;?xyT5z&Ua+M@}mOiDpYxh>^^GknUx -TJ!XL#OUcE0frb5ENEw7&f?o%+)B!ZpG}K!%4G?I4vp$|ttu*CMF0Q*000000RI300000000>QQWNBt; -WpV=p2w`G#baG*1bN~o%c4cyMX=G&q1!ie(VQl{xPGN0jWJYOaY-B-mb7^O8ZDnqBRC#b^1_J_VWCEXn -XiL(ap`B(@2KpYTJ%x(DC3d{wiWYg@TKk|G2{VWO;$>KfZ0H=mhJ>?uVC`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!} -0yp?_2y$g}WpZ|9WCD5v9p7nv%krpqNFdpMYpf(w(85W>NWOW`wsTH9-LlJ`2|Ay5Z(?oEikl{+~pis;@Q*TJ#1a4t%WdcR&qhH(he1kloHngE|MP08BSqs -Wn@NaWo%?eY;R&=Y*Tb$bY)a|aAgJq0%>FdpMYpf(w(85W>N)$WoG -Nre1kloHngE|MP05>8=lWn@NaWo%?kWprUwd2nS0 -0|IGe0-u0rOVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*KGj-%m_}|Wp0vpvv$c&#PW69R$ltr%da5t5w -^x+8!q6BVXZDj&Q>Z4!V_T!KNI`QJ|h6;Zj^jB$MPK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ{M3XW@z+p< -?Hl01LM?X!H~4Z0a%FR6a&~280(t`--)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OChzJK4+YqPF=12x -aaxrgbrDxyH3FdpMYpf(w(85W>NG*S<)6P6lYy(#<=BR_>s@(?%#f7ArN-=Rj?7Ns(11a4t%WdcR&qhH(h -e1kloHng -E|MP06;5GoWn@NaWo%?tVQgh?V|i40aAgJq0%>FdpMYpf(w(85W>N -M(yUq2ps*m=2xUDT;RqCgn#@WzFu~@adfH5^@&-|1a4t%WdcR&qhH(he1kloHngE|MP04o+chWn@-ia%o|1bagle -0|IGe00035ZeeX@0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*$IZhiz50p(P||0m=?fQ^Mv6f -Mp@;h#Lzj#&aRFSj|g&Qb7gXNWn=<+10COKearHwcS=7M7YzYaI8*bvhMOc?)(rkC#nUG5>JtwI*nu%& -Q~z;Vl^%5wS6(#;{6ajG64wDPk{-(nPj_x*WJzXWV`T&e00Uuec>n+a0S0nuXJ~YD0000224QV)b#8P3 -0009AVQzUuVRT^t000CDVQzUrbaY{3XaE2J1q5VabYTDm0RlzpqhH(hioJpYH;+t0eX2w~A!Q+0eaZ{MVycPK^psbz)a(bZ%vHa|8ka1ax?5WB>&L0`+VY -Vk7oBr%DNv+($;q`HHK!gIHa)*%m(-e#9sm3ZsHT^UK%K(4i9Ajp1M~R@C@!4#dQE#lUD;OiKi1RsjNZ -cmM?f0`+VYVk7oBr%DNv+($;q`HHK!gIHa)*%m(-e#9sm3dMUNn!oosZgNI|twmNZeC(lYZa*g7-2eQ3 -Yy;-pL -1po(RWoBV@Y;*ts009Pcd2nS;ZvX`W0006J2y}UHWlmvjWdH>M0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_ -Fs4If6Z`oP*;5t>gcQkwbf~^M){{|8P%hsRk~m~ep32F151Y4WWD*HxX=Q9=PGN0j00jX8Me3tp+xFv- -0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!}0yp?_6AN}>a%o|1 -bWUMyWdH>M0!8YhU)%QMkO4aJ;_ZeCe;xE!X<$x_Fs4If6Z`oP*$IZhiz50p(P||0m=?fQ^Mv6fMp@;h -#Lzj#&aRFSj|fwBaByr*VQ>Wj015$yz}|oy`cC#6Uw2{wE+Sw~);*uMH+9Bf@aCY-RuiZDn*} -0S0GmZ(?C=0tIh(Ze?Tx2XWo~161PWnub7^O8ZDnqB1qWwkZe??6a|Q}@a$#@6CZU+fvcywiM -b7^mG2nl6)V`Xr3X>V=`3R87(aBO95Wo~o^1PNnrZggdCbV+0Z2AHk4+Bm{3x%H=p>4!*u&n~Wpi|4ZEyepNC#tbWnpx0asr=#XiL(ap`B(@2KpYTJ%x(DC3d{wiWYg@TKk|G2{X3n -fQB3>bs~EXcCXx(drQcb3B`Fx$)^%va$Ar)C7cUkZfdKHyBH|__hx_vscRW -Au^w2r{b^x;wDWyGXd29kG60)seH8)H{-R`;$q)jqasX>@6CZb@cgV`T;j2yJg~GYywm#VTK~nd#>C`}q*r8?;yf@?frQ$owe+rTo-{ -AMw{vgzX#P!9p!}0yp?_0000000000{{R30000002WM<=Vqt7^015&{>Z4!V_T!KNI`QJ|h6;Zj^jB$M -PK+?7Lu3>C`4HI~v{(W1V6JV*{3!yZ{M3XW@z+pNHo-KZ`k;Xmr`<4sJYKN!!u{G5u+^j1lf!PF4>GEG0000000000{{R300000025D|^ -b#!w83IavyqhH(h}Ss6B;>za@6O;ffY{-CFyg83{8s!8D=zpn(&o-7tVWUa<1Q{n`|;)uYyv -!)~4rGOBq10000000030000000000BVRLh7XKrm}Zgg`13IavyqhH(h}Ss6B;>za@6O;ffY{ --CFyg83{8s!8D=zpn(&o-7tVWUa<1Q{n`|;)uYyv!)~4rGOBq100000000300000000009c42H~ZewX> -a{vhfMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r8?;yf@?frQ$owe+rTo-{AMw{vgzX#P!9p!} -0yp?_0000000000{{R300000024!+`Z*p@02?9mxqhH(huJC38-{*D7fZ(%hZo23R4S;p`Q9JBQllDyoR%LQdZvz4Xb}#?}b}<1B -S7~%^Wpi^vb#7#AWd;HYaCKr=X>@L7b8`U(J4=$RltJLk?Nfj|sXiSdmgaJi@wPyW+dHeUQG($PVQyn+ -Z*pa1LUnFrY-Ir*q&^ereJSbv4~AUlRja@2Ckv4h-B^wIs2Ae~UL>y +22w{tQ*>kqJ?lFX3Sj7m#S0l<6lWWUs|%1)CkG9>cz4~pa1P{=20~CnZ*pZ!WfpKF*Z0wZ5-ly2voTT) +QcLg9hvFSzGHuQ>ceug~LvL+uX>?X)a%pCHUATk^%RR@{#>rD>}a8$2!O9kk`*PSB+rd(so&!uOW`TABoF=_)-bYz<NgzlT_m3wFmfDB@ZlUF_{Gi(YuS4F^JLbYpL6Zt0$q=Q}``f02HLt~iCiD@{1Jw0_*8A_pi$)ov?1 +PzzIZa%p39RC#b^a|i`NY;{&m1^^NSr?vtRe2PRb^)}W8ZdqCQlr&gKJ5X<}{fp(f$H +b>aU=OZ$bvG|>z)+>9PT;Au-7)~D;-++hbyX<}1pbY+s|KgxOTbXgHlB~91)qbQqD?1jgn +N8blYb74+lZDpr0RRS&fT*&Z=qeY@Wmfle*z!SF)@h8|JkU^FEQwjx4X<|uavkfUR&BN*@p#4(ibP}+p +taQ)Oq;;uu>eaRuf?``QO_k(5tm>UaGoca9LuK7Ij+X8IutaRAF#(Wpqw&WMxoca&&HGau2p2m_Hir +tB!lh<{Yi-S-!KI0_27BH<@sVme~^s3=33YaB^jIP;zf?W)s9yQf4Q+L?w(nXY|a%e*XOAC%4aD5B-6U +FMfO2d=FG%aB^jIP+@dvP;zf?W-J4ZNJ~fc1UzTDb_LBRjrSXj?;k=^zm6d~Uh7!wPz^$CX>MdwWnpYo +cxhxfKVmL%Q_{#Gkvz+H9iKg9-*)mSRaq_gMnjYqO>G4cRAF#(Wpq+$XJ~Xna$#;`Xh%-ZT+rxDK6vW; +JU&?LxLM72H?wDC1Zo}=N}D)4mkLjCa%FT-a&K>DQJz*lU&edk{G8WCh%}junc6$5v!Tz0lK7`GY>kS^ +4nb~XXm4^vVq;KpZ*OL38SA{&vly$FvzVnzHf7z~rv`86=_Ka^V5yX|y#`JSQ)OdvWpq%$n#j0HLDJN5-IKgM_J7b(p+0MPGk2Gl) +y2(Rz1Xgc#bS10xxe^o?x}!PNUwajGr*TW+dUY6G&@nZ7)X6RBh6__;a%pgMLV0v$b1}QF=!A)P#jpo4 +axu-4_As_7EzOC4+`8Vyy2R;!*$Y%*a87SzWk_LjXf@g$6*(YoyWQNR!##&F>hhbX+H~JN$bujoP8PMf +90*KrV{24tZDlxh1hGqe4n}Q9o)<@bBy=Qy_yc6@Jxi+hIw1E!bZZGyX=hVoa%pgMU#!_}aHwX>fFqJ7jQqgpV60Q!3=n#-@oxpi@}5@PW%Fv%B~$o;&je +RCrHybeHwl212eXGm<4cs7@Wu#FOK{KGSirhjWHCPRxjcYXnnabaS0mldQV=&ET6jM)-pXanm@-FK%_b +eB&TRo~t++rXB}ZX>@L7b91ADLi5Yl(a@n1+Ku60FILp}Zw|!7cE!MGSxid=WmW`Kcxhy)e8zcXXXRJd +MCHk1I^Yb;mDw5%F9Y9nz;zN&zQ>*gRCrcpa;b%ccT=8d`>?<6$C@F;S3|*6`1-v+nBdcqJ?FPKcnV2w +bY*gGVQf%qwlfK-7{9iX4Q|L-q$GzUMp|h#f#zWg5iW~CYZWKwE66NffESNfJhg}MqX$BH +bY)X?a>aWgn!oosZgNI|twmNZeC(lYZa*g7-2eQ3Yy;-pL;_TJ=xRXCTqXIv;)MTcr4cfxK`S9uy$)6q +!N22#m0-mN2v2o%aBpdDbo`>HD!!5a&4Q@0n2=*4!cKOosx|T?(Q^f3pcpQQSqE58Zfto_YYangZEb0E +R%LQ&W_bbtIG#g>Clv)aMjKgwAH@`bu1x<7g|G$};xvA~n-$_S3Qc8lYiwmmVRLAO(LK3V&vL%&i(~ao +9rExlGMgPx_&tqtqVlwo1}@PHO=WUxY-Lb#Z*OJ^Qb$5VZ*6U9bT$A3dy}<28ig(gSpg+?&9*`C2(3=% +09avzwZKZf-~wC-LUnFrY-LGg3_{(hxZY2n*~L)h`g1`5+Y6Wcy3*3FV40R@$PzKkAVG6;X=iRyWp-s@ +Y-MCbVRT_aY-w&}Q)OXnRCrKyau2r4C}<;1JnIz8xNJV~(^X1K`bf%-u8H4;5Rd<+X4P{pQ?3(@m6 +s4{*=wy-PiS_k>Wl|t&*Fr0fZ2~A~mVOC*mb!8S#O0=mQ@MdwWnpYocu;h57Y44uDeu(+mSpNyvVU;?Wpj0tETEt$u{ByCey89j8dQ03 +Wn@8fb7^O8b3$xsZe&wsVQf@*P;_!2@=#VHk7myNk^1UqykExfX@6CZd7@2Wi;=emnEZ^0vCdd$@LOV-czo1g)3{ojBg}iEK@em(;z`} +b7^O8Qe}2!VQgh&R$**)WkPIeZe&wsVQf@*X=FAAOOsb2BHT!z`XR@Y;NLiQXyctw^aAjmcb8~5DZgWCxX>MdwWnpYocxhxfvU_4@XKMa?TsAlK-}9~&K4&!} +B_Q_~{-JMMpvoC2L349yXKq$yV?lFsX=iRyWp-s@Y-MCbVRT_aY-w&}Q)OXnRCsA*LLFzFqNeWfC|Bzc +W)C&G2_(cU)%eA9tG|}D;6vKd3RH4oZgXjLX>V>s!tI8CO};e1CqOk7zVRUtJWkxi8r5^2Q3|{+hFQ&wA>Dj|l?}?5nvXn-qjmDr}rVK}HZ(?C=R$**)Wphq!%9@}OZ_-bc +51ndy0w1NGl_wIgUQD>ylx`L>RgMiuWo~72X>(I!Xk~3-TA8sVI1lHZPjU1lqsG~bOtk&)HFq4^xslxt +&yd4j96@t)X=iR$Z)s#xbYXO5LTqVnWK(5fY*ct@WM^aw-?LlPQjTl%(2ntadXH-EO|kM)2Suh4M{I9mVQf=$VRU6vV`ybZoQPE-kW*z2&v&{< +UdS6)_{YXS3Ma>jb_z*uaCLM~aA{<7gc#?E`%W7KsO97JuYbDvlzH(zmRs?SoJt!M#ot>t3r%HoVMJwg +VQFl0hyLPaScq)s9KMExvw34D6J>+NwrBxfixd_%u|$Wt4ncEsX=iS2Wo~p-d2nTmu2d>~5inUu`9yv& +8fat=S8rs<8`txcI~e&`_$v(otsF+cqN0Qy}ddQ=3E5C~Ia +Xk~3-No1AC=6W7=VqesjRYGc!>wZFzp>JB4@xD;^wu&SY_r(NHa7kpA7yOE2lZ8~neJqmb=e!%6GT&j$ +T6TU?+!P_HIBQ)dL349yXKq$yV?lFsX=iR$Z)s#xbYXO5LTqVnWK(5fY*ctqbaIwtP5eoR)-wgn>b=na +L2?WP;yphdRtnMIcPCTiyJR0hb8~5DZc=4-WnpY(WJFc;Wu}ZU +kw;6)I>KU%$CX5lEZwTb6rTk%m84<>f2kfhA@=uGO=Jtx#~n~$5JW2|a}~7vfDWQsGAeQqRB~Z%b7^#GZ*Eg#Xk~3- +tsXy=AYX8dDQEQRO5D(yMKm~r|3!X*hx(?lDDx}U2t#OLX>LwsbgiQFz^ko6x1)SL)KNJF?yfBScz9?Y +SqBl8)jS}SY$`!>b7^O8R%K&Bb8~5DZc=4-WnpY(WL9Bpb!9?qX>MdwWnpYocu;h5w&;L{94K`ndk%K5 ++?9Jv$dw7jc}U5p5@2#$kUJ%u2uWmRZggpMdAEq7KH8Joz6zOTm|U)Lm9Rr0Amv$$1lYlz$wHX7(J4W5 +b7^O8R%K&Bb8~5DZc=4-WnpY(WJFf*E{)ae8NT&o8 +22*2bWo=>7Z(864p8Ouwzj`dQ1n3V{mIVn=ti@|(ytFb|&pdtyM`dnhb7^zc?vf5kh_h+&YE#h%O8d1V +_{UOl9{V;uR#^q%T!0{hf1BB`=sqDirMEm%rl}EHag_fA3Wp< +AwhFv2!% +kp04IdejB5_YJg;9E|1`d*r&;qSS3+uh`0YNLave-ImojDN{iR+YxT1qeJQTRI%yh?{ +hxxA$L2PhnVMAeXb4+h!VRLBFJq*Jt8?Abrta^#~Iw-!oZ%zqO(A&rh^vGm~tg_w^L2PhnVN-2kY-~(# +WMOk?3sZD*X=8L$d2nTO4*&^LN2X=Q9=Q)O*QWK$LhgcQkwbf~^M){{|8P%hsRk~m~ep32F1 +51Y4WWC&DwaAi(mZDnMP)DN(0hN+Kdp}ZAoN($wDX8VgT7DmW3qm%zcviBmGB|7z0dg +BIJ4&sCG^VR$+2!VQzGR(<~&{!{{>E!(#o&^pB98KZhv1GEPn8Orhb4n;8ZMQ)zl>ZfBCy0{K32d-H~a +`3x8b375ImR&CF_#3#*gz1^xtuG$bzVQpn(MrmbiWOGwxZAoO8A%m*X98W>f2s0TH8C&EH;|vtDTYgh) +4~t7}WW`YoMQ(L%R$+2!VQzGDn938Qb#DiI%LhXtBc@pg0t!L7$2{bU&sPXOO(dS=5LRJwX<=@3Np5Cu +Q)O*QWc?UbbJ9Xwr}~3wv^yxa@v}v^+kiGSR2X#8M$tG2GZIy9X>V>;VRC6_vj93RHP;Wm9=`bY*P@01!iOZgXj8Zf#|5bY@{}b7cky2XCKHIoQI!*iVO+VNst{;wk@CbBrVQzC~WpV<7iR(=d3vg7gbV~*3!PlK51EySK +%g?1}nECovJTYovh9c2>uJC38-{*D7fZ(%hZo23R4S;p`Q9JBQllDysbY*gFX>MU`a{vkgUATk^%RRhpP*aQYQxux_Ecpx^NEUk!Ts~yw$T9tCzEwrAszt-P)%HZ|LbH=L2A=l(W4CP5=M^00000 +0RR600000000(DfZe??6a{^tsgbB+%#$2d<$}o|7E~PjL>rzR5b&Jq7pCHn+BAwE2THpkp{2tZ6dMvX9 +=nqwv1qo2B#cO4}v@%)GJbnjab#7#AWpe-t0j!@J+1z|)_nc4T)9jZsjvvUbyZ`_I +000000RR90{{R3000whoXk~3-0$sR-3ClgkT&R7@Fp+vLr8o)eQb~Pvi_kTnAkwoUoz9Fk$<9<_tH9#z +CbfD!eC0p3ZB1|7AO43pNl2#z6a{p7aAk7>>7J73J3yCzk$#1)IEB9}O*pr-e%zuW2Pj0_vj92XkX`X>fFN00{z{Dm~KXV7O_2K9yF<>+h;;t~i_0*|LWu +HI04?{jxC<1gEwF5PXV6FZDLo1#Vec_~kix7WfVQ#Sd|CM9$^_00000000001ONa40000FLvL<#X=iS2 +Wo~qIa&=_}2nTj$a&u{KZUMGnCZ)bsi%syBtF}?M>WBLk*fW6RH_XPEi=Ry;9kVTK~nd#>{Y;yn#0$sR-3ClgkT&R7@Fp+vLr8o)eQb~Pvi_kTnAkwoUodbK5wLKbzE(ciwC3nrXLGTEzPUiqv +VS}~6O1%7&o7^|1Fn59cLW!>7R25;!; +B$TyxP%GIJ;q$9eabMAdM>3n3F}fxeRYe_HJ>2T +vm%|+Z(864p8Ouwzj`dQ1n3V{mIVn=ti@|(ytFb|&pdtyVs&n0Y-Mu*2?4C18`<1^X7`*=rzR5b&Jq7 +pCHn+BAw2RHObCYVynR7?IyK)J$&Uqwrx#s+#mjjI7vvS1QZ2yd2nTO0_mQT=Q}``f02HLt~iCiD@{1J +w0_*8A_pi$)ov?1Q2l|fgMJGKo2X9f$Rbsi%syBtF}?M>rzR5b&Jq7pCHn+BAw2RHObCYVynR7 +?IyK)J$&Uqwrx#s+#mjjI7vvS1QY-O000000093000000000Gad2nTO0_mQT=Q}``f02HLt~iCiD@{1J +w0_*8A_pi$)ov?1Q2l|fgMJGKo2X9f$R@L7 +b8`U(J4=$RltJLk?Nfj|sXiSdmgaJi@wPyW+dHeUQG($HVQyn+Z*l@X>pKz(VCaX%3mIP&XB&sB3y@ML +2MxM-cip;h4&;$ho>o3z#(UxXoYzH&G?|Q<+B>SVq0fbq_@^>#jf%+zVs&n0Y-IvnxP%GIJ;q$9eabMA +dM>3n3F}fxeRYe_HJ>2Tvm%{mWD4K2WPO#YtUE?&9s-+8NK(zculdPj2pMdrn)L7 -----END STRICT TYPE LIB----- diff --git a/stl/RGBStd@0.11.0.stl b/stl/RGBStd@0.11.0.stl index 489d56ef..9e723633 100644 Binary files a/stl/RGBStd@0.11.0.stl and b/stl/RGBStd@0.11.0.stl differ diff --git a/stl/RGBStd@0.11.0.sty b/stl/RGBStd@0.11.0.sty index c499865d..110ce54c 100644 --- a/stl/RGBStd@0.11.0.sty +++ b/stl/RGBStd@0.11.0.sty @@ -1,5 +1,5 @@ {- - Id: stl:YgyNu!Qt-mt5DMxt-GXH55TN-bmrTwZH-o11V0B$-$jxMrfE#juliet-vega-richard + Id: stl:LxiMjmBl-MRIFHb1-pitHq43-IPC2~cM-SHQA3hl-mGfDECY#studio-cycle-analyze Name: RGBStd Version: 0.11.0 Description: RGB standard library @@ -11,122 +11,99 @@ @context typelib RGBStd -import BPCore#symbol-tropic-grand +import BPCore#juliet-super-dominic use TapretNodePartner#roger-member-educate use TapretProof#marco-border-sample use TapretPathProof#kiwi-mirror-paris use BlindSealTxid#halt-crash-valid use TapretRightBranch#miracle-patriot-touch use OpretProof#good-village-flex + use AnchorDbcProof#shine-betty-hamlet use SecretSeal#dollar-iris-wizard use BlindSealTxPtr#content-paradox-dominic use TxPtr#italian-july-eddie -import StrictTypes#century-comrade-chess - use VariantName#theory-austin-before - use FieldName#present-flute-herman - use Primitive#deliver-arrow-boxer - use TySemId#popcorn-super-young - use FieldSemId#spiral-road-marco - use TypeName#edgar-carol-mystery - use UnnamedFieldsSemId#freedom-degree-gregory - use SemId#logic-absorb-hilton - use Variant#humor-regard-promise - use Sizing#courage-alien-salon - use NamedFieldsSemId#solar-salad-smoke - use EnumVariants#dispute-natasha-vega - use VariantInfoSemId#museum-edward-mirror - use UnionVariantsSemId#santana-address-pepper - use TypeSystem#adrian-boris-sponsor - -import AluVM#congo-archive-folio - use Lib#gate-biology-optimal - use LibSite#ultra-grace-message - use IsaName#taboo-olympic-cloud - use LibId#germany-culture-olivia - use IsaSeg#size-shake-olga - use LibSeg#lemon-philips-horse - -import CommitVerify#miller-pancake-elastic +import CommitVerify#violet-panther-herbert use MerkleHash#horse-popcorn-bundle use MerkleProof#price-aloha-grid - use ReservedBytes1#origin-roger-relax - use ReservedBytes2#florida-libra-circus - use ReservedBytes4#young-goblin-academy - use ReservedBytes8#rudolf-tape-adrian -import RGBCommit#raymond-open-organic - use ExtensionSchema#active-eddie-empty +import RGBCommit#support-iris-depend use BundleId#carmen-farmer-diesel - use TransitionBundle#value-benny-happy - use AttachState#lady-japan-fiesta - use GlobalValues#pilot-boris-alice - use TypedAssignsBlindSealTxPtr#sultan-doctor-loyal + use AssignRevealedDataBlindSealTxPtr#shake-couple-pogo + use GlobalDetails#milk-machine-amigo + use OwnedStateSchema#donor-venice-wave use MetaValue#split-package-recycle - use InputMap#octavia-north-gram - use GenesisSchema#iron-forbid-hamlet - use AssignmentsBlindSealTxPtr#fabric-suzuki-exhibit - use AssignVoidStateBlindSealTxPtr#horse-vision-slogan - use OwnedStateSchema#python-snake-capsule - use Extension#album-forest-heaven - use Transition#pedro-accent-mother - use AssignRevealedValueBlindSealTxid#precise-banjo-ultra + use AssignVoidStateBlindSealTxPtr#urgent-mirage-carlo + use TypedAssignsBlindSealTxPtr#electra-context-elite + use RevealedData#salon-clarion-factor use VoidState#email-snow-safari - use DataState#short-noise-postal use TransitionType#picture-reflex-brigade - use RevealedFungible#java-canvas-shelter + use AssignRevealedValueBlindSealTxid#gabriel-formal-letter + use Inputs#academy-janet-karma use Occurrences#source-olga-mirage - use Schema#vocal-hammer-logic - use MediaType#isabel-heaven-north - use ValencyType#aloha-dublin-brush - use GlobalStateSchema#silk-college-august - use AssignmentsBlindSealTxid#veteran-victor-correct - use ExtensionType#apropos-scoop-viva - use AssignRevealedAttachBlindSealTxid#capsule-ozone-puzzle - use ConcealedData#ivan-tripod-young + use TypedAssignsBlindSealTxid#adam-panther-sheriff + use AssignVecAssignRevealedDataBlindSealTxid#filter-garcia-dexter + use Transition#viking-madonna-point + use Signature#ferrari-zebra-tempo + use GlobalValues#kilo-proxy-symbol + use GenesisSchema#jasmine-product-totem + use AssignVoidStateBlindSealTxid#penguin-drink-diego + use TransitionBundle#swim-cartoon-sting use MetaType#quebec-mission-quota - use TransitionSchema#jumbo-matrix-normal - use AssignRevealedDataBlindSealTxPtr#herbert-metal-guitar - use AttachId#factor-hair-everest + use GlobalStateSchema#zipper-pioneer-visa + use InputOpids#juliet-focus-proton + use MetaDetails#arena-janet-prepare use AssignmentType#secret-penguin-limit + use AssignmentsBlindSealTxPtr#sector-toronto-bikini use Opout#yoga-samba-karma + use AssignVecAssignRevealedValueBlindSealTxid#mouse-village-bravo use SchemaId#ramirez-patron-simon use OpId#picnic-single-gloria + use AssignVecAssignVoidStateBlindSealTxPtr#geneva-neutral-mercury + use AssignRevealedDataBlindSealTxid#ferrari-cosmos-evening + use SealClosingStrategy#exile-target-catalog use ContractId#uniform-welcome-papa - use ConcealedFungible#crater-vienna-vacuum - use AssignRevealedDataBlindSealTxid#compare-saddle-scorpio - use AssignRevealedValueBlindSealTxPtr#shirt-kitchen-blitz + use GlobalState#express-poker-needle use FungibleState#guide-poker-coconut - use Inputs#herman-liberal-galaxy + use TransitionDetails#dexter-catalog-alice + use AssignmentDetails#sultan-chicken-viking + use TransitionSchema#linear-origin-james use ChainNet#ringo-fashion-enrico - use TypedAssignsBlindSealTxid#richard-double-voltage + use AssignVecAssignRevealedValueBlindSealTxPtr#polygon-eddie-except use Identity#smart-pioneer-nominal - use AssignRevealedAttachBlindSealTxPtr#yankee-lunch-element - use AssignVoidStateBlindSealTxid#emerald-dream-armada - use Genesis#tropic-joseph-permit - use Input#actor-minus-multi + use AssignVecAssignRevealedDataBlindSealTxPtr#binary-rapid-trident + use AssignmentsBlindSealTxid#alias-jumbo-judge + use Schema#visa-pacific-network + use Genesis#elastic-parker-pyramid use GlobalStateType#yoga-quick-jasmine use Ffv#pigment-career-hippie - use Valencies#light-letter-comet - use GlobalState#stadium-barcode-bazaar - use Redeemed#mile-lady-perfect - use RevealedAttach#slalom-phantom-voyage + use RevealedValue#cadet-canal-switch use Metadata#member-nobody-imitate + use AssignVecAssignVoidStateBlindSealTxid#hope-prince-inch + use AssignRevealedValueBlindSealTxPtr#complex-ground-tokyo use FungibleType#matrix-optimal-sinatra - use ConcealedAttach#meter-arizona-albino - use RevealedData#olivia-copper-stamp -import Std#ralph-blue-lucky +import Std#delete-roman-hair use AlphaCaps#picnic-soprano-aurora use AsciiPrintable#ultra-sunset-format use Bool#oxygen-complex-duet - use AlphaNumDash#sponsor-snake-nice use AlphaCapsNum#aladdin-zebra-marble use AlphaNumLodash#percent-bingo-caesar use AlphaCapsLodash#duet-hammer-labor use AlphaSmallLodash#pioneer-eagle-spell -import Bitcoin#signal-color-cipher +import AluVM#jargon-gorilla-poetic + use Lib#gate-biology-optimal + use LibSite#ultra-grace-message + use IsaName#taboo-olympic-cloud + use LibId#germany-culture-olivia + use IsaSeg#size-shake-olga + use LibSeg#lemon-philips-horse + +import RGBLogic#colombo-famous-erosion + use DbcProof#needle-change-forest + +import Bitcoin#quiz-patent-exit use SeqNo#copper-verbal-ingrid use TxIn#slang-cherry-gizmo use Vout#brush-gloria-heroic @@ -148,251 +125,61 @@ import Bitcoin#signal-color-cipher use Outpoint#logo-alamo-madam use XOnlyPk#clever-swim-carpet +import StrictTypes#henry-heart-survive + use VariantName#theory-austin-before + use FieldName#present-flute-herman + use Primitive#deliver-arrow-boxer + use TySemId#popcorn-super-young + use FieldSemId#spiral-road-marco + use TypeName#edgar-carol-mystery + use UnnamedFieldsSemId#freedom-degree-gregory + use SemId#logic-absorb-hilton + use Variant#humor-regard-promise + use Sizing#courage-alien-salon + use NamedFieldsSemId#solar-salad-smoke + use EnumVariants#dispute-natasha-vega + use VariantInfoSemId#museum-edward-mirror + use UnionVariantsSemId#santana-address-pepper + use TypeSystem#adrian-boris-sponsor -@mnemonic(vanilla-static-scoop) -data AnchoredBundle : tapret#1 ClientBundleTapretProof - | opret ClientBundleOpretProof - -@mnemonic(domino-waiter-orlando) -data AnnotationName : Std.AlphaCaps, [Std.AlphaNumDash ^ ..0xfe] - -@mnemonic(phantom-habitat-pegasus) -data Annotations : {AnnotationName -> ^ ..0xff [Byte]} - -@mnemonic(baby-infant-cake) -data AssignIface : ownedState OwnedIface - , public Std.Bool - , required Std.Bool - , multiple Std.Bool - -@mnemonic(single-today-lucky) -data ClientBundleOpretProof : mpcProof CommitVerify.MerkleProof - , dbcProof BPCore.OpretProof - , bundle RGBCommit.TransitionBundle - -@mnemonic(ivan-zodiac-figure) -data ClientBundleTapretProof : mpcProof CommitVerify.MerkleProof - , dbcProof BPCore.TapretProof - , bundle RGBCommit.TransitionBundle -@mnemonic(minimum-torpedo-dispute) +@mnemonic(plaza-russian-neutral) data Consignmentfalse : version ContainerVer , transfer Std.Bool , terminals {RGBCommit.BundleId -> BPCore.SecretSeal} , genesis RGBCommit.Genesis - , extensions {RGBCommit.Extension ^ ..0xffffffff} , bundles {WitnessBundle ^ ..0xffffffff} , schema RGBCommit.Schema - , ifaces {Iface -> ^ ..0xff IfaceImpl} - , supplements {Supplement ^ ..0xff} , types StrictTypes.TypeSystem , scripts {AluVM.Lib ^ ..0x400} - , attachments {RGBCommit.AttachId -> [Byte ^ ..0xffffff]} - , signatures {ContentId -> ^ ..0xff ContentSigs} -@mnemonic(domain-annual-apollo) +@mnemonic(epoxy-monster-armor) data Consignmenttrue : version ContainerVer , transfer Std.Bool , terminals {RGBCommit.BundleId -> BPCore.SecretSeal} , genesis RGBCommit.Genesis - , extensions {RGBCommit.Extension ^ ..0xffffffff} , bundles {WitnessBundle ^ ..0xffffffff} , schema RGBCommit.Schema - , ifaces {Iface -> ^ ..0xff IfaceImpl} - , supplements {Supplement ^ ..0xff} , types StrictTypes.TypeSystem , scripts {AluVM.Lib ^ ..0x400} - , attachments {RGBCommit.AttachId -> [Byte ^ ..0xffffff]} - , signatures {ContentId -> ^ ..0xff ContentSigs} - -@mnemonic(giant-bravo-jacket) -data ContainerVer : v2#2 | (|) +@mnemonic(option-crimson-joseph) +data ContainerVer : v0 | (|) -@mnemonic(dispute-senator-parody) -data ContentId : schema RGBCommit.SchemaId - | genesis RGBCommit.ContractId - | iface IfaceId - | ifaceImpl ImplId - | suppl SupplId -@mnemonic(reward-sharp-orca) -data ContentRef : schema RGBCommit.SchemaId - | genesis RGBCommit.ContractId - | iface IfaceId - | ifaceImpl ImplId - -@mnemonic(apropos-horizon-couple) -data ContentSigs : {RGBCommit.Identity -> ^ 1..0xa SigBlob} - -@mnemonic(corner-reptile-pagoda) -data ExtensionIface : modifier Modifier - , optional Std.Bool - , metadata {StrictTypes.FieldName ^ ..0xff} - , globals {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , assignments {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , redeems {StrictTypes.FieldName ^ ..0xff} - , valencies {StrictTypes.FieldName ^ ..0xff} - , errors {StrictTypes.VariantName ^ ..0xff} - , defaultAssignment StrictTypes.FieldName? - -@mnemonic(oregano-virus-ringo) -data GenesisIface : modifier Modifier - , metadata {StrictTypes.FieldName ^ ..0xff} - , globals {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , assignments {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , valencies {StrictTypes.FieldName ^ ..0xff} - , errors {StrictTypes.VariantName ^ ..0xff} - -@mnemonic(concert-combat-charm) -data GlobalIface : semId StrictTypes.SemId? - , required Std.Bool - , multiple Std.Bool - -@mnemonic(exodus-rider-garcia) -data Iface : version VerNo - , name StrictTypes.TypeName - , inherits [IfaceId ^ ..0xff] - , timestamp I64 - , metadata {StrictTypes.FieldName -> ^ ..0xff StrictTypes.SemId} - , globalState {StrictTypes.FieldName -> ^ ..0xff GlobalIface} - , assignments {StrictTypes.FieldName -> ^ ..0xff AssignIface} - , valencies {StrictTypes.FieldName -> ^ ..0xff ValencyIface} - , genesis GenesisIface - , transitions {StrictTypes.FieldName -> ^ ..0xff TransitionIface} - , extensions {StrictTypes.FieldName -> ^ ..0xff ExtensionIface} - , defaultOperation StrictTypes.FieldName? - , errors {StrictTypes.VariantName -> ^ ..0xff [Unicode ^ ..0xff]} - , developer RGBCommit.Identity - -@mnemonic(nova-cola-carbon) -data IfaceId : [Byte ^ 32] - -@mnemonic(chris-earth-pony) -data IfaceImpl : version VerNo - , schemaId RGBCommit.SchemaId - , ifaceId IfaceId - , timestamp I64 - , metadata {NamedFieldMetaType ^ ..0xff} - , globalState {NamedFieldGlobalStateType ^ ..0xff} - , assignments {NamedFieldAssignmentType ^ ..0xff} - , valencies {NamedFieldValencyType ^ ..0xff} - , transitions {NamedFieldTransitionType ^ ..0xff} - , extensions {NamedFieldExtensionType ^ ..0xff} - , errors {NamedVariantu8 ^ ..0xff} - , developer RGBCommit.Identity - -@mnemonic(seminar-data-table) -data ImplId : [Byte ^ 32] - -@mnemonic(sultan-dexter-lotus) +@mnemonic(postal-sinatra-disco) data Kit : version ContainerVer - , ifaces {Iface ^ ..0xff} , schemata {RGBCommit.Schema ^ ..0xff} - , iimpls {IfaceImpl ^ ..0xff} - , supplements {Supplement ^ ..0xff} , types StrictTypes.TypeSystem , scripts {AluVM.Lib} - , signatures {ContentId -> ^ ..0xff ContentSigs} - -@mnemonic(saturn-escort-jordan) -data Modifier : abstract | override | final#255 - - -@mnemonic(origin-caramel-flipper) -data NamedFieldAssignmentType : id RGBCommit.AssignmentType - , name StrictTypes.FieldName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(tuna-archer-melon) -data NamedFieldExtensionType : id RGBCommit.ExtensionType - , name StrictTypes.FieldName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(museum-ohio-arizona) -data NamedFieldGlobalStateType : id RGBCommit.GlobalStateType - , name StrictTypes.FieldName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(prefix-carmen-artist) -data NamedFieldMetaType : id RGBCommit.MetaType - , name StrictTypes.FieldName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(express-brush-desire) -data NamedFieldTransitionType : id RGBCommit.TransitionType - , name StrictTypes.FieldName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(invest-apollo-inca) -data NamedFieldValencyType : id RGBCommit.ValencyType - , name StrictTypes.FieldName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(star-pilgrim-pilgrim) -data NamedVariantu8 : id U8 - , name StrictTypes.VariantName - , reserved CommitVerify.ReservedBytes4 - -@mnemonic(delphi-athlete-fresh) -data OwnedIface : any () - | rights () - | amount () - | anyData () - | anyAttach () - | data StrictTypes.SemId @mnemonic(paper-visa-storm) data PubWitness : txid Bitcoin.Txid | tx Bitcoin.Tx -@mnemonic(insect-cello-avalon) -data SigBlob : [Byte ^ 1..0x1000] - -@mnemonic(pilot-claudia-minute) -data SupplId : [Byte ^ 32] - -@mnemonic(jargon-orchid-forget) -data SupplItem : default () - | typeNo U16 - | typeName#17 StrictTypes.TypeName - | fieldName StrictTypes.FieldName - | variantName StrictTypes.VariantName - -@mnemonic(phone-claudia-kiwi) -data SupplMap : {SupplItem -> ^ ..0xff Annotations} - -@mnemonic(canoe-denmark-short) -data SupplSub : itself | meta | global | owned - | valency | assignment | genesis | transition - | extension | exception - - -@mnemonic(lobster-traffic-flame) -data Supplement : contentId ContentRef - , timestamp I64 - , creator RGBCommit.Identity - , annotations {SupplSub -> ^ ..0xff SupplMap} - -@mnemonic(sigma-rose-cubic) -data TransitionIface : modifier Modifier - , optional Std.Bool - , metadata {StrictTypes.FieldName ^ ..0xff} - , globals {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , inputs {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , assignments {StrictTypes.FieldName -> ^ ..0xff RGBCommit.Occurrences} - , valencies {StrictTypes.FieldName ^ ..0xff} - , errors {StrictTypes.VariantName ^ ..0xff} - , defaultAssignment StrictTypes.FieldName? - -@mnemonic(buzzer-holiday-fiber) -data ValencyIface : required Std.Bool - -@mnemonic(textile-next-stretch) -data VerNo : v0 | v1 - - -@mnemonic(message-danube-casino) -data WitnessBundle : pubWitness PubWitness, anchoredBundle AnchoredBundle +@mnemonic(vortex-genesis-risk) +data WitnessBundle : pubWitness PubWitness + , anchor BPCore.AnchorDbcProof + , bundle RGBCommit.TransitionBundle diff --git a/stl/RGBStorage@0.11.0.sta b/stl/RGBStorage@0.11.0.sta index c21bc6ef..fa9c2974 100644 --- a/stl/RGBStorage@0.11.0.sta +++ b/stl/RGBStorage@0.11.0.sta @@ -1,219 +1,172 @@ -----BEGIN STRICT TYPE LIB----- -Id: stl:c5eyy1RT-t6KrAvm-keIbJHD-CLn9soO-8texpLg-EECfSPw#prize-status-pattern +Id: stl:HWQT7tdF-Lqa1hg5-irH6cgG-Ot7VIra-ZFcTzDK-NPRnpDc#chess-open-nepal Name: RGBStorage Dependencies: - RGBLogic#permit-helena-lorenzo, - BPCore#symbol-tropic-grand, - StrictTypes#century-comrade-chess, - RGBStd#juliet-vega-richard, - AluVM#congo-archive-folio, - CommitVerify#miller-pancake-elastic, - RGBCommit#raymond-open-organic, - Std#ralph-blue-lucky, + RGBStd#studio-cycle-analyze, + BPCore#juliet-super-dominic, + CommitVerify#violet-panther-herbert, + RGBCommit#support-iris-depend, + Std#delete-roman-hair, + AluVM#jargon-gorilla-poetic, + RGBLogic#colombo-famous-erosion, + StrictTypes#henry-heart-survive, Bitcoin#signal-color-cipher -Check-SHA256: f2f4e349586ba5b8d7139f30b8c0bc13d0b7325b3d4dfdd5986aa015f33ddb5d +Check-SHA256: 9429df3f427cd0fdbc32d2d690a5f6612ef12a45b3cff5763b2e94977fb8ff15 -3Q|WxQ*>`~VP|Ct9rx4~O&OrvnOxfr^6gzk#5iY}j-z(!KALU=NBN052vSEvOmAmtVq4l6D4ZcK) -2hLYH81C&KXiWu&flb+s{C0G-{02f$LvM0rMe3tp+xFv-0Xp&G?S=|}9rRaeU`~uMrbA>C`}q*r3sZD* -X=8L$d2nTOVhoMD*5<7|86J&wS3rOMJWQ?e22w{tQ*>lva5aA+<>R2XhQO_4{AcS- -HH^7AVzASV8M4NYxyCjHL2PwaO?m?z-)Viz@~C%8KNS}Z0aQ3s^SOqbBwN-D{wl@OCJaMwZEb0ER%LQ& -W_h20XiL(ap`B(@2KpYTJ%x(DC3d{wiWYg@TKk|G2{Q>&M?ynyZEb0E$}AplgPGkh3_fq3Q7_j=2#kPT -_9!;lWR>~GYywm#15`~VP|CtFBpuDU}Z591s%OlK>pKz(VCaX%3mIP& +XB&sB3y@ML2MxM-cip;h4&;#rLQq3*a%D_q7H}ii_tAk8EiIL^F;WduOYhK!;vHZzZO$@xxWWuWZ*6U9 +bXH|@X=Zs{xP%GIJ;q$9eabMAdM>3n3F}fxeRYe_HJ>2Tvm%`dQb$5VZ*6U9bb^WNO%DrjRIhYP1?a)o +og)LLTw}}6rDvG=`c^zKY6DYrWSc5I(&k{eX@5SIR>|w{s%)+}o6^~`ha@$PehdAwF$F7J73J3yCzk$#1)IEB9}O*pr-e%zuW2Pj0< +ZYw-c3sZD*X=8L$d2nTO^=uPjBlbC`N(qzPM@Gr{imSMTSY5T*7C#t%#3&jH2SRCdV{d702?arHbyiIV 01^bJwgM1*ibOBDT%6aZ|SrJerP1pIOD57`7Ol|-ogQ6Pjg~y>s-v>!^VNPLfWv4Jz0xkJm$nc4y MWR2J-cc#Q6SofWC)gp7L6!Sc3I$AQVo7AP4Jk3r!|EoW{Zi$060oMN(jLzPuNboiNpoRS -WoOdj7+WWC1?EKi+6QrwlvP$nl8x-M691f9z+~t)>6ivgX<}1lX9hx0LvM0r3;+Rq2VDR_OBR)w8yCZ2 +WoOdj7+WWC1?EKi+6QrwlvP$nl8x-M691f9z+~t)>6ivgX<}1lX9hx0LvM0r3IG9o2VDR_OBR)w8yCZ2 EylR&t_^>1Sz?kFbz0>alMxYAVQ_L~bWU$%Wl&*qbZ%vG54IneKN{_;j(f`H9IfkFzO$PGD6U0+eW+%HuC5$^~^vuG3{`}-8x6fV={eh1!etXz_4^&}ra%FT-VRUFva&K>D ECY>5OGottJZHLg1Ujv+c;>sahi4MJ>bZe&wsVQf@*X=FG*VlHu0(#Ro^Jj-_-pFL#X cJe4ySuOZRLzEUxZ3PijVQ_L~bW&+&XmmnyVQyn+M^4XN(CAD)cag{ -3QuryWpq$-Z*OK~K*OqjPr(1k(EY-6%U8=q(4?)}eJ3)E0#%9cElQglL2hGcZ*om#a%*g5LTqniYgA!y -a%FT-a&K>DWMEp}<<2L&Dqlb_e6Pm!=_rp}o{aaCWdH8!$Jtd@8$oVkXm4^&WpZn5WkPIkV{1=va%FT- -a&K>DXc_Cg)w39@m$R6qOEzWQ+NTC@=;OF|0}@Y#k~NrxRcQq+F$P2q2)nlUE64L7%3W7R -4nk~cZe&wsVQf@*P;_#!ZeT05|jA;vvYupWm6Q)O{ZZweWZ*HiKem1Z9kJM|+S+XYD&bY*ifyRPVjiFd`Y2QhLn&64&owka*miGSR>-o?7a>3`V^RAF#V -Z)9aiVRL9T+8q@+Aa1+e+@!-jhcW8%o2S}z-#y5JARJB>wYeM!OmAarRB3HxICTWEOMDJSZAYFLM|~u8 -B!Bn=Wb8dls`ok|_d#@P2~%ljQ)6;zaCBd+*=^-NPQ?`2v5jYd+6t@dEhY>7H!Y*UdZb-BpG^u(WnpGh -V{&P5bdWn_aCwA}8zxgKpy7|rEn>a@Jg9&ldILR+=b-aAzAVr?5I2ooM2UlryZe??Gqk=;7%h%D+ -p%U7S;b1RT)c9`>#Kd;Rz-U=aO9W+B1XOrwWTLLzo&{8R -R%LRjg@kugo@o29zwXDHA;ech!BqJAy+4@X(~&*rw>NkSNp5sya&BR4P;0g`38@&rwvr8Q$XKK#ha*N> -X+Ls92fzOv*E(~7PRR#MWnpGkWpcj!9{gsd8U18ZYC02#KAOx^Y=h@bX*KmV{&P5bWn9- -Yh`)Fa%+!|DA9Vsm&hHC4WXN2M4aZ(WL^Hp>3BS~hw-BaLV0v$Q*?60dm);?_c?BIMu4qFRxf<)p=@qH -Cf(fs{C;c$=G;UARCwrWK+Rkw`Mu(V|7oQWGN(Z+AyvH&RuaL#N4?X)a%pCH2>>vae&!uvG+Da^2;||fJ!&Dp -*8BS%F@mRgsZfv!yd427@;7veO2zMB=|GYU;*a%*g5NMUnmT+QYFd;Umr-dgNEFCuu*?Wk)@ -WS(Jw`th(K{eY_63r%HmYiwmgY;R+0llNeFa6}P}rq7L!(40)FbL%msz%JU8hqvFyoea2o4pL=vWpZ|9 -WI}m#WpgphxGg*8X!CPrawgw_sqk4BX8}k^^xj-FXm+)yumJ%MQe|^xa&~28LV0v$b28Yqxt8-)z}-In -eIMOkG~3NFhnExe0MKl@b~cOE&{qgla%E*sZ)9cf>JtwI*nu%&Q~z;Vl^%5wS6(#;{6ajG64wDPk{-(r -Qe|^xa&~28LV0v$b2R>f7D?ZDzCQez5c=X9w<(f6`q$DH-G17V_XV{1(H;&`Wpib6c4cHjd30rSI0;fm -LPKwDZE18o00U?O%&6V>N}#h955#ht!=;R2Lj=uo+MI7C_W0!u+z&-~bY*UHX>V>*V`yb6Kou(dlA0G^4k_f9_{X9aCT` -m+=r(a$#@6CZbEf#WNc*#wto`e>uZ$?1z+)WysMU3t2e*FfKh32^DD>YKF13Ts`WEp!#kMM{I9mVQf}mY;|RG4AaeCy`?B|MH$#iox7(epK^GJZz3uq*Cb2l>R6 -Lh9EroO>_{O=WapR$**)WfhrcWXrXyKnGOwA#t$mH2bG7pQ)aE=^FQF!@KkQhzLn;aCLM|VQ?5o)zidW -vABmX&uCxQ{9vUAsn@)h(<^=)@3p(i4FwHHWo~72X>(I!Xk~3-BTDP};0*ks55c}RUto&5M4d4gMbT{# -8YchOlMBbi89{S%X=iS2Wo~qHLTqVnWK(5fY*ctqbaEu3O})vuwNYes?|slVUJVMdwWnpYocu;h5B}H_;!MSfIY{o4njA(e*y9jN*vODbSxwYq{gu+hp -5Knh*Wn@!yVRU6vV`ybbY*UHX>V>RL|e#I -O-TAgsp%#NX)%c(fjr3)`APEDlE~V`A*D$QRB~Z%b7^#GZ*DEpeMzTb7O++N8oyXDpZBoE54a3NI^6d4 -KBMdwWnpYocxhxVvZekPz%WEGnBZKS8(M7E9_@AwVcyGt -Cevi|7U8=IR&Qx!Q*>c;Wip;tQ3m-<6)UHjqig^*m4co5us7ukl*0UQzs7w8g$YDqbYW9;VRU6QQV*^Z -mKt8YDf|&5KZQ>65I6*X)C9iYp+?yjr7~y^RB~Z%b7^#GZ*Ek1aAh?*h8FxqMGF>;)g%0j&kVcqmr((< -d|oa*W2671#lR3!Wp-s@Y-MCdb#7;AVr*qL!8D=zpn(&o-7tVWUa<1Q{n`|;)uYyv!)~4rGOBqCPh(?s -a&l#EV`XzWdtiph_du_cl6_7Jvu!-2h2yT^5yv>ite$I%(jAWmQ)6glZDB$%VTFju)Tx{+}2@b8~5DZf#|5baO&%X>MdwWnpYocxhy0bsj>g6`?#s5rWnKhSeO? -L~x^!;Y#eFP|P}0Z%Ez^MR;^&ZgXjGZd7@2Wp2#WhI~QV&X+ep#A6w*Y?6dZtMP`1@htLD*t(0EsUbmg -b7^O8Qe}2!VQgh&L3DIsV`xHbX>MdwWnpYocxhyC4P_9rf`M-zw>{+&W0M0{2&GbCtpecGzFNi4r|Jm} -LvL@6CZc}4uWo==3#Mns)Y&M6LqDeqU-jv95KHlThh+c{3 -8p;h*Y8ns*OksItaxs6+hz+(e+q|0DOh?)N_UyZEhuA*+>b)o!7;u!nFdemP_$e?^hl+JkM;eY!XZL3DIsV`xcahyLPaScq)s -9KMExvw34D6J>+NwrBxfixd_%u|$Wt4ncEsX=iS2Wo~p-d2nTu5WIk~G+K)5%bR49 -t5yk`^qQ9iPjGK_bd*xl+XJhss8OG%_CC-Q>(otsF+cqN0Qy}ddQ=3E5C~IaXk~3-No1AC=6W7=Vqesj -RYGc!>wZFzp>JB4@xD;^wu&SY_r(NHa7kpJ2rNlD$O59e#ogQsB77jPl+h5j^*S;NLvL<$ -a$#e1No1d<IUvP{mXY}ey+|ZdtG&qC*MSg*Y`lhfb^DEW}Lug@XZcb%%t-SO+Y4cU? -c}!0zvoT?8H=D1RsoC%sRTdL_u<=_d8B}?2Wn@8fb7^O8b3$xsZe&wsVQf@*X=JwOfQB3>bs~EXcCXx( -drQcb3B`Fx$)^%va$Ar)C7cLJWMyu2X>@tbRHZ_FJ{?>&Rph7jPVW%b(L2*g%&@>wmxoIA`(ME#L349y -XKqquc4c8~Wn@8gbYWv?LTqVnWK(5fY*ctqbaK)dll1LbcY^ob(uSpY74YD(LO1vdEoQwrK}u5 -b8~5DZdPw;WK(oubY((pX>MdwWnpYocxhzPv_t#xfeQO-*^G1%CWcW)(d=A`A?1{twwBf$2YQ1CM`dnh -b7^zcjb8{1n}Vi_2Sx(mPtQ%C7;C?4Hp3VmIkXhJs^;PaNp5g;bk**X4oQf!Y4K`P(FaQVwIle)QgI&p -Ha%8Z1>xis%MV9vZ(?C=Q*>c;WmI`^W!jrj6Id2jc94hrndMfLayEe1ISdA&%p{mB1!VWk)dNOmcHM<$ -0B>Pr5ftu@@z<*O39}j`u&O7io3b$Is?RA$O$kloIF_owDud_0-=Ov5& -mq(eSq^TM>JW4?*h+3X!X@fjr@d0IimUQ-Q4pL=yWnpY(WI=RvVPk0ZdQCW4e)%xftOSp9TD)g5B;KO; -Krzd=y+`rt_<1!5O=WapWMOn+`Sh#^X0AbZX4L%*5q$))*;M@wXI>IJVg&1PPwC}G3`TWsXK7+=WmI`^ -W&AWn-CxfQ3;(PYq*(Q&@ei9r{ -b#!obbU|}-X=iS2Wo~p*Wp-s@Y-MCbVRT^nW^eLnZQ)OXn -S7~%^Wpi^O#}{qTDnK1gUZ=~4IPtBJuMnKCWEcQ$kD_ZvQg;gnQ)y>HY;R&QOWz*^NEK^Ovka3nbZSF5 -vXHEqN2R?6nqxf9#qALeL2hnubYXO9Z*ERuZDltO8yY=#e=i37J-o5}w=U0FTPy7>iqjyYR#Y>))`AaI -a$#@6CZb@cgV`Vr#yHxrnc61o;;Y_@lb0o?aDlVAs$BAI5s(jW5SdbV_VQpn(MrmbiWK?otZgXjL -X>V>+d2nSoYc6p#+${pKVqYC2T5jO -V`WKXK5OyylhJ#}PNp!L%7{0GY9xpq!KXGYdg; -b7^O8NoHYVWlVHJW|2#K;wB)k0g*C`Fwq1F!!?eFe@CD1{Hz9}!v$7la!zknhozd@T(rwWP-G*~32(7)!VKwhueASIYDuGM{9p;;;bXCQUmt2vc=%aBNd`Vq-niiLgsaRw~c9 -&Ny{YCK_TCaeS`x+X~XLW@}|UwF*;paBys8ZDnqBXEKMt2yp8annvOGPI~_sbHU;fx2Gv#gJM&>FkgU` -2UB%$aBN9rX~bo}HX&M*bLmIr&^7fxYqWn@NaWo%?ccywiMb7^mGRC#b^ -adI6-(bd|-i#!&GYaF>qoh8ard&4S7rwg9}|^$ORAg?_G_n1nO(?SEuMzN -{%51&MrF+jNoHYVWl3#tY=vTZV5b3xH$$#qHiSUt?>koiWBSx8z6l#U<`??EtsYNxbZ~WaL349yXKrm} -Zgf&*c4c8~Wn@8gbYWv?h8PemXlG!~;@e)_O3H?xO^a~KWeI~0jp}x-Dk@(^3qx;ibY*UIQ)y>&hQQu{ -9Qsc78(()~0WKn7PS!o2w>NdhVC3z)=0wst2~%}&aBN9*Wo?uk?`6hkSR^JNLF;fotFYyGgElEner?Qj --*6=+=BfxyZ)9m^X=QSmA}Fy@mepYsm-R}r$$+zarmRet52gKjQ(+a4Wz=vOPGN0jWJYOaY-B-mb7^O8 -ZDnqBRC#b^oD+mh$ngc_{o0BQHv&+Zz~Nu-9tWThDIq|CJf~Jy2}f*iVqt7gb#$WOS=7<6%^jtx5=^cX -z--x^3Rg~O2_Ny!Q1}E;1fU93a&>cbOl5XuY`uYqVp0y6#Opn49V(cQiM=UF)OS@-HCak`i5#Wy{om=fffyPjz%~b#y^c;Wy%QVke?j1 -l!xqXd>q7+-P0pRHy9#PwI{4d;Y3eK&S@S1XLTY^Y -?LL}v9ZWWu2|;XdXkkNPaC1n$BNr;@ghiU?gEXK9KMDE{F?;HZBRuDVqlk6qmbeZmb;*F>vukd;=m`ygb@x#_>`RmOO$0)3Z)|2*aM+Gq(Fu_0Ocz)^+@GUUoV7w&pu=F9 -->y0X3z7m=HF#-wX0mI#UQqw(qY;tp7Zc6+Qb4G4KrzO(t)@DpIt)Q@6J -WikDr@YkEAs#9)9JJvRH-Qc7Q2s%Kf+=VCyOABEU3kOtrQ)O*QWJFFoaz*WZZ5##rf6bm&7qffY6*N`B -##bI~HzDmr7z##dWo%?qWo=1hQx*t>6v={gsJ=SZlTl1iF5eQ8IAl(q%E@>So406W2vm7+WlmvjWn_%h -53p;7sgGx&z)8&prN#D&cR=tS@df05SQ3Z*PZCvbZeeX@WJYOaY-Dp&Wo=1hYXqYdo~D%m7H6OD0<^0n -_2##VWXRdjy=DB@qgYOj1yf~hNo0M=LMPN>0NEy%g(UCHeUkYj{YR7-159lqXIqm$}teZO^;JC(UrZ --Ks{e+7M1*ZDnLeX=Q9=b5mt)No1EHgR0RSPeIWLGZ_*YTjUMn3>33lep74@i%V@}#Ze4JZgp)|VRC6< -Zgg{)$`hk?ZwGtJ2SXtvrdbC93PHKYJmiYcR|q~$B%b6DR$+2!VQzFuZf0*&Wo=1h{TNkq(n4IP`h#h- -J1DmCvqiYufHpK#7;+#Z*Ep$a%o|1baPW>ZAoPPfv$so3kRF1PV2}fOp_vjQ6FdFHId|< -b)4huMS`gcRC#b^Q+acAWo-rk4MT5kbaG*1bV+VxWq1Yx3~+T~Y-wXpaBp>Va{vhfpMYpf(w(85W>NlMuXsu{2tXFT+?;?hj39&>gq>HOrf1lB-q;n)I5N0000000000|Ns90 -000004sUgIaBpdDbWd<^b#!w83IZW;tD*IvDh<9wi3iSCIT-HkA81Vlhk;Gmjr?|WwEUnvf%o<(T&E;B -3PONkMAxSUN>@h$CD;?(VA_yLjW_@a0-u0rOVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*KGm{X!fUz`M -i!Z}iQtl5;XwV(E`Zdd&WRj~^37YhpmjD0&000000RR900000000000000000RR900000001!=OZ9{Kv -baG*1bW?O;bY%ty2yN)$WoGNrYW-WRvK!KKk>= -iM=UF)OS@-HCak`i5#Wy{om=fffZ0000000030|Ns9000009W_507X<}?; -a{vhfVhoMD*5<7|86J&wS3rOMJWQ?e_G69TXIL>{4d;Y3eK*5<7|86J&wS3rOMJWQ?e3#PMu -b0zS$R1PI#k8M9VrRnYo;h`Hf2cFp`kG*~p0000000000|NsC00000024Qq`VPj|j2?Amajl1M6n%+Y* -8%A7yc}&*ktvneXjdfQ*fBrm7t?`9od0?jjhc`p6U^aw6=I=XJ|6}^pD!vIDJLVVqzpVfO0000000960 -|Nj60000h6Wo<`nZ(?C=Q*>c;Wd;HTYi@6MZU71bVhoMD*5<7|86J&wS3rOMJWQ?e -oD+mh$ngc_{o0BQHv&+Zz~Nu-9tWThDIq|CJf~Jy0-u0rOVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*K -Gcul5Q3m-<6)UHjqig^*m4co5us7ukl*0UQzs7w8g#Z8m000000RR90{{R3000nGmZE17>00Rh3Wo=1r -WMy~;1{H5`LUnFrY-K}eX>4S2Wo}7sWMy~&3Id;iXiL(ap`B(@2KpYTJ%x(DC3d{wiWYg@TKk|G2{V<* -=6W7=VqesjRYGc!>wZFzp>JB4@xD;^wu&SY_r(AS0-u0rOVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*K -GXr~*wLKbzE(ciwC3nrXLGTEzPUiqvVS}~6O1wZFzp>JB4@xD;^wu&SY_r(IAfM`q7ouQp(QU>}Ss6B;>za@6O;ffY{-CFyg83{83dy}<28ig(gSpg+? -&9*`C2(3=%09avzwZKZf-~wC#0000000030|Nj600000JVs&n0Y-K}lZgg^CV{}PwWMy~&3Id;iXiL(a -p`B(@2KpYTJ%x(DC3d{wiWYg@TKk|G2{QwGleIk>g)RqK0VQ|Mwn6X+txo3vSYd;;z)HQ~0$c*0fM`q7 -ouQp(QU>}Ss6B;>za@6O;ffY{-CFyg83{9=2rNlD$O59e#ogQsB77jPl+h5j^*S;D00000 -00030|Nj600000IVs&n0Y-LwzbZ%vHb4hMwWq1Gz0-u0rOVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*K -GXr~*wLKbzE(ciwC3nrXLGTEzPUiqvVS}~6O1#Kd;Rz-U=aO9W+B0000000000{{R30000000000000000|Ns90 -000004P$R^baG*1bV+VxWq1Gz0-u0rOVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*KGoJ`7Njk^^qPoT1 -+zTRnAg`3vXv9d*8d@RXy~6c6G6A?jl5_^Jmae8PaFd-@1fSOS=_sEK*2tZxtUl`Mr%M0;0000000930 -00000000eiWpZt4ZeeUmZe(S6015&jaI2y9pehZ%M2QE^S2-B&?H_1O1&4u6*^T^mbhP|v8SA{&vly$F -vzVnzHf7z~rv`86=_Ka^V5yX|y#`JI2?C#hXiL(ap`B(@2KpYTJ%x(DC3d{wiWYg@TKk|G2{V%rynwMZ -T8l5kSW@l}O=!>^xB4~9n`Dx!RtcK)nwJ0o000000093000000000000000000960{{R30000P0Wo=V* -VRL8(4G42%Xk~3-bYTDr0-u0rOVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*KGn7)(+XJhss8OG%_CC-Q ->(otsF+cqN0Qy}ddQ=3E5CUQhjl1M6n%+Y*8%A7yc}&*ktvneXjdfQ*fBrm7t?|-#FLmd)8^C0+InTyb -%?WTG%$DZ$m;bAR)ya#VGE@Kn000000093000000000JQW?^Gxa{vkgVhoMD*5<7| -86J&wS3rOMJWQ?eJIcU;0|?p#+${pKVqYC0%8n}yW}mJ-a|7RMqGY*OxEVD -JQ*I1byq-t{ya>r@j1sDK7J55&$qsubbafuzL1-^j%|=cN>I>nnK4))Pyhe`000000RI300000000(Df -Ze??2a{vkgpMYpf(w(85W>Np9m~TI>-W|y2ahx3nF|Vuawki#7NH? -S|Q-Q!u2{b0-u0rOVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*KGt#s}`|*Ja`)b*YbP*k000000RI300000000nb(aByq@3Ibvbjl1M6n%+Y*8%A7yc}&*ktvneXjdfQ*fBrm7 -t?>q!t+(1Z!Y#S=r-tc=NPf>PeW=$`IKP*ssSB}HE2RJl0%8n}yW}mJ-a|7RMqGY*OxEVDJQ*I1byq-t -{ya>r@nb#HiLgsaRw~c9&Ny{YCK_TCaeS`x+X~XLW@}|UwEzGB000000RI300000000000000000RI30 -0000000&}qZe(m_a{vkgpMYpf(w(85W>N1ACLTJsO2B2U!6ncg?mz -@CdC==Kxq?gSEg)z2E{|0-u0rOVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*KGX;3#jF_Psll$K3m0qvW ->0&oDqqo0*?q^FKQ(!8W@c;k-000000RR90{{R30019PzbY*UHX>V?G015)1fM`q7ouQp(QU>}Ss6B;> -za@6O;ffY{-CFyg83{9$$mV(;bz)!CmQ_M(k?Vd!kfCo{nDM?)_qK{868FUdpMYpf(w(85W>NCW*|x7tZ`I!jQ)C-lM`_kv%gaYO7(UC~SMps>d-e0000000000|NsC000000 -33q99Ze??GWpe-u0`+VYVk7oBr%DNv+($;q`HHK!gIHa)*%m(-e#9sm3ZsHT^UK%K(4i9Ajp1M~R@C@! -4#dQE#lUD;OiKi1Rsv!Sjl1M6n%+Y*8%A7yc}&*ktvneXjdfQ*fBrm7t??2o-$0@yp2V-B2Sg`iDCMTP -tNw5A9E}qwvrD7&DWm`Z0000000960|Nj60000YNbaY{3Xl-R~baMa-0-u0rOVXX8on}%7`W~n~g^Ir= -cD&(=7J1!T`=A*KGlX#slPpg3!?y@aX^XIja4CK{WF&t@k=WXUZP9(YH~bW>$vY;yn!0wHj#q4l6D4ZcK)2hLYH81C&KXiWu&flb+s{C0G- -{HLh$xdReUg_1Rxg;i+}Ss6B;>za@6O;ffY{-CFyg83{AC=zxYCD0L!x4tB5Hm3vFbl?lap -NXe%XU~*fKJ0+X~VhoMD*5<7|86J&wS3rOMJWQ?eqTpH7(Xh=OrK%E4t`xv**_;Yj -PG|`q@y<~A1W*K^0000000000|Nj60000001Z-(ya{vkgVsJHoA?4$swuZp1Wc+9AOf`(TIbyKWjTy4W -kGaM+r!Z9lE%{u?@QI^EqCb}2Q7OO^w+`_q*ddTXmHSf)0%CAAe<9`Lptgpr6F_xjAC6(~TLj -#*ewiHWCDr@#54KP!Z9Fy4s@&s7y*hO1UlNfirx{z*_V4e8lMKAp&9y -jl1M6n%+Y*8%A7yc}&*ktvneXjdfQ*fBrm7t?`B!5G-hCV9w&(UffE`hM!G~aLQ!~gAR@AcC9KZUqt`_ -000000096000000000P0Wo=V*VRU5%0||F&bZ%vHb7gY?3Ig?P6JjIwIj2eqliWu}$@z+_xPw?-wb>Rw -7=FYk8VaL=Li5Yl(a@n1+Ku60FILp}Zw|!7cE!MGSxid=WmWLp3P=6Evz0000000030|Ns900000EX>N95Y-wad -b#7#AWpe-t0-u0rOVXX8on}%7`W~n~g^Ir=cD&(=7J1!T`=A*KGXr~*wLKbzE(ciwC3nrXLGTEzPUiqv -VS}~6O13Id;iXiL(ap`B(@2KpYTJ%x(DC3d{wiWYg@ -TKk|G2{WGvEJ-@Z0;0Ob-P{Wzd?2rs)M&&=&l*}G;Jw22Ix+zQeSE-D&as6bavW-TpDK3Q$S;EaU-vt4 -bL@h$CD;?(VA_yLjW`fRcyMfKV`+3#WnpYocxhy(sPef35>JJaHJF7}X$37Y21E`BySDf% +$MYb{T~|g9LTqVnWK(5fY*ctqbaJufI5`vwIKJ?28qdBQV5M*2;q-lY2q<~K(fZR6A>9R3cu;h52SRCd +V{d706aWDkZG|bw_S!^E6;6$ujJ=)@jfnzUJFt-<#ywK79)|@}WpPe#3K@{sQ}POxW*-wf^&?6pkN!)@ +-3ce88{`DNj-p1Y1XOrQZXx47L&d6G@+l`%qd385?K@+fP1(-9sgE>i7rMzqbp%##b#x`G^|=xh7rLW4 +)L(lQb*FJl;d*r#UC=Q#deq4+>4pnaV{&P5bV7M_WpgpRuIPk`cg3&=F>*1@lJ+pRDJ{*3f84s>#k$1l +f7uIEVQ@}wWMxQUb7(c%9ThnsZoA#wq{BUjG3xT0r`mMiJ;;I}98MOsxf}>gZ)0mzX>DaVbp)|Xd=5r! +N1hi)eI#@wfA|Ar>^)1W_c|c=L3C>gQ)y>YV{&P5bYHC5ZRI~s#T41Gjc0(`3ajfaCJX&HEu+ACq+L0m +O$tn9VP;cfa%pgMkUL~>d4!J}CQ~Zp&c>#RM4(exxbT6?CbPTvEuK5`1yp!Xb##~Y*9JnaDl?KLJE%?_ +&cu`BzdqA(v4?YpHBQWkf@=g*VRUnyRgqGWM}19*F@#XVmjaq%az$04KD-Vbij2I +Prk>V1yp!eWpb&7gm+V(X#23g?#G%T#8*SXRQUS6KbYXtkv-?PH+Tw3ZggdGZeeUtYqm29sTjYuk_~Ri +SfnI}BSut4!A4H=_ds@ZTntlV +a%pgMP<3K!WqHJMYmbj8(R#s`$Q_Oip_^hvoaWGEUH-@Ecs#X-@uLSqd30q{baKUeA)3GUIc{=BfUQMV +FMRBwY;Hd$-Q55DeryBg+(ZIYc<5?C&0HnY62ZUYgq2{$1_)1ebZ~EJZgl*j +rz*aY{>_4@v6zr!BEn8~s;V{eB++vPW1tu=h*<|%Pi|~^P-_fBZ*6U9bXH|@X=Zr^05Fw)<{e=)S-S-Y +Q3WPbltNdpi4*91)SI!> +2Tf&jb75y?IG#g>Clv)aMjKgwAH@`bu1x<7g|G$};xvA~n-$_S3Qc8lYiwmmVRL9)&E@`k{z!7(TI@Y9 +B6!g4sB24Po?(Fc@vtHNfU4XJO=WUxY-K`hZ)0oNwYiq_Rlwao{(T?aUNqayF^88E^#IUpx^^~;)zDW6 +RB~lyPH$vo2~tNwLvL+uX>>LK1ACLTJsO2B2U!6ncg?mz@CdC==Kxq?gSEg)z2E{|2tsvkWNc+gWDG*x +skq)xpV`Gw<@$3$0NV?f{JPT8u3(v#XUGyU%pgH?b7^O8Qe}2!VQgh&L}7GcLTqVnWK(5fY*ctqbaD^2 +%P43gO+4!q%eZVl@Y7XFOZrI4j;@LJR>mVbPjd}NY;R&=Y(!;rVQFl05mk4XX5>{BgqY!%B9ne2;GPx* +vyoN#D~xyn2O`xG5Knh*Wn@!yVRU6vV`ybj|MdwWnpYocu;h5 +Ao5UFB9CUy{E_wOY}Ov_ +b`4?P%YY`+Wb+o`y9rirX=GD$VRU6QQV*^ZmKt8YDf|&5KZQ>65I6*X)C9iYp+?yjr7~y^RB~Z%b7^#G +Z*Ek1aAh>_o|h$~m;x7qi^=s8P2N+kb%iTyz>IGsVJuTN&(k15b8~5DZc=4-WnpY(WL9Bpb!9?qX>Mdw +WnpYocxhxd21}DyAtKyJp!y-llj5_1lAj$w(~~K8Zkuu=2wF ++7z(Wqt=tdZk`V^s(A}fV`Fu4a%FB~Wpg*1^P0j`PyFcKl0@oC_m?3Ve+y;&po9u3K1f-Y=e!wId2nT9 +L349yXKr&sY-w&}Q)OXnRCsA*II??UXJ=~udt5d*^xyNY6+UM*BPAgB7yhAdTcFArC_!^`X=iR$Wn)2e +b7^O8Qe}2!VQgh&L}7GcLTqVnWK(5fY*ct@WI`Qhoua1h@F-X75M~cGx(Ou2EYc;WkPIe +Ze&wsVQf@*X=G<)3g5G2eU+-LJ4R_90-H=oQq8@u`N?Dm8EmJT^zaZ=a$#@6CZbEf#WNc-1*YiE5tb$Y2vUw~^w5s+eR_{-?oF}s +QU^t*5l3uqVqt7kbYXO5Q)6glZDE4?v{pIxoScYNB9K#M4$pVGM_$MqSNO-qKME(uiFOJ}Zg6#UPjG2u +bA%Y@iTh3)1gPcX^{;=r`ILF_J(gSXjhspw6vf|LHVaK_2Ed=W5NNclv5FdArN4p(nv$Q#%5lsg#tSokXs89{S% +X=iS2Wo~qHLTqVnWK(5fY*ctqbaImrynwMZT8l5kSW@l}O=!>^xB4~9n`Dx!RtcK)nwJGnaBp>VlRC}c +diNl+Np+sim8IKY2NL?#G1fp*MV^LGtQvy0DM52{X=iR$Wn)2eb7^O8Qe}2!VQgh&R$**)WkPIeZe&ws +VQf@*X=IdA)7t~9tEf?*r}jS36zkMYeK9}${s8)2BzjZ?kPrw{V`ybF%vyGSQrr|FsW@w0CP8y^X=iR$Wn)2e +b7^O8R&Qx!Q*>c;WkPIeZe&wsVQf@*P;_#ZWKH}@ht@L%%<8?+|3PvL1mZnE9aaj_-*+cdMdwWnpYocxhysE!4oj;3`<37v2Z4^tv`QLvAn=wSY4a%d)dfQpu?kQ)OXn +Lu_wzX>MmzbaG*IWoLPx2rNlD$O59e#ogQsB77jPl+h5j^*S;NLvL<$a$#e1No1lk$>=Cf +%ypRj207<6(8~ghODx=kkv^H(szyE})=~>cY;R&=Y*Tb$bY-TDFp)<~$~wYgjK`HkjV#@&#T1_fGnK3M +JXK)_7bXoxb#7;AVr*qobYXO5r?zUHR4te2V>s +WprU_Y;&t+cznDDD1^I$Y^N^U(vj;W#J@gj^sY5z(hn_6P=XObb8~5DZf#|5bVOxzVQFl0tbeHV>*V`ybPpga1W- +frt90uqg8@)(AsrVQFqoWpu5g^uVjFLARrPJ=9S-1@5ja{CIe19$5zwmeo8Ulx!+Nb8~5DZdPSuL349y +XKqquc4c8~Wn@-iY;|QqY-w&}Q)OXnRCrKya<=Gzh8!q$B6|*YuiTY;OURW8#d%1{rxIXtTaY^?oCrx| +Wo~q7ba}UkqCVP_+P(^zWtd#9ah0$`At2>hiv-xgp2MdwWnpYocu;h5%sU`)39H8lI7A^rifZh_?ICzyC$UZalW1NfPXalR7(sJ$X=iS2Wo~qHLTqVn +WK(5fY*ct@WX_B=$<9<_tH9#zCbfD!eC0p3ZB1|7AO43pNl2#z6b4gcXk~3-(r;Se1fKjJ)xUZyvjpf5 +Rh9(_P^`skWxTX9SMp{wIfQLx1JC|lRtv}2|vJ# +Rj;5&YI0c6F%?4p4N_%xWnpY(WL9Bpb!GK>O*mP8`7qV21dnrCyk{{a-lF$FG0V5TNAc?Tc{K=4WprU= +VRT{lTw_^8WdM??RZ;ab079^O9n9I5E1y8~f0E6BLSf$}L349yXKq$yV?lFsX=iR$Z)s#xbYXO5LTqVn +WK(5fY*ct@WcSVA$Leu*(}zl(oBO2gDT>+WIm|Pn7B)KM(;qzK2_Zpqb7^O8Qe}2!VQgh&R$**)WkPIe +Ze&wsVQf@*P;_$n^sESGu0eNZ)cp(*eFU-DRQ(QTUJ^TE1nY56>E%WYMs;pyX<}?;RC#b^2vSEvOmAmt +V*~&Wz8;AIDT-**L6)$-r+lRyXoI{GIo*U3C +NI7Emc=xo*$N+#63Rh`#Ze??GP;Ya2#Mns)Y&M6LqDeqU-jv95KHlThh+c{38p;h*Y8ns*OksItaxstV +VFCP7wPq#=<|G-oQP|YlF^@fu07kb?cmYX}g@OuKX>@L7b8}B}WCl`4LQ`~P2LJ{;OOmXVLEy~oQ-C|E +J{=;K=5mqowm^*AJFBo!g5e5Kbz)a(bZ%vHb5FsfyU6^!Am>*UnF~ugt;tRB34tClkb#0P@Kl(bS{+Yy +bZ~WaL349yXKrm}Zgf&*c4c8~Wn@-iY;|R4z!w}!_*fFX9u23x2B)@U$sQVATFdKeto{kO7k*y}PjFXh +bZ%vHbDeh}Dl%U><|oit;<)Mmc#PrnMmBmzDete!zLOlP=NwOUbZ~WaL349yXKrm}Zgf&*c4c8~Wn@HQ +bYZQUDoPxXm+POS?Zkdao(?NvR4VY;R&=Y)^G`!^wVq=f*JR(GpTfNL}lr+43(S +;gS+vl4Z-(f9Jy@8BcX|aCLM+b8~5DZf#|5bXIR^WK(oubY=3%=@L7b8`bzbYuqrCxp?AYYxUduU{DdG`^>&S@S1XLTY^Y?LL}v9ZWWu2|;XdXkkNP +aC1n$BNr;@ghiU?gEXK9KMDE{F?;HZBRuDVqlk6qmbeZ|1Bk8zGh-IHIi*o-3_)ygXkkNPaC1&| +ZI#2l$xQ-a`EhCyJoZT~T}~sIjxz)>1`ZdvNB=ndTz*X~v;Uq>`<)y^XImOPdju4Lv +R$+2!VQzFzVQpm_v{(W1V6JV*{3!yZ{M3XW@z+pX9Jt +zktHWiJ@1L)babHELfN$u@7k>`Uy~SX>DnAX?A5X{h;vIo29B#Zbv)THgnzJqzni;K&ISmvLd)pN>Rl&wr9&I-v?L-&~MrmbiWK(5rNn}$N2!s^Lf^?|9I@Xg> +Oi(W05|TJ%PM*ricn_PmXk-Xfd2nS;VQpn(jMNXXYlf+hXQ9AJ%?72#_KJ5v@E-96x! +ZDnLeX=Q9=b5mt)Nn~pTqZFQ|l>ioJpYH;+t0eX2w~A!Q+0eaZ{MVycPK^aqWo=1heaS*6)M5bHCYFUH +@63IY`6K;Dlo$g{Z6f4)7N~Yk2UcNnX<=@3fzvD`*Td*C*~4P}$n=kpoj->tyfRKrOAiJKV)22*Kz +X>Mnd(*pTEa(nZJgZT^?2ML$C)mClKyTm8WaJ}8CMy}crPGN0jWJYOaY-Dp&Wo=1hmm!0y(Hu`f(Fijc +5*b_M4dVsY!8b|ZDhq!3`K5rZB}7&X<=@3bC}8#qjhfwd&>tyAtR<)2LcK~xyL-@iqBUFK20Q^ +G*lRL(MHiY2Qv~?ZfS3BR$+2!VQzGD +Q)O*QWc`7zgMJGKo2X9f$RrzR5b&Jq7pCHn+BAt^EynwMZT8l5kSW@l} +O=!>^xB4~9n`Dx!RtcK)nwJ0o0000000960|Nj60000heb#!oVX>N2+aBp>Va{vkgJ?lFX3Sj7m#S0l< +6lWWUs|%1)CkG9>cz4~pa1P{=pge*1_9$GZBsdB}fMG<}rv*w^M*=0-6Wn0hkV%a=00{zJxP%GIJ;q$9 +eabMAdM>3n3F}fxeRYe_HJ>2Tvm%|75WIk~G+K)5%bR49t5yk`^qQ9d0000000030 +|Nj60000000000000030|Ns900000GO=WFEZ*FvQVPkYtbYXO51_lUoV`ybbaG*1bV+0a +UATk^%RR-W|y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b +24`$rzR5b&Jq7pCHn+BAwOlk`76TvuW{aQ_%-X`?VwZ$5L?~ +`!+pRSq0(b70UrvE7rsqBHk#fJ+ZFZf!BafnCGSE(FlGoV#P-WF=PJ#00000000300000000006a%pF1 +baMa+0xuYhj$mam5(OQ-X^PS6<8luRZ`?5<&;xj7m}kQfCd0{oedoq7=Ft*TNJw4lquKH=AmNe{U6N(X +)PLv0A^-pY000000RR90{{R30010MwZf9v?Y-Mu*2?8$|jE-PsF%ktGy=jWk>f>?`3vb*pAf>?`3vb*pAASyCnI_4+PSmLc;Wd;HTYi@6MZU71bFBpuDU}Z591s%Oen_4UD`8YGkyt}EpMh{<^eb^)0$sR-3ClgkT&R7@Fp+vLr8o)eQb~Pvi_kTn +AkwoUogng1Rw9pP&is-3>Sw%P#_(xeJx6(SSwF1NH_CEIWdHyG000000RR90{{R3000nGmZE17>00Rh3 +Wo=1rWMy~;1{H5`LUnFrY-K}eX>4S2Wo}7sWMy~&3IbiYgbB+%#$2d<$}o|7E~PjL>rzR5b&Jq7pCHn+ +BAu1U=6W7=VqesjRYGc!>wZFzp>JB4@xD;^wu&SY_r(AS0$sR-3ClgkT&R7@Fp+vLr8o)eQb~Pvi_kTn +AkwoUodbK5wLKbzE(ciwC3nrXLGTEzPUiqvVS}~6O1rzR5b&Jq7pCHn+BAu1U=6W7=Vqesj +RYGc!>wZFzp>JB4@xD;^wu&SY_r(HTxP%GIJ;q$9eabMAdM>3n3F}fxeRYe_HJ>2Tvm%`Xdy}<28ig(g +Spg+?&9*`C2(3=%09avzwZKZf-~wC#0000000030|Ns900000JVs&n0Y-K}lZgg^CV{}PwWMy~&3IbiY +gbB+%#$2d<$}o|7E~PjL>rzR5b&Jq7pCHn+BAo+!leIk>g)RqK0VQ|Mwn6X+txo3vSYd;;z)HQ~0$c)J +xP%GIJ;q$9eabMAdM>3n3F}fxeRYe_HJ>2Tvm%|J2rNlD$O59e#ogQsB77jPl+h5j^*S;D +0000000030|Ns900000IVs&n0Y-LwzbZ%vHb4hMwWq1Gz0$sR-3ClgkT&R7@Fp+vLr8o)eQb~Pvi_kTn +AkwoUodbK5wLKbzE(ciwC3nrXLGTEzPUiqvVS}~6O1#Kd;Rz-U=aO9W+B0000000000|NsC0000000000000000 +|NsC0000004P$R^baG*1bV+VxWq1Gz0$sR-3ClgkT&R7@Fp+vLr8o)eQb~Pvi_kTnAkwoUou3FSNjk^^ +qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G64kxGba`;79(Hi^QCjpnbefDtxpKz(VCaX%3mIP&XB&sB3y@ML2MxM-cip;h4&;$&8SA{& +vly$FvzVnzHf7z~rv`86=_Ka^V5yX|y#`JI2?AZXgbB+%#$2d<$}o|7E~PjL>rzR5b&Jq7pCHn+BAt^E +ynwMZT8l5kSW@l}O=!>^xB4~9n`Dx!RtcK)nwJ0o0000000960{{R30000000000000960|Nj60000P0 +Wo=V*VRL8(2MBXxXk~3-bYTDr0$sR-3ClgkT&R7@Fp+vLr8o)eQb~Pvi_kTnAkwoUos?43+XJhss8OG% +_CC-Q>(otsF+cqN0Qy}ddQ=3E5CUDegbB+%#$2d<$}o|7E~PjL>rzR5b&Jq7pCHn+BAw2RHObCYVynR7 +?IyK)J$&Uqwrx#s+#mjjI7vvS1QY-O000000093000000000MPWo~72Wpe-u0$sR-3ClgkT&R7@Fp+vL +r8o)eQb~Pvi_kTnAkwoUou3FSNjk^^qPoT1+zTRnAg`3vXv9d*8d@RXy~6c6G6G$=gbB+%#$2d<$}o|7 +E~PjL>rzR5b&Jq7pCHn+BAwE2THpkp{2tZ6dMvX9=nqwv1qo2B#cO4}v@%)GJbnNG000000096000000 +000MKb#7#AWpe-u0$sR-3ClgkT&R7@Fp+vLr8o)eQb~Pvi_kTnAkwoUodbK5wLKbzE(ciwC3nrXLGTEz +PUiqvVS}~6O1rzR5b&Jq7pCHn+BAsVs3g5G2eU+-LJ4R_90-H=o +Qq8@u`N?Dm8EmJT^zZ-x0000000960|Nj60000ShX>@L7b8}^L015*2Y!hN5_Bp3Y36tDMM#=e#tGI($ +UA5U3KNx<*C>jc*f- +a%FT=WnpY{00{y;>pKz(VCaX%3mIP&XB&sB3y@ML2MxM-cip;h4&;%isPef35>JJaHJF7}X$37Y21E`B +ySDf%$MYb{T~|f`0000000030|Ns900000Aba`-PQ+acAWo-iKo|5M~K$m}!eub_$g}*CJIJdNZ+@c}} +C`8q6D?CvBfv$so3kRF1PV2}fOp_vjQ6FdFHId|+h;; +t~i_0*|LWuHI04?{jxEqFjWFA`CQ2GiK9iLKbGE6DZmrA4)G`0A&^0p`%?-6n<_oh=3uyKe?FB~$?NZ` +Y_2$)(%G_yBsGnG3;nV&5(KBV0uX$PL@)I=)&*`^S@`8Scoz5#{lyP)a751L0000000000|Nj6000000 +2u)>eQ*>c;Wd;KYcWHEPWpi_7a{vkg^=uPjBlbC`N(qzPM@Gr{imSMTSY5T*7C#t%#3&jHqk=;7%h%D+ +p%U7S;b1RT)c9`>#Kd;Rz-U=aO9W+B0;-8nrZYj|nJFZS6xP`-jES%TjD&(ihCCQ0ZEXBf&c&j000000RR90{{R3001jzxc42I3WI}arWNc+~00{zJxP%GI +J;q$9eabMAdM>3n3F}fxeRYe_HJ>2Tvm%`Xdy}<28ig(gSpg+?&9*`C2(3=%09avzwZKZf-~wC#00000 +00030|Ns9000009V{dMBa$#e1a{vkgUATk^%RR-W| +y2ahx3nF|Vuawki#7NH?S|Q-Q!u2{b0n9D`_KFAY2phA?>-!eGJLd1CM2xPn1?{~t^y ^ ..0xffffff {RGBCommit.Opout ^ ..0xffffff}} +@mnemonic(organic-sweet-karate) +data ContractIndex : publicOpouts {RGBCommit.Opout ^ ..0xffffffff}, outpointOpouts {BPCore.ExplicitSealTxid -> ^ ..0xffffffff {RGBCommit.Opout ^ ..0xffffff}} -@mnemonic(henry-agatha-parole) +@mnemonic(laura-eric-planet) data MemContractState : schemaId RGBCommit.SchemaId , contractId RGBCommit.ContractId , global {RGBCommit.GlobalStateType -> ^ ..0xff MemGlobalState} , rights {RGBStd.OutputAssignmentVoidState ^ ..0xffffffff} , fungibles {RGBStd.OutputAssignmentRevealedValue ^ ..0xffffffff} , data {RGBStd.OutputAssignmentRevealedData ^ ..0xffffffff} - , attach {RGBStd.OutputAssignmentRevealedAttach ^ ..0xffffffff} - -@mnemonic(august-depend-banana) -data MemGlobalState : known {RGBStd.GlobalOut -> ^ ..0xffffffff RGBCommit.DataState}, limit U24 - -@mnemonic(lithium-lunar-cartoon) -data MemIndex : opBundleChildrenIndex {RGBCommit.OpId -> ^ ..0xffffff {RGBCommit.BundleId ^ ..0xff}} - , opBundleIndex {RGBCommit.OpId -> ^ ..0xffffff RGBCommit.BundleId} - , bundleContractIndex {RGBCommit.BundleId -> ^ ..0xffffff RGBCommit.ContractId} - , bundleWitnessIndex {RGBCommit.BundleId -> ^ ..0xffffff {Bitcoin.Txid ^ ..0xff}} - , contractIndex {RGBCommit.ContractId -> ^ ..0xff ContractIndex} - , terminalIndex {BPCore.SecretSeal -> ^ ..0xffffff {RGBCommit.Opout ^ ..0xff}} - -@mnemonic(horse-reunion-tonight) -data MemStash : schemata {RGBCommit.SchemaId -> ^ ..0xff RGBStd.SchemaIfaces} - , ifaces {RGBStd.IfaceId -> ^ ..0xff RGBStd.Iface} - , geneses {RGBCommit.ContractId -> ^ ..0xff RGBCommit.Genesis} - , suppl {RGBStd.ContentRef -> ^ ..0xff {RGBStd.Supplement ^ ..0xff}} + +@mnemonic(electra-before-cobra) +data MemGlobalState : known {RGBStd.GlobalOut -> ^ ..0xffffffff RGBCommit.RevealedData}, limit U24 + +@mnemonic(canyon-sherman-nurse) +data MemIndex : opBundleChildrenIndex {RGBCommit.OpId -> ^ ..0xffffffff {RGBCommit.BundleId}} + , opBundleIndex {RGBCommit.OpId -> ^ ..0xffffffff RGBCommit.BundleId} + , bundleContractIndex {RGBCommit.BundleId -> ^ ..0xffffffff RGBCommit.ContractId} + , bundleWitnessIndex {RGBCommit.BundleId -> ^ ..0xffffffff {Bitcoin.Txid ^ ..0xffffffff}} + , contractIndex {RGBCommit.ContractId -> ContractIndex} + , terminalIndex {BPCore.SecretSeal -> ^ ..0xffffffff {RGBCommit.Opout ^ ..0xffffff}} + +@mnemonic(nylon-studio-singer) +data MemStash : schemata {RGBCommit.SchemaId -> ^ ..0xff RGBCommit.Schema} + , geneses {RGBCommit.ContractId -> RGBCommit.Genesis} , bundles {RGBCommit.BundleId -> ^ ..0xffffffff RGBCommit.TransitionBundle} - , extensions {RGBCommit.OpId -> ^ ..0xffffffff RGBCommit.Extension} , witnesses {Bitcoin.Txid -> ^ ..0xffffffff RGBStd.SealWitness} - , attachments {RGBCommit.AttachId -> [Byte ^ ..0xffffff]} - , secretSeals {BPCore.BlindSealTxPtr ^ ..0xffffff} + , secretSeals {BPCore.BlindSealTxPtr ^ ..0xffffffff} , typeSystem StrictTypes.TypeSystem - , identities {RGBCommit.Identity -> RGBStd.TrustLevel} , libs {AluVM.LibId -> AluVM.Lib} - , sigs {RGBStd.ContentId -> RGBStd.ContentSigs} -@mnemonic(bazooka-dallas-martin) +@mnemonic(eddie-prague-trilogy) data MemState : witnesses {Bitcoin.Txid -> ^ ..0xffffffff RGBLogic.WitnessOrd} , invalidBundles {RGBCommit.BundleId ^ ..0xffffffff} - , contracts {RGBCommit.ContractId -> ^ ..0xff MemContractState} + , contracts {RGBCommit.ContractId -> MemContractState} diff --git a/stl/Transfer.vesper b/stl/Transfer.vesper index e5031dd9..2ac2076b 100644 --- a/stl/Transfer.vesper +++ b/stl/Transfer.vesper @@ -7,1005 +7,278 @@ Seals vesper lexicon=types+commitments -ConsignmentId commitment hasher=SHA256 tagged=urn:lnp-bp:rgb:consignment#2024-03-11 - ContainerVer serialized - Bool serialized - ContractId serialized - DiscloseHash serialized - ImplId set len=0..MAX8 - ImplId element - DiscloseHash set len=0..MAX32 - DiscloseHash element - DiscloseHash set len=0..MAX32 - DiscloseHash element - SecretSeal map len=0..MAX16 - BundleId mapKey - SecretSeal mapValue - AttachId set len=0..MAX16 - AttachId element - SupplId set len=0..MAX8 - SupplId element - TypeSysId serialized - LibId set len=0..MAX16 - LibId element - ContentSigs map len=0..MAX8 - ContentId mapKey - ContentSigs mapValue +commitment ConsignmentId, hasher SHA256, tagged urn:lnp-bp:rgb:consignment#2024-03-11 + serialized ContainerVer + serialized Bool + serialized ContractId + serialized DiscloseHash + set DiscloseHash, len 0..MAX32 + element DiscloseHash + map SecretSeal, len 0..MAX16 + mapKey BundleId + mapValue SecretSeal + serialized TypeSysId + set LibId, len 0..MAX16 + element LibId -Consignmenttrue rec - version enum ContainerVer v2=2 - transfer enum Bool false=0 true=1 - terminals map len=0..MAX16 - value bytes len=32 aka=SecretSeal - genesis rec Genesis - ffv is U16 aka=Ffv - schemaId bytes len=32 aka=SchemaId - flags bytes len=1 aka=ReservedBytes1 - timestamp is I64 - issuer ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 - chainNet enum ChainNet bitcoinMainnet=0 bitcoinTestnet3=1 bitcoinTestnet4=2 bitcoinSignet=3 bitcoinRegtest=4 liquidMainnet=5 liquidTestnet=6 - 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 - assignments map len=0..MAX8 aka=AssignmentsBlindSealTxid - key is U16 aka=AssignmentType - value union TypedAssignsBlindSealTxid - declarative list len=0..MAX16 wrapped tag=0 - AssignVoidStateBlindSealTxid union - confidential rec tag=0 - seal bytes len=32 aka=SecretSeal - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal bytes len=32 aka=SecretSeal - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - 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 - AssignRevealedValueBlindSealTxid union - confidential rec tag=0 - seal bytes len=32 aka=SecretSeal - state rec ConcealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - concealedDummy is Unit - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec ConcealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - concealedDummy is Unit - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal bytes len=32 aka=SecretSeal - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - lock bytes len=2 aka=ReservedBytes2 - structured list len=0..MAX16 wrapped tag=2 - AssignRevealedDataBlindSealTxid union - confidential rec tag=0 - seal bytes len=32 aka=SecretSeal - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - 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 bytes len=32 aka=SecretSeal - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - 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 - AssignRevealedAttachBlindSealTxid union - confidential rec tag=0 - seal bytes len=32 aka=SecretSeal - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - 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 bytes len=32 aka=SecretSeal - 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 rec BlindSealTxid - txid bytes len=32 aka=Txid - 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 - extensions set len=0..MAX32 - Extension rec - ffv is U16 aka=Ffv - contractId bytes len=32 aka=ContractId - nonce is U64 - extensionType is U16 aka=ExtensionType - 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 - assignments map len=0..MAX8 aka=AssignmentsBlindSealTxid - key is U16 aka=AssignmentType - value union TypedAssignsBlindSealTxid - declarative list len=0..MAX16 wrapped tag=0 - AssignVoidStateBlindSealTxid union - confidential rec tag=0 - seal bytes len=32 aka=SecretSeal - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal bytes len=32 aka=SecretSeal - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - 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 - AssignRevealedValueBlindSealTxid union - confidential rec tag=0 - seal bytes len=32 aka=SecretSeal - state rec ConcealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - concealedDummy is Unit - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec ConcealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - concealedDummy is Unit - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal bytes len=32 aka=SecretSeal - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - blinding is U64 - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - lock bytes len=2 aka=ReservedBytes2 - structured list len=0..MAX16 wrapped tag=2 - AssignRevealedDataBlindSealTxid union - confidential rec tag=0 - seal bytes len=32 aka=SecretSeal - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - 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 bytes len=32 aka=SecretSeal - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - 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 - AssignRevealedAttachBlindSealTxid union - confidential rec tag=0 - seal bytes len=32 aka=SecretSeal - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxid - txid bytes len=32 aka=Txid - 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 bytes len=32 aka=SecretSeal - 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 rec BlindSealTxid - txid bytes len=32 aka=Txid - 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 - redeemed map len=0..MAX8 aka=Redeemed - key is U16 aka=ValencyType - value bytes len=32 aka=OpId - valencies set len=0..MAX8 aka=Valencies - element is U16 aka=ValencyType - validator bytes len=1 aka=ReservedBytes1 - witness bytes len=2 aka=ReservedBytes2 - bundles set len=0..MAX32 - WitnessBundle rec - pubWitness union PubWitness - txid bytes len=32 wrapped aka=Txid tag=0 - tx rec Tx wrapped tag=1 - version is I32 aka=TxVer - inputs list len=0..MAX32 - TxIn rec - prevOutput rec Outpoint - txid bytes len=32 aka=Txid - vout is U32 aka=Vout - sigScript bytes len=0..MAX32 aka=SigScript aka=ScriptBytes - sequence is U32 aka=SeqNo - witness list len=0..MAX32 aka=Witness - element bytes len=0..MAX32 aka=ByteStr - outputs list len=0..MAX32 - TxOut rec - value is U64 aka=Sats - scriptPubkey bytes len=0..MAX32 aka=ScriptPubkey aka=ScriptBytes - lockTime is U32 aka=LockTime - anchoredBundle union AnchoredBundle - tapret rec ClientBundleTapretProof wrapped tag=0 - mpcProof rec MerkleProof - pos is U32 - cofactor is U16 - path list len=0..32 - element bytes len=32 aka=MerkleHash - dbcProof rec TapretProof - pathProof rec TapretPathProof - some union TapretNodePartner option wrapped tag=1 - rightBranch rec TapretRightBranch wrapped tag=2 - nonce is U8 - bundle rec TransitionBundle - 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 bytes len=32 aka=SecretSeal - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxPtr - 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 bytes len=32 aka=SecretSeal - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal rec BlindSealTxPtr - 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 bytes len=32 aka=SecretSeal - state rec ConcealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - concealedDummy is Unit - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxPtr - 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 - value union FungibleState - bits64 is U64 wrapped tag=0 - concealedDummy is Unit - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal bytes len=32 aka=SecretSeal - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal rec BlindSealTxPtr - 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 - lock bytes len=2 aka=ReservedBytes2 - structured list len=0..MAX16 wrapped tag=2 - AssignRevealedDataBlindSealTxPtr union - confidential rec tag=0 - seal bytes len=32 aka=SecretSeal - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxPtr - 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 bytes len=32 aka=SecretSeal - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal rec BlindSealTxPtr - 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 bytes len=32 aka=SecretSeal - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxPtr - 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 bytes len=32 aka=SecretSeal - 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 rec BlindSealTxPtr - 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 - opret rec ClientBundleOpretProof wrapped tag=1 - mpcProof rec MerkleProof - pos is U32 - cofactor is U16 - path list len=0..32 - element bytes len=32 aka=MerkleHash - dbcProof is Unit aka=OpretProof - bundle rec TransitionBundle - 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 bytes len=32 aka=SecretSeal - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxPtr - 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 bytes len=32 aka=SecretSeal - state is Unit aka=VoidState - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal rec BlindSealTxPtr - 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 bytes len=32 aka=SecretSeal - state rec ConcealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - concealedDummy is Unit - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxPtr - 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 - value union FungibleState - bits64 is U64 wrapped tag=0 - concealedDummy is Unit - lock bytes len=2 aka=ReservedBytes2 - confidentialSeal rec tag=2 - seal bytes len=32 aka=SecretSeal - state rec RevealedFungible - value union FungibleState - bits64 is U64 wrapped tag=0 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal rec BlindSealTxPtr - 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 - lock bytes len=2 aka=ReservedBytes2 - structured list len=0..MAX16 wrapped tag=2 - AssignRevealedDataBlindSealTxPtr union - confidential rec tag=0 - seal bytes len=32 aka=SecretSeal - state bytes len=32 aka=ConcealedData - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxPtr - 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 bytes len=32 aka=SecretSeal - state rec RevealedData - value bytes len=0..MAX16 aka=DataState - salt is U128 - lock bytes len=2 aka=ReservedBytes2 - revealed rec tag=3 - seal rec BlindSealTxPtr - 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 bytes len=32 aka=SecretSeal - state bytes len=32 aka=ConcealedAttach - lock bytes len=2 aka=ReservedBytes2 - confidentialState rec tag=1 - seal rec BlindSealTxPtr - 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 bytes len=32 aka=SecretSeal - 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 rec BlindSealTxPtr - 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 - schema rec Schema - 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 - ifaces map len=0..MAX8 - key rec Iface - version enum VerNo v0=0 v1=1 - name ascii aka=TypeName first=AlphaCapsLodash rest=AlphaNumLodash len=1..100 - inherits list len=0..MAX8 - element bytes len=32 aka=IfaceId - timestamp is I64 - metadata map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value bytes len=32 aka=SemId - globalState map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec GlobalIface - some bytes len=32 option wrapped aka=SemId tag=1 - required enum Bool false=0 true=1 - multiple enum Bool false=0 true=1 - assignments map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec AssignIface - ownedState union OwnedIface - any is Unit tag=0 - rights is Unit tag=1 - amount is Unit tag=2 - anyData is Unit tag=3 - anyAttach is Unit tag=4 - data bytes len=32 wrapped aka=SemId tag=5 - public enum Bool false=0 true=1 - required enum Bool false=0 true=1 - multiple enum Bool false=0 true=1 - valencies map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec ValencyIface - required enum Bool false=0 true=1 - genesis rec GenesisIface - modifier enum Modifier abstract=0 override=1 final=255 - metadata set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - globals map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - assignments map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - errors set len=0..MAX8 - element ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - transitions map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec TransitionIface - modifier enum Modifier abstract=0 override=1 final=255 - optional enum Bool false=0 true=1 - metadata set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - globals map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - inputs map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - assignments map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - valencies set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - errors set len=0..MAX8 - element ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - some ascii option wrapped aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 tag=1 - extensions map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec ExtensionIface - modifier enum Modifier abstract=0 override=1 final=255 - optional enum Bool false=0 true=1 - metadata set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - globals map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - assignments map len=0..MAX8 - key ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value rec Occurrences - min is U16 - max is U16 - redeems set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - valencies set len=0..MAX8 - element ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - errors set len=0..MAX8 - element ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - some ascii option wrapped aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 tag=1 - some ascii option wrapped aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 tag=1 - errors map len=0..MAX8 - key ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - value str len=0..MAX8 - developer ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 - value rec IfaceImpl - version enum VerNo v0=0 v1=1 - schemaId bytes len=32 aka=SchemaId - ifaceId bytes len=32 aka=IfaceId - timestamp is I64 - metadata set len=0..MAX8 - NamedFieldMetaType rec - id is U16 aka=MetaType - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - globalState set len=0..MAX8 - NamedFieldGlobalStateType rec - id is U16 aka=GlobalStateType - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - assignments set len=0..MAX8 - NamedFieldAssignmentType rec - id is U16 aka=AssignmentType - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - valencies set len=0..MAX8 - NamedFieldValencyType rec - id is U16 aka=ValencyType - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - transitions set len=0..MAX8 - NamedFieldTransitionType rec - id is U16 aka=TransitionType - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - extensions set len=0..MAX8 - NamedFieldExtensionType rec - id is U16 aka=ExtensionType - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - errors set len=0..MAX8 - NamedVariantu8 rec - id is U8 - name ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - reserved bytes len=4 aka=ReservedBytes4 - developer ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 - supplements set len=0..MAX8 - Supplement rec - contentId union ContentRef - schema bytes len=32 wrapped aka=SchemaId tag=0 - genesis bytes len=32 wrapped aka=ContractId tag=1 - iface bytes len=32 wrapped aka=IfaceId tag=2 - ifaceImpl bytes len=32 wrapped aka=ImplId tag=3 - timestamp is I64 - creator ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 - annotations map len=0..MAX8 - key enum { - SupplSub itself=0 meta=1 global=2 owned=3 valency=4 assignment=5 genesis=6 transition=7 - extension=8 exception=9 - } - value map len=0..MAX8 aka=SupplMap - key union SupplItem - default is Unit tag=0 - typeNo is U16 wrapped tag=1 - typeName ascii wrapped aka=TypeName first=AlphaCapsLodash rest=AlphaNumLodash len=1..100 tag=2 - fieldName ascii wrapped aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 tag=3 - variantName ascii wrapped aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 tag=4 - value map len=0..MAX8 aka=Annotations - key ascii aka=AnnotationName first=AlphaCaps rest=AlphaNumDash len=1..MAX8 - value bytes len=0..MAX16 - types map len=0..MAX24 aka=TypeSystem - key bytes len=32 aka=SemId - value union TySemId - primitive is U8 wrapped aka=Primitive tag=0 - unicode is Unit tag=1 - enum set len=1..MAX8 wrapped aka=EnumVariants tag=2 - Variant rec - name ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - tag is U8 - union map len=0..MAX8 wrapped aka=UnionVariantsSemId tag=3 - key is U8 - value rec VariantInfoSemId - name ascii aka=VariantName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - ty bytes len=32 aka=SemId - tuple list len=1..MAX8 wrapped aka=UnnamedFieldsSemId tag=4 - element bytes len=32 aka=SemId - struct list len=1..MAX8 wrapped aka=NamedFieldsSemId tag=5 - FieldSemId rec - name ascii aka=FieldName first=AlphaSmallLodash rest=AlphaNumLodash len=1..100 - ty bytes len=32 aka=SemId - array tuple tag=6 - _ bytes len=32 aka=SemId - _ is U16 - list tuple tag=7 - _ bytes len=32 aka=SemId - Sizing rec - min is U64 - max is U64 - set tuple tag=8 - _ bytes len=32 aka=SemId - Sizing rec - min is U64 - max is U64 - map tuple tag=9 - _ bytes len=32 aka=SemId - _ bytes len=32 aka=SemId - Sizing rec - min is U64 - max is U64 - scripts set len=0..1024 - Lib rec - isae set len=0..64 aka=IsaSeg - element ascii aka=IsaName first=AlphaCaps rest=AlphaCapsNum len=2..8 - code bytes len=0..MAX16 - data bytes len=0..MAX16 - libs set len=0..MAX8 aka=LibSeg - element bytes len=32 aka=LibId - attachments map len=0..MAX16 - key bytes len=32 aka=AttachId - value bytes len=0..MAX24 - signatures map len=0..MAX8 - key union ContentId - schema bytes len=32 wrapped aka=SchemaId tag=0 - genesis bytes len=32 wrapped aka=ContractId tag=1 - iface bytes len=32 wrapped aka=IfaceId tag=2 - ifaceImpl bytes len=32 wrapped aka=ImplId tag=3 - suppl bytes len=32 wrapped aka=SupplId tag=4 - value map len=1..10 aka=ContentSigs - key ascii aka=Identity first=AsciiPrintable rest=AsciiPrintable len=1..4096 - value bytes len=1..4096 aka=SigBlob +rec Consignmenttrue + enum version, ContainerVer, v0 0 + enum transfer, Bool, false 0, true 1 + map terminals, len 0..MAX16 + bytes key, len 32, aka BundleId + bytes value, len 32, aka SecretSeal + rec genesis, Genesis + is ffv, U16, aka Ffv + bytes schemaId, len 32, aka SchemaId + is timestamp, I64 + ascii issuer, aka Identity, first AsciiPrintable, rest AsciiPrintable, len 1..4096 + enum chainNet, ChainNet, bitcoinMainnet 0, bitcoinTestnet3 1, bitcoinTestnet4 2, bitcoinSignet 3, bitcoinRegtest 4, liquidMainnet 5, liquidTestnet 6 + enum sealClosingStrategy, SealClosingStrategy, firstOpretOrTapret 0 + map metadata, len 0..MAX8, aka Metadata + is key, U16, aka MetaType + bytes value, len 0..MAX16, aka MetaValue + map globals, len 0..MAX8, aka GlobalState + is key, U16, aka GlobalStateType + list value, len 1..MAX16, aka GlobalValues + bytes element, len 0..MAX16, aka RevealedData + map assignments, len 0..MAX16, aka AssignmentsBlindSealTxid + is key, U16, aka AssignmentType + union value, TypedAssignsBlindSealTxid + list declarative, len 1..MAX16, wrapped, aka AssignVecAssignVoidStateBlindSealTxid, tag 0 + union AssignVoidStateBlindSealTxid + rec revealed, tag 0 + rec seal, BlindSealTxid + bytes txid, len 32, aka Txid + is vout, U32, aka Vout + is blinding, U64 + is state, Unit, aka VoidState + rec confidentialSeal, tag 1 + bytes seal, len 32, aka SecretSeal + is state, Unit, aka VoidState + list fungible, len 1..MAX16, wrapped, aka AssignVecAssignRevealedValueBlindSealTxid, tag 1 + union AssignRevealedValueBlindSealTxid + rec revealed, tag 0 + rec seal, BlindSealTxid + bytes txid, len 32, aka Txid + is vout, U32, aka Vout + is blinding, U64 + union state, FungibleState, aka RevealedValue + is bits64, U64, wrapped, tag 0 + rec confidentialSeal, tag 1 + bytes seal, len 32, aka SecretSeal + union state, FungibleState, aka RevealedValue + is bits64, U64, wrapped, tag 0 + list structured, len 1..MAX16, wrapped, aka AssignVecAssignRevealedDataBlindSealTxid, tag 2 + union AssignRevealedDataBlindSealTxid + rec revealed, tag 0 + rec seal, BlindSealTxid + bytes txid, len 32, aka Txid + is vout, U32, aka Vout + is blinding, U64 + bytes state, len 0..MAX16, aka RevealedData + rec confidentialSeal, tag 1 + bytes seal, len 32, aka SecretSeal + bytes state, len 0..MAX16, aka RevealedData + set bundles, len 0..MAX32 + rec WitnessBundle + union pubWitness, PubWitness + bytes txid, len 32, wrapped, aka Txid, tag 0 + rec tx, Tx, wrapped, tag 1 + is version, I32, aka TxVer + list inputs, len 0..MAX32 + rec TxIn + rec prevOutput, Outpoint + bytes txid, len 32, aka Txid + is vout, U32, aka Vout + bytes sigScript, len 0..MAX32, aka SigScript, aka ScriptBytes + is sequence, U32, aka SeqNo + list witness, len 0..MAX32, aka Witness + bytes element, len 0..MAX32, aka ByteStr + list outputs, len 0..MAX32 + rec TxOut + is value, U64, aka Sats + bytes scriptPubkey, len 0..MAX32, aka ScriptPubkey, aka ScriptBytes + is lockTime, U32, aka LockTime + rec bundle, TransitionBundle + map inputMap, len 1..MAX16 + is key, U32, aka Vout + set value, len 1..MAX16, aka InputOpids + bytes element, len 32, aka OpId + map knownTransitions, len 1..MAX16 + bytes key, len 32, aka OpId + rec value, Transition + is ffv, U16, aka Ffv + bytes contractId, len 32, aka ContractId + is nonce, U64 + is transitionType, U16, aka TransitionType + map metadata, len 0..MAX8, aka Metadata + is key, U16, aka MetaType + bytes value, len 0..MAX16, aka MetaValue + map globals, len 0..MAX8, aka GlobalState + is key, U16, aka GlobalStateType + list value, len 1..MAX16, aka GlobalValues + bytes element, len 0..MAX16, aka RevealedData + set inputs, len 1..MAX16, aka Inputs + rec Opout + bytes op, len 32, aka OpId + is ty, U16, aka AssignmentType + is no, U16 + map assignments, len 0..MAX16, aka AssignmentsBlindSealTxPtr + is key, U16, aka AssignmentType + union value, TypedAssignsBlindSealTxPtr + list declarative, len 1..MAX16, wrapped, aka AssignVecAssignVoidStateBlindSealTxPtr, tag 0 + union AssignVoidStateBlindSealTxPtr + rec revealed, tag 0 + rec seal, BlindSealTxPtr + union txid, TxPtr + is witnessTx, Unit, tag 0 + bytes txid, len 32, wrapped, aka Txid, tag 1 + is vout, U32, aka Vout + is blinding, U64 + is state, Unit, aka VoidState + rec confidentialSeal, tag 1 + bytes seal, len 32, aka SecretSeal + is state, Unit, aka VoidState + list fungible, len 1..MAX16, wrapped, aka AssignVecAssignRevealedValueBlindSealTxPtr, tag 1 + union AssignRevealedValueBlindSealTxPtr + rec revealed, tag 0 + rec seal, BlindSealTxPtr + union txid, TxPtr + is witnessTx, Unit, tag 0 + bytes txid, len 32, wrapped, aka Txid, tag 1 + is vout, U32, aka Vout + is blinding, U64 + union state, FungibleState, aka RevealedValue + is bits64, U64, wrapped, tag 0 + rec confidentialSeal, tag 1 + bytes seal, len 32, aka SecretSeal + union state, FungibleState, aka RevealedValue + is bits64, U64, wrapped, tag 0 + list structured, len 1..MAX16, wrapped, aka AssignVecAssignRevealedDataBlindSealTxPtr, tag 2 + union AssignRevealedDataBlindSealTxPtr + rec revealed, tag 0 + rec seal, BlindSealTxPtr + union txid, TxPtr + is witnessTx, Unit, tag 0 + bytes txid, len 32, wrapped, aka Txid, tag 1 + is vout, U32, aka Vout + is blinding, U64 + bytes state, len 0..MAX16, aka RevealedData + rec confidentialSeal, tag 1 + bytes seal, len 32, aka SecretSeal + bytes state, len 0..MAX16, aka RevealedData + bytes some, len 64, option, wrapped, aka Signature, tag 1 + rec schema, Schema + is ffv, U16, aka Ffv + ascii name, aka TypeName, first AlphaCapsLodash, rest AlphaNumLodash, len 1..100 + map metaTypes, len 0..MAX8 + is key, U16, aka MetaType + rec value, MetaDetails + bytes semId, len 32, aka SemId + ascii name, aka FieldName, first AlphaSmallLodash, rest AlphaNumLodash, len 1..100 + map globalTypes, len 0..MAX8 + is key, U16, aka GlobalStateType + rec value, GlobalDetails + rec globalStateSchema, GlobalStateSchema + bytes semId, len 32, aka SemId + is maxItems, U24 + ascii name, aka FieldName, first AlphaSmallLodash, rest AlphaNumLodash, len 1..100 + map ownedTypes, len 0..MAX8 + is key, U16, aka AssignmentType + rec value, AssignmentDetails + union ownedStateSchema, OwnedStateSchema + is declarative, Unit, tag 0 + enum fungible, FungibleType, wrapped, unsigned64Bit 8, tag 1 + bytes structured, len 32, wrapped, aka SemId, tag 2 + ascii name, aka FieldName, first AlphaSmallLodash, rest AlphaNumLodash, len 1..100 + is defaultTransition, U16, aka TransitionType + rec genesis, GenesisSchema + set metadata, len 0..MAX8 + is element, U16, aka MetaType + map globals, len 0..MAX8 + is key, U16, aka GlobalStateType + rec value, Occurrences + is min, U16 + is max, U16 + map assignments, len 0..MAX8 + is key, U16, aka AssignmentType + rec value, Occurrences + is min, U16 + is max, U16 + rec some, LibSite, option, wrapped, tag 1 + bytes lib, len 32, aka LibId + is pos, U16 + map transitions, len 0..MAX8 + is key, U16, aka TransitionType + rec value, TransitionDetails + rec transitionSchema, TransitionSchema + set metadata, len 0..MAX8 + is element, U16, aka MetaType + map globals, len 0..MAX8 + is key, U16, aka GlobalStateType + rec value, Occurrences + is min, U16 + is max, U16 + map inputs, len 0..MAX8 + is key, U16, aka AssignmentType + rec value, Occurrences + is min, U16 + is max, U16 + map assignments, len 0..MAX8 + is key, U16, aka AssignmentType + rec value, Occurrences + is min, U16 + is max, U16 + rec some, LibSite, option, wrapped, tag 1 + bytes lib, len 32, aka LibId + is pos, U16 + ascii name, aka FieldName, first AlphaSmallLodash, rest AlphaNumLodash, len 1..100 + is some, U16, option, wrapped, aka AssignmentType, tag 1 + map types, len 0..MAX24, aka TypeSystem + bytes key, len 32, aka SemId + union value, TySemId + is primitive, U8, wrapped, aka Primitive, tag 0 + is unicode, Unit, tag 1 + set enum, len 1..MAX8, wrapped, aka EnumVariants, tag 2 + rec Variant + ascii name, aka VariantName, first AlphaSmallLodash, rest AlphaNumLodash, len 1..100 + is tag, U8 + map union, len 0..MAX8, wrapped, aka UnionVariantsSemId, tag 3 + is key, U8 + rec value, VariantInfoSemId + ascii name, aka VariantName, first AlphaSmallLodash, rest AlphaNumLodash, len 1..100 + bytes ty, len 32, aka SemId + list tuple, len 1..MAX8, wrapped, aka UnnamedFieldsSemId, tag 4 + bytes element, len 32, aka SemId + list struct, len 1..MAX8, wrapped, aka NamedFieldsSemId, tag 5 + rec FieldSemId + ascii name, aka FieldName, first AlphaSmallLodash, rest AlphaNumLodash, len 1..100 + bytes ty, len 32, aka SemId + tuple array, tag 6 + bytes _, len 32, aka SemId + is _, U16 + tuple list, tag 7 + bytes _, len 32, aka SemId + rec Sizing + is min, U64 + is max, U64 + tuple set, tag 8 + bytes _, len 32, aka SemId + rec Sizing + is min, U64 + is max, U64 + tuple map, tag 9 + bytes _, len 32, aka SemId + bytes _, len 32, aka SemId + rec Sizing + is min, U64 + is max, U64 + set scripts, len 0..1024 + rec Lib + set isae, len 0..64, aka IsaSeg + ascii element, aka IsaName, first AlphaCaps, rest AlphaCapsNum, len 2..8 + bytes code, len 0..MAX16 + bytes data, len 0..MAX16 + set libs, len 0..MAX8, aka LibSeg + bytes element, len 32, aka LibId diff --git a/stl/src/main.rs b/stl/src/main.rs index 3cf24119..c8576d2f 100644 --- a/stl/src/main.rs +++ b/stl/src/main.rs @@ -26,8 +26,8 @@ use std::io::Write; use commit_verify::CommitmentLayout; use rgbstd::containers::Transfer; use rgbstd::stl::{ - aluvm_stl, bp_core_stl, bp_tx_stl, commit_verify_stl, rgb_commit_stl, rgb_contract_stl, - rgb_logic_stl, rgb_std_stl, rgb_storage_stl, + aluvm_stl, bp_consensus_stl, bp_core_stl, bp_tx_stl, commit_verify_stl, rgb_commit_stl, + rgb_contract_stl, rgb_logic_stl, rgb_std_stl, rgb_storage_stl, }; use strict_types::stl::{std_stl, strict_types_stl}; use strict_types::{parse_args, StlFormat, SystemBuilder}; @@ -50,7 +50,7 @@ fn main() { "0.11.0", Some( " - Description: Types for writing RGB contracts and interfaces + Description: Types for writing RGB schemata Author: Dr Maxim Orlovsky Copyright (C) 2023-2024 LNP/BP Standards Association. All rights reserved. License: Apache-2.0", @@ -107,6 +107,7 @@ fn main() { let rgb_commit = rgb_commit_stl(); let rgb_logic = rgb_logic_stl(); let tx = bp_tx_stl(); + let consensus = bp_consensus_stl(); let bp = bp_core_stl(); let cv = commit_verify_stl(); let st = strict_types_stl(); @@ -121,6 +122,8 @@ fn main() { .unwrap() .import(vm) .unwrap() + .import(consensus) + .unwrap() .import(bp) .unwrap() .import(tx)