diff --git a/.cargo/config-release.toml b/.cargo/config-release.toml index faab5e6c572..7229efc68bd 100644 --- a/.cargo/config-release.toml +++ b/.cargo/config-release.toml @@ -9,3 +9,6 @@ rustflags = ["-C", "target-feature=-crt-static"] [target.aarch64-unknown-linux-gnu] linker = "aarch64-linux-gnu-gcc" + +[target.wasm32-unknown-unknown] +rustflags = ['--cfg', 'getrandom_backend="wasm_js"'] diff --git a/.cargo/config.toml b/.cargo/config.toml index 18bc8e4064b..2ef8c318fc4 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -9,5 +9,8 @@ rustflags = ["-C", "target-feature=-crt-static", "--cfg", "tokio_unstable"] [target.aarch64-unknown-linux-gnu] linker = "aarch64-linux-gnu-gcc" +[target.wasm32-unknown-unknown] +rustflags = ['--cfg', 'getrandom_backend="wasm_js"'] + [build] rustflags = ["--cfg", "tokio_unstable"] diff --git a/Cargo.lock b/Cargo.lock index 597cdf552d5..73de44ee340 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -213,7 +213,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -224,7 +224,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -304,17 +304,16 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] name = "backon" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4fa97bb310c33c811334143cf64c5bb2b7b3c06e453db6b095d7061eff8f113" +checksum = "ba5289ec98f68f28dd809fd601059e6aa908bb8f6108620930828283d4ee23d7" dependencies = [ "fastrand", - "gloo-timers", "tokio", ] @@ -407,7 +406,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.75", + "syn 2.0.94", "which", ] @@ -428,7 +427,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -438,7 +437,7 @@ source = "git+https://github.com/dashpay/rs-bip37-bloom-filter?branch=develop#35 dependencies = [ "bitvec", "murmur3", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -560,7 +559,7 @@ dependencies = [ "sha2", "sha3", "subtle", - "thiserror", + "thiserror 1.0.64", "uint-zigzag", "vsss-rs", "zeroize", @@ -616,7 +615,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", "syn_derive", ] @@ -862,7 +861,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -1125,7 +1124,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -1134,6 +1133,7 @@ version = "1.8.0-dev.2" dependencies = [ "dapi-grpc-macros", "futures-core", + "getrandom", "platform-version", "prost", "serde", @@ -1151,7 +1151,7 @@ dependencies = [ "dapi-grpc", "heck 0.5.0", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -1175,7 +1175,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -1186,7 +1186,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -1222,7 +1222,7 @@ dependencies = [ "serde", "serde_json", "test-case", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-test", "tokio-util", @@ -1304,7 +1304,7 @@ dependencies = [ "platform-value", "platform-version", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -1318,7 +1318,7 @@ dependencies = [ "platform-value", "platform-version", "serde_json", - "thiserror", + "thiserror 1.0.64", "wallet-utils-contract", "withdrawals-contract", ] @@ -1331,7 +1331,7 @@ checksum = "5060bb0febb73fa907273f8a7ed17ab4bf831d585eac835b28ec24a1e2460956" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -1362,7 +1362,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -1375,7 +1375,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -1395,7 +1395,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", "unicode-xid", ] @@ -1424,7 +1424,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -1446,7 +1446,7 @@ dependencies = [ "platform-value", "platform-version", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -1466,7 +1466,7 @@ dependencies = [ "data-contracts", "derive_more 1.0.0", "dpp", - "env_logger 0.11.5", + "env_logger 0.11.6", "getrandom", "hex", "indexmap 2.7.0", @@ -1495,7 +1495,7 @@ dependencies = [ "sha2", "strum", "test-case", - "thiserror", + "thiserror 1.0.64", "tokio", ] @@ -1536,7 +1536,7 @@ dependencies = [ "serde_json", "sqlparser", "tempfile", - "thiserror", + "thiserror 1.0.64", "tracing", ] @@ -1587,7 +1587,7 @@ dependencies = [ "strategy-tests", "tempfile", "tenderdash-abci", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-util", "tracing", @@ -1611,7 +1611,7 @@ dependencies = [ "serde", "serde_json", "tenderdash-abci", - "thiserror", + "thiserror 1.0.64", "tracing", ] @@ -1622,7 +1622,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9c8d6ea916fadcd87e3d1ff4802b696d717c83519b47e76f267ab77e536dd5a" dependencies = [ "ed-derive", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -1728,14 +1728,14 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -1756,9 +1756,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" dependencies = [ "anstream", "anstyle", @@ -1842,8 +1842,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" dependencies = [ "bit-set", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -1859,7 +1859,7 @@ dependencies = [ "platform-value", "platform-version", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -2034,7 +2034,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -2166,7 +2166,7 @@ dependencies = [ "reqwest", "sha2", "tempfile", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-util", "tower-http", @@ -2181,7 +2181,7 @@ checksum = "360f7c8d3b20beafcbf3cde8754bbcfd201ae2a30ec7594a4b9678fd2fa3c7a8" dependencies = [ "integer-encoding", "intmap", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -2194,7 +2194,7 @@ dependencies = [ "hex", "integer-encoding", "intmap", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -2219,7 +2219,7 @@ dependencies = [ "integer-encoding", "num_cpus", "rand", - "thiserror", + "thiserror 1.0.64", "time", ] @@ -2246,7 +2246,7 @@ dependencies = [ "rocksdb", "strum", "tempfile", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -2255,7 +2255,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4be0c1a1ef97068fe93212e7b6f349e0b44a9fc90063c8c28e110cfb8c2fcb2" dependencies = [ - "thiserror", + "thiserror 1.0.64", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2789,7 +2789,7 @@ checksum = "ec9ad60d674508f3ca8f380a928cfe7b096bc729c4e2dbfe3852bc45da3ab30b" dependencies = [ "serde", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -2801,7 +2801,7 @@ dependencies = [ "json-schema-compatibility-validator", "once_cell", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -2972,7 +2972,7 @@ dependencies = [ "platform-value", "platform-version", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -3033,7 +3033,7 @@ dependencies = [ "metrics", "metrics-util", "quanta", - "thiserror", + "thiserror 1.0.64", "tokio", "tracing", ] @@ -3127,7 +3127,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -3149,7 +3149,7 @@ dependencies = [ "rustc_version", "smallvec", "tagptr", - "thiserror", + "thiserror 1.0.64", "triomphe", "uuid", ] @@ -3279,7 +3279,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -3372,7 +3372,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -3419,7 +3419,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -3552,7 +3552,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -3597,7 +3597,7 @@ version = "1.8.0-dev.2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", "virtue 0.0.17", ] @@ -3611,14 +3611,12 @@ dependencies = [ "ciborium 0.2.0", "hex", "indexmap 2.7.0", - "lazy_static", "platform-serialization", "platform-version", "rand", - "regex", "serde", "serde_json", - "thiserror", + "thiserror 1.0.64", "treediff", ] @@ -3627,7 +3625,7 @@ name = "platform-value-convertible" version = "1.8.0-dev.2" dependencies = [ "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -3637,7 +3635,7 @@ dependencies = [ "bincode", "grovedb-version", "once_cell", - "thiserror", + "thiserror 1.0.64", "versioned-feature-core 1.0.0 (git+https://github.com/dashpay/versioned-feature-core)", ] @@ -3647,7 +3645,7 @@ version = "1.8.0-dev.2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -3742,7 +3740,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -3789,9 +3787,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -3823,7 +3821,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.75", + "syn 2.0.94", "tempfile", ] @@ -3837,7 +3835,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -3978,14 +3976,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -3999,13 +3997,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -4016,9 +4014,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rend" @@ -4144,16 +4142,21 @@ dependencies = [ "chrono", "dapi-grpc", "futures", + "getrandom", + "gloo-timers", "hex", + "http", "http-serde", "lru", "rand", "serde", "serde_json", "sha2", - "thiserror", + "thiserror 1.0.64", "tokio", + "tonic-web-wasm-client", "tracing", + "wasm-bindgen-futures", ] [[package]] @@ -4294,11 +4297,10 @@ dependencies = [ [[package]] name = "sanitize-filename" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603" +checksum = "bc984f4f9ceb736a7bb755c3e3bd17dc56370af2600c9780dcc48c66453da34d" dependencies = [ - "lazy_static", "regex", ] @@ -4432,7 +4434,7 @@ checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -4466,7 +4468,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -4533,7 +4535,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -4545,7 +4547,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -4764,7 +4766,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -4795,9 +4797,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.75" +version = "2.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +checksum = "987bc0be1cdea8b10216bd06e2ca407d40b9543468fafd3ddfb02f36e77f71f3" dependencies = [ "proc-macro2", "quote", @@ -4813,7 +4815,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -4892,16 +4894,15 @@ dependencies = [ [[package]] name = "tenderdash-abci" version = "1.2.1+1.3.0" -source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1%2B1.3.0#aad72f4d25816bdf0f584ee4ba3cd383addf8a33" +source = "git+https://github.com/dashpay/rs-tenderdash-abci?rev=a558c0a2deab149183f125a012b14b709150401c#a558c0a2deab149183f125a012b14b709150401c" dependencies = [ "bytes", "futures", "hex", "lhash", "semver", - "serde_json", "tenderdash-proto", - "thiserror", + "thiserror 2.0.9", "tokio", "tokio-util", "tracing", @@ -4913,7 +4914,7 @@ dependencies = [ [[package]] name = "tenderdash-proto" version = "1.2.1+1.3.0" -source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1%2B1.3.0#aad72f4d25816bdf0f584ee4ba3cd383addf8a33" +source = "git+https://github.com/dashpay/rs-tenderdash-abci?rev=a558c0a2deab149183f125a012b14b709150401c#a558c0a2deab149183f125a012b14b709150401c" dependencies = [ "bytes", "chrono", @@ -4932,7 +4933,7 @@ dependencies = [ [[package]] name = "tenderdash-proto-compiler" version = "1.2.1+1.3.0" -source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1%2B1.3.0#aad72f4d25816bdf0f584ee4ba3cd383addf8a33" +source = "git+https://github.com/dashpay/rs-tenderdash-abci?rev=a558c0a2deab149183f125a012b14b709150401c#a558c0a2deab149183f125a012b14b709150401c" dependencies = [ "fs_extra", "prost-build", @@ -4977,7 +4978,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -4988,7 +4989,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", "test-case-core", ] @@ -4998,7 +4999,16 @@ version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.64", +] + +[[package]] +name = "thiserror" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +dependencies = [ + "thiserror-impl 2.0.9", ] [[package]] @@ -5009,7 +5019,18 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", ] [[package]] @@ -5134,7 +5155,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -5296,7 +5317,32 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn 2.0.75", + "syn 2.0.94", +] + +[[package]] +name = "tonic-web-wasm-client" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5ca6e7bdd0042c440d36b6df97c1436f1d45871ce18298091f114004b1beb4" +dependencies = [ + "base64 0.22.1", + "byteorder", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "httparse", + "js-sys", + "pin-project", + "thiserror 1.0.64", + "tonic", + "tower-service", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", ] [[package]] @@ -5373,7 +5419,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -5627,7 +5673,7 @@ dependencies = [ "platform-value", "platform-version", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -5666,7 +5712,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", "wasm-bindgen-shared", ] @@ -5701,7 +5747,7 @@ checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5729,7 +5775,7 @@ dependencies = [ "serde", "serde-wasm-bindgen", "serde_json", - "thiserror", + "thiserror 1.0.64", "wasm-bindgen", "wasm-bindgen-futures", "wasm-logger", @@ -5747,6 +5793,19 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-streams" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.76" @@ -6024,7 +6083,7 @@ dependencies = [ "serde", "serde_json", "serde_repr", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -6071,7 +6130,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -6098,7 +6157,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.94", ] [[package]] @@ -6134,7 +6193,7 @@ dependencies = [ "flate2", "indexmap 2.7.0", "memchr", - "thiserror", + "thiserror 1.0.64", "zopfli", ] diff --git a/Cargo.toml b/Cargo.toml index 02295b6b475..d005160f041 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ members = [ "packages/rs-json-schema-compatibility-validator", "packages/check-features", "packages/wallet-utils-contract", + # "packages/wasm-sdk", # This one is experimental and not ready for use ] [workspace.package] diff --git a/packages/dapi-grpc/Cargo.toml b/packages/dapi-grpc/Cargo.toml index 60b818489e1..97d7cbd2219 100644 --- a/packages/dapi-grpc/Cargo.toml +++ b/packages/dapi-grpc/Cargo.toml @@ -20,19 +20,19 @@ platform = [] # Re-export Dash Platform protobuf types as `dapi_grpc::platform::proto` # Note: client needs tls and tls-roots to connect to testnet which uses TLS. tenderdash-proto = [] -client = [ - "tonic/channel", - "tonic/transport", - "tonic/tls", - "tonic/tls-roots", - "tonic/tls-webpki-roots", - "platform", -] -server = ["tonic/channel", "tonic/transport", "platform"] -serde = ["dep:serde", "dep:serde_bytes"] + +# Client support. +client = ["platform"] + +# Build tonic server code. Includes all client features and adds server-specific dependencies. +server = ["platform", "tenderdash-proto/server", "client"] + +serde = ["dep:serde", "dep:serde_bytes", "tenderdash-proto/serde"] mocks = ["serde", "dep:serde_json"] [dependencies] +tenderdash-proto = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.2.1", rev = "a558c0a2deab149183f125a012b14b709150401c", default-features = false } + prost = { version = "0.13" } futures-core = "0.3.30" tonic = { version = "0.12.3", features = [ @@ -42,12 +42,23 @@ tonic = { version = "0.12.3", features = [ serde = { version = "1.0.197", optional = true, features = ["derive"] } serde_bytes = { version = "0.11.12", optional = true } serde_json = { version = "1.0", optional = true } -tenderdash-proto = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.2.1", tag = "v1.2.1+1.3.0", default-features = false, features = [ - "grpc", -] } dapi-grpc-macros = { path = "../rs-dapi-grpc-macros" } platform-version = { path = "../rs-platform-version" } +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { version = "0.2", features = ["js"] } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +tonic = { version = "0.12.3", features = [ + "codegen", + "prost", + "channel", + "transport", + "tls", + "tls-roots", + "tls-webpki-roots", +], default-features = false } + [build-dependencies] tonic-build = { version = "0.12.3" } diff --git a/packages/dapi-grpc/build.rs b/packages/dapi-grpc/build.rs index 642b614ab90..8e9f70cea6f 100644 --- a/packages/dapi-grpc/build.rs +++ b/packages/dapi-grpc/build.rs @@ -2,7 +2,6 @@ use std::{ collections::HashSet, fs::{create_dir_all, remove_dir_all}, path::PathBuf, - process::exit, }; use tonic_build::Builder; @@ -14,9 +13,19 @@ const SERDE_WITH_STRING: &str = r#"#[cfg_attr(feature = "serde", serde(with = "crate::deserialization::from_to_string"))]"#; fn main() { + #[cfg(feature = "server")] + generate_code(ImplType::Server); + #[cfg(feature = "client")] + generate_code(ImplType::Client); + #[cfg(target_arch = "wasm32")] + generate_code(ImplType::Wasm); +} + +fn generate_code(typ: ImplType) { let core = MappingConfig::new( PathBuf::from("protos/core/v0/core.proto"), PathBuf::from("src/core"), + &typ, ); configure_core(core) @@ -26,6 +35,7 @@ fn main() { let platform = MappingConfig::new( PathBuf::from("protos/platform/v0/platform.proto"), PathBuf::from("src/platform"), + &typ, ); configure_platform(platform) @@ -210,6 +220,43 @@ fn configure_core(core: MappingConfig) -> MappingConfig { core } +#[allow(unused)] +enum ImplType { + Server, + Client, + Wasm, +} + +impl ImplType { + // Configure the builder based on the implementation type. + pub fn configure(&self, builder: Builder) -> Builder { + match self { + Self::Server => builder + .build_client(true) + .build_server(true) + .build_transport(true), + Self::Client => builder + .build_client(true) + .build_server(false) + .build_transport(true), + Self::Wasm => builder + .build_client(true) + .build_server(false) + .build_transport(false), + } + } + + /// Get the directory name for the implementation type. + fn dirname(&self) -> String { + match self { + Self::Server => "server", + Self::Client => "client", + Self::Wasm => "wasm", + } + .to_string() + } +} + impl MappingConfig { /// Create a new MappingConfig instance. /// @@ -220,31 +267,18 @@ impl MappingConfig { /// /// Depending on the features, either `client`, `server` or `client_server` subdirectory /// will be created inside `out_dir`. - fn new(protobuf_file: PathBuf, out_dir: PathBuf) -> Self { + fn new(protobuf_file: PathBuf, out_dir: PathBuf, typ: &ImplType) -> Self { let protobuf_file = abs_path(&protobuf_file); - let build_server = cfg!(feature = "server"); - let build_client = cfg!(feature = "client"); - // Depending on the features, we need to build the server, client or both. // We save these artifacts in separate directories to avoid overwriting the generated files // when another crate requires different features. - let out_dir_suffix = match (build_server, build_client) { - (true, true) => "client_server", - (true, false) => "server", - (false, true) => "client", - (false, false) => { - println!("WARNING: At least one of the features 'server' or 'client' must be enabled; dapi-grpc will not generate any files."); - exit(0) - } - }; + let out_dir_suffix = typ.dirname(); let out_dir = abs_path(&out_dir.join(out_dir_suffix)); - let builder = tonic_build::configure() - .build_server(build_server) - .build_client(build_client) - .build_transport(build_server || build_client) + let builder = typ + .configure(tonic_build::configure()) .out_dir(out_dir.clone()) .protoc_arg("--experimental_allow_proto3_optional"); diff --git a/packages/dapi-grpc/src/lib.rs b/packages/dapi-grpc/src/lib.rs index 486ba8f3fce..c4258a8ff33 100644 --- a/packages/dapi-grpc/src/lib.rs +++ b/packages/dapi-grpc/src/lib.rs @@ -4,36 +4,45 @@ pub use prost::Message; pub mod core { #![allow(non_camel_case_types)] pub mod v0 { - #[cfg(all(feature = "server", not(feature = "client")))] + // Note: only one of the features can be analyzed at a time + #[cfg(all(feature = "server", not(target_arch = "wasm32")))] include!("core/server/org.dash.platform.dapi.v0.rs"); - #[cfg(all(feature = "client", not(feature = "server")))] + #[cfg(all( + feature = "client", + not(feature = "server"), + not(target_arch = "wasm32") + ))] include!("core/client/org.dash.platform.dapi.v0.rs"); - #[cfg(all(feature = "server", feature = "client"))] - include!("core/client_server/org.dash.platform.dapi.v0.rs"); + #[cfg(target_arch = "wasm32")] + include!("core/wasm/org.dash.platform.dapi.v0.rs"); } } #[cfg(feature = "platform")] pub mod platform { pub mod v0 { - #[cfg(all(feature = "server", not(feature = "client")))] + #[cfg(all(feature = "server", not(target_arch = "wasm32")))] include!("platform/server/org.dash.platform.dapi.v0.rs"); - #[cfg(all(feature = "client", not(feature = "server")))] + #[cfg(all( + feature = "client", + not(feature = "server"), + not(target_arch = "wasm32") + ))] include!("platform/client/org.dash.platform.dapi.v0.rs"); - #[cfg(all(feature = "server", feature = "client"))] - include!("platform/client_server/org.dash.platform.dapi.v0.rs"); + #[cfg(target_arch = "wasm32")] + include!("platform/wasm/org.dash.platform.dapi.v0.rs"); } #[cfg(feature = "tenderdash-proto")] pub use tenderdash_proto as proto; - #[cfg(any(feature = "server", feature = "client"))] + #[cfg(any(feature = "server", feature = "client", target_arch = "wasm32"))] mod versioning; - #[cfg(any(feature = "server", feature = "client"))] + #[cfg(any(feature = "server", feature = "client", target_arch = "wasm32"))] pub use versioning::{VersionedGrpcMessage, VersionedGrpcResponse}; } diff --git a/packages/js-dapi-client/package.json b/packages/js-dapi-client/package.json index f6e303f37e3..d77c21509a9 100644 --- a/packages/js-dapi-client/package.json +++ b/packages/js-dapi-client/package.json @@ -82,7 +82,8 @@ "files": [ "docs", "lib", - "polyfills" + "polyfills", + "dist" ], "scripts": { "build:web": "webpack", diff --git a/packages/rs-dapi-client/Cargo.toml b/packages/rs-dapi-client/Cargo.toml index 0f741d4b754..7996dd12b92 100644 --- a/packages/rs-dapi-client/Cargo.toml +++ b/packages/rs-dapi-client/Cargo.toml @@ -4,7 +4,9 @@ version = "1.8.0-dev.2" edition = "2021" [features] +# TODO we should not enable deps features in default default = ["mocks", "offline-testing"] + mocks = [ "dep:sha2", "dep:hex", @@ -18,16 +20,34 @@ dump = ["mocks"] # skip tests that require connection to the platform; enabled by default offline-testing = [] +# non-wasm dependencies +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +backon = { version = "1.3", default-features = false, features = [ + "tokio-sleep", +] } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +gloo-timers = { version = "0.3.0", features = ["futures"] } +tonic-web-wasm-client = { version = "0.6.0" } +wasm-bindgen-futures = { version = "0.4.49" } +getrandom = { version = "0.2", features = ["js"] } + [dependencies] -backon = { version = "1.2", features = ["tokio-sleep"] } +backon = { version = "1.3", default-features = false } dapi-grpc = { path = "../dapi-grpc", features = [ "core", "platform", "client", ], default-features = false } -futures = "0.3.28" +futures = { version = "0.3.28" } +http = { version = "1.1.0", default-features = false } http-serde = { version = "2.1", optional = true } -rand = { version = "0.8.5", features = ["small_rng"] } + + +rand = { version = "0.8.5", features = [ + "small_rng", + "getrandom", +], default-features = false } thiserror = "1.0.64" tracing = "0.1.40" tokio = { version = "1.40", default-features = false } diff --git a/packages/rs-dapi-client/src/address_list.rs b/packages/rs-dapi-client/src/address_list.rs index 2f59b22c3bc..eeea7be8a22 100644 --- a/packages/rs-dapi-client/src/address_list.rs +++ b/packages/rs-dapi-client/src/address_list.rs @@ -1,7 +1,7 @@ //! Subsystem to manage DAPI nodes. +use crate::Uri; use chrono::Utc; -use dapi_grpc::tonic::transport::Uri; use rand::{rngs::SmallRng, seq::IteratorRandom, SeedableRng}; use std::collections::hash_map::Entry; use std::collections::HashMap; diff --git a/packages/rs-dapi-client/src/connection_pool.rs b/packages/rs-dapi-client/src/connection_pool.rs index 97dd991d509..99effb4ac76 100644 --- a/packages/rs-dapi-client/src/connection_pool.rs +++ b/packages/rs-dapi-client/src/connection_pool.rs @@ -3,12 +3,12 @@ use std::{ sync::{Arc, Mutex}, }; -use dapi_grpc::tonic::transport::Uri; use lru::LruCache; use crate::{ request_settings::AppliedRequestSettings, transport::{CoreGrpcClient, PlatformGrpcClient}, + Uri, }; /// ConnectionPool represents pool of connections to DAPI nodes. diff --git a/packages/rs-dapi-client/src/dapi_client.rs b/packages/rs-dapi-client/src/dapi_client.rs index 126d820e1ca..8986ac01d67 100644 --- a/packages/rs-dapi-client/src/dapi_client.rs +++ b/packages/rs-dapi-client/src/dapi_client.rs @@ -3,6 +3,7 @@ use backon::{ConstantBuilder, Retryable}; use dapi_grpc::mock::Mockable; use dapi_grpc::tonic::async_trait; +#[cfg(not(target_arch = "wasm32"))] use dapi_grpc::tonic::transport::Certificate; use std::fmt::{Debug, Display}; use std::sync::atomic::AtomicUsize; @@ -13,7 +14,7 @@ use tracing::Instrument; use crate::address_list::AddressListError; use crate::connection_pool::ConnectionPool; use crate::request_settings::AppliedRequestSettings; -use crate::transport::TransportError; +use crate::transport::{self, TransportError}; use crate::{ transport::{TransportClient, TransportRequest}, AddressList, CanRetry, DapiRequestExecutor, ExecutionError, ExecutionResponse, ExecutionResult, @@ -77,6 +78,7 @@ pub struct DapiClient { address_list: AddressList, settings: RequestSettings, pool: ConnectionPool, + #[cfg(not(target_arch = "wasm32"))] /// Certificate Authority certificate to use for verifying the server's certificate. pub ca_certificate: Option, #[cfg(feature = "dump")] @@ -95,6 +97,7 @@ impl DapiClient { pool: ConnectionPool::new(address_count), #[cfg(feature = "dump")] dump_dir: None, + #[cfg(not(target_arch = "wasm32"))] ca_certificate: None, } } @@ -107,6 +110,7 @@ impl DapiClient { /// /// # Returns /// [DapiClient] with CA certificate set. + #[cfg(not(target_arch = "wasm32"))] pub fn with_ca_certificate(mut self, ca_cert: Certificate) -> Self { self.ca_certificate = Some(ca_cert); @@ -200,8 +204,9 @@ impl DapiRequestExecutor for DapiClient { .settings .override_by(R::SETTINGS_OVERRIDES) .override_by(settings) - .finalize() - .with_ca_certificate(self.ca_certificate.clone()); + .finalize(); + #[cfg(not(target_arch = "wasm32"))] + let applied_settings = applied_settings.with_ca_certificate(self.ca_certificate.clone()); // Setup retry policy: let retry_settings = ConstantBuilder::default() @@ -310,10 +315,16 @@ impl DapiRequestExecutor for DapiClient { } }; + let sleeper = transport::BackonSleeper::default(); + // Start the routine with retry policy applied: // We allow let_and_return because `result` is used later if dump feature is enabled - let result = routine + let result: Result< + ExecutionResponse<::Response>, + ExecutionError, + > = routine .retry(retry_settings) + .sleep(sleeper) .notify(|error, duration| { let retries_counter = Arc::clone(&retries_counter_arc); retries_counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed); diff --git a/packages/rs-dapi-client/src/executor.rs b/packages/rs-dapi-client/src/executor.rs index 0afb8f57054..c87b2f9336b 100644 --- a/packages/rs-dapi-client/src/executor.rs +++ b/packages/rs-dapi-client/src/executor.rs @@ -34,7 +34,7 @@ pub trait InnerInto { } /// Error happened during request execution. -#[derive(Debug, Clone, thiserror::Error, Eq, PartialEq)] +#[derive(Debug, Clone, thiserror::Error, Eq)] #[error("{inner}")] pub struct ExecutionError { /// The cause of error @@ -45,6 +45,12 @@ pub struct ExecutionError { pub address: Option
, } +impl PartialEq for ExecutionError { + fn eq(&self, other: &Self) -> bool { + self.inner == other.inner && self.retries == other.retries && self.address == other.address + } +} + impl InnerInto> for ExecutionError where F: Into, diff --git a/packages/rs-dapi-client/src/lib.rs b/packages/rs-dapi-client/src/lib.rs index e820a714a0e..c54e4d3f65b 100644 --- a/packages/rs-dapi-client/src/lib.rs +++ b/packages/rs-dapi-client/src/lib.rs @@ -26,6 +26,10 @@ pub use executor::{ WrapToExecutionResult, }; use futures::{future::BoxFuture, FutureExt}; +#[cfg(any(target_arch = "wasm32", not(feature = "mocks")))] +pub use http::Uri; +#[cfg(all(feature = "mocks", not(target_arch = "wasm32")))] +pub use http_serde::http::Uri; pub use request_settings::RequestSettings; /// A DAPI request could be executed with an initialized [DapiClient]. diff --git a/packages/rs-dapi-client/src/request_settings.rs b/packages/rs-dapi-client/src/request_settings.rs index df89112322b..39f2da42d00 100644 --- a/packages/rs-dapi-client/src/request_settings.rs +++ b/packages/rs-dapi-client/src/request_settings.rs @@ -1,5 +1,6 @@ //! DAPI client request settings processing. +#[cfg(not(target_arch = "wasm32"))] use dapi_grpc::tonic::transport::Certificate; use std::time::Duration; @@ -65,6 +66,7 @@ impl RequestSettings { ban_failed_address: self .ban_failed_address .unwrap_or(DEFAULT_BAN_FAILED_ADDRESS), + #[cfg(not(target_arch = "wasm32"))] ca_certificate: None, } } @@ -82,12 +84,14 @@ pub struct AppliedRequestSettings { /// Ban DAPI address if node not responded or responded with error. pub ban_failed_address: bool, /// Certificate Authority certificate to use for verifying the server's certificate. + #[cfg(not(target_arch = "wasm32"))] pub ca_certificate: Option, } impl AppliedRequestSettings { /// Use provided CA certificate for verifying the server's certificate. /// /// If set to None, the system's default CA certificates will be used. + #[cfg(not(target_arch = "wasm32"))] pub fn with_ca_certificate(mut self, ca_cert: Option) -> Self { self.ca_certificate = ca_cert; self diff --git a/packages/rs-dapi-client/src/transport.rs b/packages/rs-dapi-client/src/transport.rs index 26c394ff034..3e342dbd708 100644 --- a/packages/rs-dapi-client/src/transport.rs +++ b/packages/rs-dapi-client/src/transport.rs @@ -1,17 +1,28 @@ //! Transport options that DAPI requests use under the hood. pub(crate) mod grpc; +#[cfg(not(target_arch = "wasm32"))] +pub(crate) mod tonic_channel; +#[cfg(target_arch = "wasm32")] +pub(crate) mod wasm_channel; use crate::connection_pool::ConnectionPool; pub use crate::request_settings::AppliedRequestSettings; -use crate::{CanRetry, RequestSettings}; +use crate::{CanRetry, RequestSettings, Uri}; use dapi_grpc::mock::Mockable; -use dapi_grpc::tonic::transport::Uri; pub use futures::future::BoxFuture; -pub use grpc::{CoreGrpcClient, PlatformGrpcClient}; use std::any; use std::fmt::Debug; +#[cfg(not(target_arch = "wasm32"))] +pub use tonic_channel::{ + create_channel, CoreGrpcClient, PlatformGrpcClient, TokioBackonSleeper as BackonSleeper, +}; +#[cfg(target_arch = "wasm32")] +pub use wasm_channel::{ + create_channel, CoreGrpcClient, PlatformGrpcClient, WasmBackonSleeper as BackonSleeper, +}; + /// Generic transport layer request. /// Requires [Clone] as could be retried and a client in general consumes a request. pub trait TransportRequest: Clone + Send + Sync + Debug + Mockable { diff --git a/packages/rs-dapi-client/src/transport/grpc.rs b/packages/rs-dapi-client/src/transport/grpc.rs index 77b98acf812..8c6195bd055 100644 --- a/packages/rs-dapi-client/src/transport/grpc.rs +++ b/packages/rs-dapi-client/src/transport/grpc.rs @@ -2,52 +2,16 @@ use std::time::Duration; +use super::create_channel; use super::{CanRetry, TransportClient, TransportError, TransportRequest}; +use super::{CoreGrpcClient, PlatformGrpcClient}; use crate::connection_pool::{ConnectionPool, PoolPrefix}; -use crate::{request_settings::AppliedRequestSettings, RequestSettings}; -use dapi_grpc::core::v0::core_client::CoreClient; +use crate::{request_settings::AppliedRequestSettings, RequestSettings, Uri}; use dapi_grpc::core::v0::{self as core_proto}; -use dapi_grpc::platform::v0::{self as platform_proto, platform_client::PlatformClient}; -use dapi_grpc::tonic::transport::{Certificate, ClientTlsConfig, Uri}; -use dapi_grpc::tonic::Streaming; -use dapi_grpc::tonic::{transport::Channel, IntoRequest}; +use dapi_grpc::platform::v0::{self as platform_proto}; +use dapi_grpc::tonic::{IntoRequest, Streaming}; use futures::{future::BoxFuture, FutureExt, TryFutureExt}; -/// Platform Client using gRPC transport. -pub type PlatformGrpcClient = PlatformClient; -/// Core Client using gRPC transport. -pub type CoreGrpcClient = CoreClient; - -fn create_channel( - uri: Uri, - settings: Option<&AppliedRequestSettings>, -) -> Result { - let host = uri.host().expect("Failed to get host from URI").to_string(); - - let mut builder = Channel::builder(uri); - let mut tls_config = ClientTlsConfig::new() - .with_native_roots() - .with_webpki_roots() - .assume_http2(true); - - if let Some(settings) = settings { - if let Some(timeout) = settings.connect_timeout { - builder = builder.connect_timeout(timeout); - } - - if let Some(pem) = settings.ca_certificate.as_ref() { - let cert = Certificate::from_pem(pem); - tls_config = tls_config.ca_certificate(cert).domain_name(host); - }; - } - - builder = builder - .tls_config(tls_config) - .expect("Failed to set TLS config"); - - Ok(builder.connect_lazy()) -} - impl TransportClient for PlatformGrpcClient { fn with_uri(uri: Uri, pool: &ConnectionPool) -> Result { Ok(pool @@ -506,6 +470,17 @@ impl_transport_request_grpc!( subscribe_to_transactions_with_proofs ); +impl_transport_request_grpc!( + core_proto::MasternodeListRequest, + Streaming, + CoreGrpcClient, + RequestSettings { + timeout: Some(STREAMING_TIMEOUT), + ..RequestSettings::default() + }, + subscribe_to_masternode_list +); + // rpc getStatus(GetStatusRequest) returns (GetStatusResponse); impl_transport_request_grpc!( platform_proto::GetStatusRequest, diff --git a/packages/rs-dapi-client/src/transport/tonic_channel.rs b/packages/rs-dapi-client/src/transport/tonic_channel.rs new file mode 100644 index 00000000000..0df0f55bf2a --- /dev/null +++ b/packages/rs-dapi-client/src/transport/tonic_channel.rs @@ -0,0 +1,52 @@ +use super::TransportError; +use crate::{request_settings::AppliedRequestSettings, Uri}; +use dapi_grpc::core::v0::core_client::CoreClient; +use dapi_grpc::platform::v0::platform_client::PlatformClient; +use dapi_grpc::tonic::transport::{Certificate, Channel, ClientTlsConfig}; + +/// Platform Client using gRPC transport. +pub type PlatformGrpcClient = PlatformClient; +/// Core Client using gRPC transport. +pub type CoreGrpcClient = CoreClient; + +/// backon::Sleeper +// #[derive(Default, Clone, Debug)] +pub type TokioBackonSleeper = backon::TokioSleeper; + +// impl backon::Sleeper for TonicBackonSleeper { +// type Sleep = ::Sleep; +// fn sleep(&self, dur: Duration) -> Self::Sleep { +// self.0.sleep(dur) +// } +// } + +/// Create channel (connection) for gRPC transport. +pub fn create_channel( + uri: Uri, + settings: Option<&AppliedRequestSettings>, +) -> Result { + let host = uri.host().expect("Failed to get host from URI").to_string(); + + let mut builder = Channel::builder(uri); + let mut tls_config = ClientTlsConfig::new() + .with_native_roots() + .with_webpki_roots() + .assume_http2(true); + + if let Some(settings) = settings { + if let Some(timeout) = settings.connect_timeout { + builder = builder.connect_timeout(timeout); + } + + if let Some(pem) = settings.ca_certificate.as_ref() { + let cert = Certificate::from_pem(pem); + tls_config = tls_config.ca_certificate(cert).domain_name(host); + }; + } + + builder = builder + .tls_config(tls_config) + .expect("Failed to set TLS config"); + + Ok(builder.connect_lazy()) +} diff --git a/packages/rs-dapi-client/src/transport/wasm_channel.rs b/packages/rs-dapi-client/src/transport/wasm_channel.rs new file mode 100644 index 00000000000..625e5b5791b --- /dev/null +++ b/packages/rs-dapi-client/src/transport/wasm_channel.rs @@ -0,0 +1,114 @@ +//! Listing of gRPC requests used in DAPI. + +use std::future::Future; +use std::time::Duration; + +use super::TransportError; +use crate::{request_settings::AppliedRequestSettings, Uri}; +use dapi_grpc::core::v0::core_client::CoreClient; + +use dapi_grpc::platform::v0::platform_client::PlatformClient; +use dapi_grpc::tonic::{self as tonic, Status}; +use futures::channel::oneshot; +use futures::future::BoxFuture; +use futures::{FutureExt, TryFutureExt}; +use http::Response; +use tonic_web_wasm_client::Client; +use wasm_bindgen_futures::spawn_local; + +/// Platform Client using gRPC transport. +pub type PlatformGrpcClient = PlatformClient; +/// Core Client using gRPC transport. +pub type CoreGrpcClient = CoreClient; + +/// Create a channel that will be used to communicate with the DAPI. +pub fn create_channel( + uri: Uri, + _settings: Option<&AppliedRequestSettings>, +) -> Result { + WasmClient::new(&uri.to_string()) +} + +/// Transport client used in wasm32 target (eg. Javascript family) +#[derive(Clone, Debug)] +pub struct WasmClient { + client: Client, +} + +impl WasmClient { + /// Create a new instance of the client, connecting to provided uri. + pub fn new(uri: &str) -> Result { + let client = tonic_web_wasm_client::Client::new(uri.to_string()); + Ok(Self { client }) + } +} + +impl tonic::client::GrpcService for WasmClient { + type Future = BoxFuture<'static, Result, Self::Error>>; + type ResponseBody = tonic::body::BoxBody; + type Error = Status; + + fn call(&mut self, request: http::Request) -> Self::Future { + let mut client = self.client.clone(); + let fut = client.call(request).map(|res| match res { + Ok(resp) => { + let body = tonic::body::boxed(resp.into_body()); + Ok(Response::new(body)) + } + Err(e) => Err(wasm_client_error_to_status(e)), + }); + + into_send(fut) + } + + fn poll_ready( + &mut self, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.client + .poll_ready(cx) + .map_err(wasm_client_error_to_status) + } +} + +/// Map [`tonic_web_wasm_client::Error`] to [`tonic::Status`]. +/// +/// TODO: Add more error handling. +fn wasm_client_error_to_status(e: tonic_web_wasm_client::Error) -> Status { + match e { + tonic_web_wasm_client::Error::TonicStatusError(status) => status, + _ => Status::internal(format!("Failed to call gRPC service: {}", e)), + } +} + +/// backon::Sleeper implementation for Wasm. +/// +/// ## Note +/// +/// It is already implemented in [::backon] crate, but it is not Send, so it cannot be used in our context. +/// We reimplement it here to make it Send. +// TODO: Consider moving it to different module. +#[derive(Default, Clone, Debug)] +pub struct WasmBackonSleeper {} +impl backon::Sleeper for WasmBackonSleeper { + type Sleep = BoxFuture<'static, ()>; + fn sleep(&self, dur: Duration) -> Self::Sleep { + into_send(gloo_timers::future::sleep(dur)).boxed() + } +} + +/// Convert a future into a boxed future that can be sent between threads. +/// +/// This is a workaround using oneshot channel to synchronize. +/// It spawns a local task that sends the result of the future to the channel. +fn into_send<'a, F: Future + 'static>(f: F) -> BoxFuture<'a, F::Output> +where + F::Output: Send, +{ + let (tx, rx) = oneshot::channel::(); + spawn_local(async move { + tx.send(f.await).ok(); + }); + rx.unwrap_or_else(|e| panic!("Failed to receive result: {:?}", e)) + .boxed() +} diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index c3363198eb7..de5897134c3 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -29,7 +29,6 @@ dashcore = { git = "https://github.com/dashpay/rust-dashcore", features = [ "signer", "serde", ], default-features = false, tag = "0.34.0" } -env_logger = { version = "0.11" } getrandom = { version = "0.2", features = ["js"] } hex = { version = "0.4" } integer-encoding = { version = "4.0.0" } @@ -38,7 +37,6 @@ jsonschema = { git = "https://github.com/dashpay/jsonschema-rs", branch = "confi "draft202012", ], optional = true } lazy_static = { version = "1.4" } -log = { version = "0.4.6" } num_enum = "0.7" bincode = { version = "2.0.0-rc.3", features = ["serde"] } rand = { version = "0.8.5", features = ["small_rng"] } @@ -56,11 +54,11 @@ platform-serialization = { path = "../rs-platform-serialization" } platform-serialization-derive = { path = "../rs-platform-serialization-derive" } derive_more = { version = "1.0", features = ["from", "display", "try_into"] } nohash-hasher = "0.2.0" -rust_decimal = "1.29.1" -rust_decimal_macros = "1.29.1" +rust_decimal = { version = "1.29.1", optional = true } +rust_decimal_macros = { version = "1.29.1", optional = true } indexmap = { version = "2.7.0", features = ["serde"] } strum = { version = "0.26", features = ["derive"] } -json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator' } +json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator', optional = true } once_cell = "1.19.0" [dev-dependencies] @@ -70,14 +68,15 @@ pretty_assertions = { version = "1.4.1" } dpp = { path = ".", features = ["all_features_without_client"] } assert_matches = "1.5.0" once_cell = "1.7" +env_logger = { version = "0.11" } +log = { version = "0.4.22" } [features] -default = ["platform-value", "state-transitions"] +default = ["state-transitions"] bls-signatures = ["dashcore/bls"] ed25519-dalek = ["dashcore/eddsa"] all_features = [ "json-object", - "platform-value", "system_contracts", "state-transitions", "extended-document", @@ -121,27 +120,27 @@ all_features = [ ] dash-sdk-features = [ - "json-object", - "platform-value", - "system_contracts", - "state-transitions", - "validation", + # "json-object", + # "platform-value", + # "system_contracts", + # "validation", # TODO: This one is big "identity-hashing", - "identity-serialization", - "vote-serialization", - "document-value-conversion", - "data-contract-value-conversion", + "data-contract-json-conversion", + # "identity-serialization", + # "vote-serialization", + # "document-value-conversion", + # "data-contract-value-conversion", "identity-value-conversion", - "core-types", - "core-types-serialization", - "core-types-serde-conversion", - "state-transition-serde-conversion", + # "core-types", + # "core-types-serialization", + # "core-types-serde-conversion", + # "state-transition-serde-conversion", "state-transition-value-conversion", - "state-transition-json-conversion", - "state-transition-validation", + # "state-transition-json-conversion", + # "state-transition-validation", "state-transition-signing", - "state-transitions", - "fee-distribution", + # "state-transitions", + # "fee-distribution", "client", "platform-value-cbor", ] @@ -208,9 +207,15 @@ validation = [ "state-transition-serde-conversion", "ed25519-dalek", ] +# TODO: Tring to remove regexp +create-contested-document = [] platform-value-json = ["platform-value/json"] platform-value-cbor = ["platform-value/cbor"] -json-schema-validation = ["jsonschema", "platform-value-json"] +json-schema-validation = [ + "jsonschema", + "platform-value-json", + "dep:json-schema-compatibility-validator", +] json-object = ["platform-value", "platform-value-json"] platform-value = [] identity-hashing = ["identity-serialization"] @@ -281,7 +286,7 @@ random-public-keys = ["bls-signatures", "ed25519-dalek"] random-identities = ["random-public-keys"] random-documents = [] random-document-types = ["platform-value-json"] -fee-distribution = [] +fee-distribution = ["dep:rust_decimal", "dep:rust_decimal_macros"] extended-document = [ "document-serde-conversion", "data-contract-serde-conversion", diff --git a/packages/rs-dpp/src/balances/credits.rs b/packages/rs-dpp/src/balances/credits.rs index d0f9e2805b9..8db94c32386 100644 --- a/packages/rs-dpp/src/balances/credits.rs +++ b/packages/rs-dpp/src/balances/credits.rs @@ -16,22 +16,18 @@ use std::convert::TryFrom; pub type Duffs = u64; /// Credits type - pub type Credits = u64; /// Signed Credits type is used for internal computations and total credits /// balance verification - pub type SignedCredits = i64; /// Maximum value of credits - pub const MAX_CREDITS: Credits = 9223372036854775807 as Credits; //i64 Max pub const CREDITS_PER_DUFF: Credits = 1000; /// Trait for signed and unsigned credits - pub trait Creditable { /// Convert unsigned credit to singed fn to_signed(&self) -> Result; diff --git a/packages/rs-dpp/src/bls/mod.rs b/packages/rs-dpp/src/bls/mod.rs index 8b825531c02..a5501f4634d 100644 --- a/packages/rs-dpp/src/bls/mod.rs +++ b/packages/rs-dpp/src/bls/mod.rs @@ -1,4 +1,4 @@ -#[cfg(all(not(target_arch = "wasm32"), feature = "bls-signatures"))] +#[cfg(feature = "bls-signatures")] pub mod native_bls; use crate::{ProtocolError, PublicKeyValidationError}; diff --git a/packages/rs-dpp/src/data_contract/data_contract_facade.rs b/packages/rs-dpp/src/data_contract/data_contract_facade.rs index d1f606622e3..aa352c47699 100644 --- a/packages/rs-dpp/src/data_contract/data_contract_facade.rs +++ b/packages/rs-dpp/src/data_contract/data_contract_facade.rs @@ -57,10 +57,13 @@ impl DataContractFacade { pub fn create_from_object( &self, raw_data_contract: Value, - skip_validation: bool, + #[cfg(feature = "validation")] skip_validation: bool, ) -> Result { - self.factory - .create_from_object(raw_data_contract, skip_validation) + self.factory.create_from_object( + raw_data_contract, + #[cfg(feature = "validation")] + skip_validation, + ) } /// Create Data Contract from buffer @@ -68,9 +71,13 @@ impl DataContractFacade { pub fn create_from_buffer( &self, buffer: Vec, - skip_validation: bool, + #[cfg(feature = "validation")] skip_validation: bool, ) -> Result { - self.factory.create_from_buffer(buffer, skip_validation) + self.factory.create_from_buffer( + buffer, + #[cfg(feature = "validation")] + skip_validation, + ) } #[cfg(feature = "state-transitions")] diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs index 57b3bffb37f..a55ce4a6d0e 100644 --- a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs @@ -721,6 +721,8 @@ fn insert_values( Ok(()) } + +// TODO: This is quite big fn insert_values_nested( document_properties: &mut IndexMap, known_required: &BTreeSet, diff --git a/packages/rs-dpp/src/data_contract/document_type/index/mod.rs b/packages/rs-dpp/src/data_contract/document_type/index/mod.rs index a8768ed8f5d..70bb184aa2f 100644 --- a/packages/rs-dpp/src/data_contract/document_type/index/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/index/mod.rs @@ -25,6 +25,7 @@ use serde::de::{VariantAccess, Visitor}; use std::cmp::Ordering; #[cfg(feature = "index-serde-conversion")] use std::fmt; +use std::sync::OnceLock; use std::{collections::BTreeMap, convert::TryFrom}; pub mod random_index; @@ -53,10 +54,37 @@ impl TryFrom for ContestedIndexResolution { #[repr(u8)] #[derive(Debug)] pub enum ContestedIndexFieldMatch { - Regex(regex::Regex), + Regex(LazyRegex), PositiveIntegerMatch(u128), } +#[derive(Debug, Clone)] +pub struct LazyRegex { + regex: OnceLock, + regex_str: String, +} + +impl LazyRegex { + pub fn new(regex_str: String) -> Self { + LazyRegex { + regex: OnceLock::new(), + regex_str, + } + } + + pub fn is_match(&self, string: &str) -> bool { + let regexp = self + .regex + .get_or_init(|| Regex::new(&self.regex_str).expect("valid regexp")); + + regexp.is_match(string) + } + + pub fn as_str(&self) -> &str { + self.regex_str.as_str() + } +} + #[cfg(feature = "index-serde-conversion")] impl Serialize for ContestedIndexFieldMatch { fn serialize(&self, serializer: S) -> Result @@ -133,10 +161,9 @@ impl<'de> Deserialize<'de> for ContestedIndexFieldMatch { { match visitor.variant()? { (Field::Regex, v) => { - let regex_str: &str = v.newtype_variant()?; - Regex::new(regex_str) - .map(ContestedIndexFieldMatch::Regex) - .map_err(de::Error::custom) + let regex_str: String = v.newtype_variant()?; + + Ok(ContestedIndexFieldMatch::Regex(LazyRegex::new(regex_str))) } (Field::PositiveIntegerMatch, v) => { let num: u128 = v.newtype_variant()?; @@ -192,7 +219,7 @@ impl Clone for ContestedIndexFieldMatch { fn clone(&self) -> Self { match self { ContestedIndexFieldMatch::Regex(regex) => { - ContestedIndexFieldMatch::Regex(regex::Regex::new(regex.as_str()).unwrap()) + ContestedIndexFieldMatch::Regex(regex.clone()) } ContestedIndexFieldMatch::PositiveIntegerMatch(int) => { ContestedIndexFieldMatch::PositiveIntegerMatch(*int) @@ -494,15 +521,20 @@ impl TryFrom<&[(Value, Value)]> for Index { name = Some(field); } "regexPattern" => { - let regex = field_match_value.to_str()?.to_owned(); + let regex_str = + field_match_value.to_str()?.to_owned(); + + #[cfg(feature = "validation")] + Regex::new(®ex_str).map_err(|e| { + RegexError(format!( + "invalid field match regex: {}", + e.to_string() + )) + })?; + field_matches = Some(ContestedIndexFieldMatch::Regex( - Regex::new(®ex).map_err(|e| { - RegexError(format!( - "invalid field match regex: {}", - e.to_string() - )) - })?, + LazyRegex::new(regex_str), )); } key => { diff --git a/packages/rs-dpp/src/data_contract/mod.rs b/packages/rs-dpp/src/data_contract/mod.rs index 5fd8f7b56f5..2c1fa42fa75 100644 --- a/packages/rs-dpp/src/data_contract/mod.rs +++ b/packages/rs-dpp/src/data_contract/mod.rs @@ -23,6 +23,11 @@ mod v0; pub mod factory; #[cfg(feature = "factories")] pub use factory::*; +#[cfg(any( + feature = "data-contract-value-conversion", + feature = "data-contract-cbor-conversion", + feature = "data-contract-json-conversion" +))] pub mod conversion; #[cfg(feature = "client")] mod data_contract_facade; diff --git a/packages/rs-dpp/src/identity/identity_facade.rs b/packages/rs-dpp/src/identity/identity_facade.rs index eecdf45e6e2..323fea838dd 100644 --- a/packages/rs-dpp/src/identity/identity_facade.rs +++ b/packages/rs-dpp/src/identity/identity_facade.rs @@ -56,9 +56,13 @@ impl IdentityFacade { pub fn create_from_buffer( &self, buffer: Vec, - skip_validation: bool, + #[cfg(feature = "validation")] skip_validation: bool, ) -> Result { - self.factory.create_from_buffer(buffer, skip_validation) + self.factory.create_from_buffer( + buffer, + #[cfg(feature = "validation")] + skip_validation, + ) } pub fn create_instant_lock_proof( diff --git a/packages/rs-dpp/src/lib.rs b/packages/rs-dpp/src/lib.rs index 27932329aa9..0b6075e5d9c 100644 --- a/packages/rs-dpp/src/lib.rs +++ b/packages/rs-dpp/src/lib.rs @@ -24,7 +24,6 @@ pub mod version; pub mod errors; -pub mod schema; pub mod validation; #[cfg(feature = "client")] diff --git a/packages/rs-dpp/src/schema/data_contract/v0/stateTransition/dataContractCreate.json b/packages/rs-dpp/src/schema/data_contract/v0/stateTransition/dataContractCreate.json deleted file mode 100644 index c093f71afb9..00000000000 --- a/packages/rs-dpp/src/schema/data_contract/v0/stateTransition/dataContractCreate.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "version": { - "type": "integer", - "$comment": "Maximum is the latest protocol version" - }, - "type": { - "type": "integer", - "const": 0 - }, - "dataContract": { - "type": "object" - }, - "entropy": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32 - }, - "signaturePublicKeyId": { - "type": "integer", - "minimum": 0 - }, - "signature": { - "type": "array", - "byteArray": true, - "minItems": 65, - "maxItems": 96 - } - }, - "additionalProperties": false, - "required": [ - "version", - "type", - "dataContract", - "entropy", - "signaturePublicKeyId", - "signature" - ] -} diff --git a/packages/rs-dpp/src/schema/data_contract/v0/stateTransition/dataContractUpdate.json b/packages/rs-dpp/src/schema/data_contract/v0/stateTransition/dataContractUpdate.json deleted file mode 100644 index 4ce9c5dd353..00000000000 --- a/packages/rs-dpp/src/schema/data_contract/v0/stateTransition/dataContractUpdate.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "version": { - "type": "integer", - "$comment": "Maximum is the latest protocol version" - }, - "type": { - "type": "integer", - "const": 4 - }, - "dataContract": { - "type": "object" - }, - "signaturePublicKeyId": { - "type": "integer", - "minimum": 0 - }, - "signature": { - "type": "array", - "byteArray": true, - "minItems": 65, - "maxItems": 96 - } - }, - "additionalProperties": false, - "required": [ - "version", - "type", - "dataContract", - "signaturePublicKeyId", - "signature" - ] -} diff --git a/packages/rs-dpp/src/schema/document/v0/documentBase.json b/packages/rs-dpp/src/schema/document/v0/documentBase.json deleted file mode 100644 index a8ee99ae9cb..00000000000 --- a/packages/rs-dpp/src/schema/document/v0/documentBase.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "$protocolVersion": { - "type": "integer", - "$comment": "Maximum is the latest protocol version" - }, - "$id": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - }, - "$type": { - "type": "string" - }, - "$revision": { - "type": "integer", - "minimum": 1 - }, - "$dataContractId": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - }, - "$ownerId": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - }, - "$createdAt": { - "type": "integer", - "minimum": 0 - }, - "$updatedAt": { - "type": "integer", - "minimum": 0 - }, - "$transferredAt": { - "type": "integer", - "minimum": 0 - }, - "$createdAtBlockHeight": { - "type": "integer", - "minimum": 0 - }, - "$updatedAtBlockHeight": { - "type": "integer", - "minimum": 0 - }, - "$transferredAtBlockHeight": { - "type": "integer", - "minimum": 0 - }, - "$createdAtCoreBlockHeight": { - "type": "integer", - "minimum": 0 - }, - "$updatedAtCoreBlockHeight": { - "type": "integer", - "minimum": 0 - }, - "$transferredAtCoreBlockHeight": { - "type": "integer", - "minimum": 0 - } - }, - "required": [ - "$protocolVersion", - "$id", - "$type", - "$revision", - "$dataContractId", - "$ownerId" - ], - "additionalProperties": false -} diff --git a/packages/rs-dpp/src/schema/document/v0/stateTransition/documentTransition/base.json b/packages/rs-dpp/src/schema/document/v0/stateTransition/documentTransition/base.json deleted file mode 100644 index 7b74ddb4b87..00000000000 --- a/packages/rs-dpp/src/schema/document/v0/stateTransition/documentTransition/base.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "$id": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - }, - "$type": { - "type": "string" - }, - "$action": { - "type": "integer", - "enum": [0, 1, 3] - }, - "$dataContractId": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - } - }, - "required": [ - "$id", - "$type", - "$action", - "$dataContractId" - ], - "additionalProperties": false -} diff --git a/packages/rs-dpp/src/schema/document/v0/stateTransition/documentTransition/create.json b/packages/rs-dpp/src/schema/document/v0/stateTransition/documentTransition/create.json deleted file mode 100644 index 399cb5c4f7d..00000000000 --- a/packages/rs-dpp/src/schema/document/v0/stateTransition/documentTransition/create.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "$entropy": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32 - }, - "$createdAt": { - "type": "integer", - "minimum": 0 - }, - "$updatedAt": { - "type": "integer", - "minimum": 0 - } - }, - "required": [ - "$entropy" - ], - "additionalProperties": false -} diff --git a/packages/rs-dpp/src/schema/document/v0/stateTransition/documentTransition/replace.json b/packages/rs-dpp/src/schema/document/v0/stateTransition/documentTransition/replace.json deleted file mode 100644 index 1fde6adba6f..00000000000 --- a/packages/rs-dpp/src/schema/document/v0/stateTransition/documentTransition/replace.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "$revision": { - "type": "integer", - "minimum": 1 - }, - "$updatedAt": { - "type": "integer", - "minimum": 0 - } - }, - "required": [ - "$revision" - ], - "additionalProperties": false -} diff --git a/packages/rs-dpp/src/schema/document/v0/stateTransition/documentsBatch.json b/packages/rs-dpp/src/schema/document/v0/stateTransition/documentsBatch.json deleted file mode 100644 index 01e4d2bad61..00000000000 --- a/packages/rs-dpp/src/schema/document/v0/stateTransition/documentsBatch.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "protocolVersion": { - "type": "integer", - "$comment": "Maximum is the latest protocol version" - }, - "type": { - "type": "integer", - "const": 1 - }, - "ownerId": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - }, - "transitions": { - "type": "array", - "items": { - "type": "object" - }, - "minItems": 1, - "maxItems": 10 - }, - "signaturePublicKeyId": { - "type": "integer", - "minimum": 0 - }, - "signature": { - "type": "array", - "byteArray": true, - "minItems": 65, - "maxItems": 96 - } - }, - "additionalProperties": false, - "required": [ - "protocolVersion", - "type", - "ownerId", - "transitions", - "signaturePublicKeyId", - "signature" - ] -} diff --git a/packages/rs-dpp/src/schema/identity/mod.rs b/packages/rs-dpp/src/schema/identity/mod.rs deleted file mode 100644 index 2d24cd45f58..00000000000 --- a/packages/rs-dpp/src/schema/identity/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod v0; diff --git a/packages/rs-dpp/src/schema/identity/v0/identity.json b/packages/rs-dpp/src/schema/identity/v0/identity.json deleted file mode 100644 index d29b01e8c1c..00000000000 --- a/packages/rs-dpp/src/schema/identity/v0/identity.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "protocolVersion": { - "type": "integer", - "minimum": 0, - "$comment": "Maximum is the latest protocol version" - }, - "id": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - }, - "publicKeys": { - "type": "array", - "minItems": 1, - "maxItems": 32, - "uniqueItems": true - }, - "balance": { - "type": "integer", - "minimum": 0 - }, - "revision": { - "type": "integer", - "minimum": 0, - "description": "Identity update revision" - } - }, - "required": [ - "protocolVersion", - "id", - "publicKeys", - "balance", - "revision" - ] -} diff --git a/packages/rs-dpp/src/schema/identity/v0/identity.rs b/packages/rs-dpp/src/schema/identity/v0/identity.rs deleted file mode 100644 index 4a75f03993a..00000000000 --- a/packages/rs-dpp/src/schema/identity/v0/identity.rs +++ /dev/null @@ -1,46 +0,0 @@ -use serde_json::Value; - -pub const IDENTITY_JSON_STRING: &str = r#"{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "protocolVersion": { - "type": "integer", - "minimum": 0, - "$comment": "Maximum is the latest protocol version" - }, - "id": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - }, - "publicKeys": { - "type": "array", - "minItems": 1, - "maxItems": 32, - "uniqueItems": true - }, - "balance": { - "type": "integer", - "minimum": 0 - }, - "revision": { - "type": "integer", - "minimum": 0, - "description": "Identity update revision" - } - }, - "required": [ - "protocolVersion", - "id", - "publicKeys", - "balance", - "revision" - ] -}"#; - -pub fn identity_json() -> Result { - serde_json::from_str(IDENTITY_JSON_STRING) -} diff --git a/packages/rs-dpp/src/schema/identity/v0/mod.rs b/packages/rs-dpp/src/schema/identity/v0/mod.rs deleted file mode 100644 index 9210acfe1f9..00000000000 --- a/packages/rs-dpp/src/schema/identity/v0/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub use identity::identity_json; - -mod identity; diff --git a/packages/rs-dpp/src/schema/identity/v0/publicKey.json b/packages/rs-dpp/src/schema/identity/v0/publicKey.json deleted file mode 100644 index af3ae1f077c..00000000000 --- a/packages/rs-dpp/src/schema/identity/v0/publicKey.json +++ /dev/null @@ -1,150 +0,0 @@ - { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "id": { - "type": "integer", - "minimum": 0, - "description": "Public key ID", - "$comment": "Must be unique for the identity. It can’t be changed after adding a key. Included when signing state transitions to indicate which identity key was used to sign." - }, - "type": { - "type": "integer", - "enum": [ - 0, - 1, - 2, - 3 - ], - "description": "Public key type. 0 - ECDSA Secp256k1, 1 - BLS 12-381, 2 - ECDSA Secp256k1 Hash160, 3 - BIP 13 Hash160", - "$comment": "It can't be changed after adding a key" - }, - "purpose": { - "type": "integer", - "enum": [ - 0, - 1, - 2, - 3 - ], - "description": "Public key purpose. 0 - Authentication, 1 - Encryption, 2 - Decryption, 3 - Withdraw", - "$comment": "It can't be changed after adding a key" - }, - "securityLevel": { - "type": "integer", - "enum": [ - 0, - 1, - 2, - 3 - ], - "description": "Public key security level. 0 - Master, 1 - Critical, 2 - High, 3 - Medium", - "$comment": "It can't be changed after adding a key" - }, - "data": true, - "readOnly": { - "type": "boolean", - "description": "Read only", - "$comment": "Identity public key can't be modified with readOnly set to true. It can’t be changed after adding a key" - }, - "disabledAt": { - "type": "integer", - "description": "Timestamp indicating that the key was disabled at a specified time", - "minimum": 0 - } - }, - "allOf": [ - { - "if": { - "properties": { - "type": { - "const": 0 - } - } - }, - "then": { - "properties": { - "data": { - "type": "array", - "byteArray": true, - "minItems": 33, - "maxItems": 33, - "description": "Raw ECDSA public key", - "$comment": "It must be a valid key of the specified type and unique for the identity. It can’t be changed after adding a key" - } - } - } - }, - { - "if": { - "properties": { - "type": { - "const": 1 - } - } - }, - "then": { - "properties": { - "data": { - "type": "array", - "byteArray": true, - "minItems": 48, - "maxItems": 48, - "description": "Raw BLS public key", - "$comment": "It must be a valid key of the specified type and unique for the identity. It can’t be changed after adding a key" - } - } - } - }, - { - "if": { - "properties": { - "type": { - "const": 2 - } - } - }, - "then": { - "properties": { - "data": { - "type": "array", - "byteArray": true, - "minItems": 20, - "maxItems": 20, - "description": "ECDSA Secp256k1 public key Hash160", - "$comment": "It must be a valid key hash of the specified type and unique for the identity. It can’t be changed after adding a key" - } - } - } - }, - { - "if": { - "properties": { - "type": { - "const": 3 - } - } - }, - "then": { - "properties": { - "data": { - "type": "array", - "byteArray": true, - "minItems": 20, - "maxItems": 20, - "description": "BIP13 script public key", - "$comment": "It must be a valid script hash of the specified type and unique for the identity" - } - } - } - } - ], - "required": [ - "id", - "type", - "data", - "purpose", - "securityLevel" - ], - "additionalProperties": false - } diff --git a/packages/rs-dpp/src/schema/identity/v0/stateTransition/assetLockProof/chainAssetLockProof.json b/packages/rs-dpp/src/schema/identity/v0/stateTransition/assetLockProof/chainAssetLockProof.json deleted file mode 100644 index e5da91cbc26..00000000000 --- a/packages/rs-dpp/src/schema/identity/v0/stateTransition/assetLockProof/chainAssetLockProof.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "type": { - "type": "integer", - "const": 1 - }, - "coreChainLockedHeight": { - "type": "integer", - "minimum": 1, - "maximum": 4294967295 - }, - "outPoint": { - "type": "array", - "byteArray": true, - "minItems": 36, - "maxItems": 36 - } - }, - "additionalProperties": false, - "required": [ - "type", - "coreChainLockedHeight", - "outPoint" - ] -} diff --git a/packages/rs-dpp/src/schema/identity/v0/stateTransition/assetLockProof/instantAssetLockProof.json b/packages/rs-dpp/src/schema/identity/v0/stateTransition/assetLockProof/instantAssetLockProof.json deleted file mode 100644 index 5a5441b432f..00000000000 --- a/packages/rs-dpp/src/schema/identity/v0/stateTransition/assetLockProof/instantAssetLockProof.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "type": { - "type": "integer", - "const": 0 - }, - "instantLock": { - "type": "array", - "byteArray": true, - "minItems": 165, - "maxItems": 100000 - }, - "transaction": { - "type": "array", - "byteArray": true, - "minItems": 1, - "maxItems": 100000 - }, - "outputIndex": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "type", - "instantLock", - "transaction", - "outputIndex" - ] -} diff --git a/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityCreate.json b/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityCreate.json deleted file mode 100644 index 3eb2227a2f7..00000000000 --- a/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityCreate.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "protocolVersion": { - "type": "integer", - "$comment": "Maximum is the latest protocol version" - }, - "type": { - "type": "integer", - "const": 2 - }, - "assetLockProof": { - "type": "object" - }, - "publicKeys": { - "type": "array", - "minItems": 1, - "maxItems": 10, - "uniqueItems": true - }, - "signature": { - "type": "array", - "byteArray": true, - "minItems": 65, - "maxItems": 65, - "description": "Signature made by AssetLock one time ECDSA key" - } - }, - "additionalProperties": false, - "required": [ - "protocolVersion", - "type", - "assetLockProof", - "publicKeys", - "signature" - ] -} diff --git a/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityCreditTransfer.json b/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityCreditTransfer.json deleted file mode 100644 index da1047bbb2c..00000000000 --- a/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityCreditTransfer.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "protocolVersion": { - "type": "integer", - "$comment": "Maximum is the latest protocol version" - }, - "type": { - "type": "integer", - "const": 7 - }, - "identityId": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - }, - "recipientId": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - }, - "amount": { - "type": "integer", - "description": "The amount to be transferred", - "minimum": 1000 - }, - "signature": { - "type": "array", - "byteArray": true, - "minItems": 65, - "maxItems": 65 - }, - "signaturePublicKeyId": { - "type": "integer", - "minimum": 0 - } - }, - "additionalProperties": false, - "required": [ - "protocolVersion", - "type", - "identityId", - "recipientId", - "amount", - "signature", - "signaturePublicKeyId" - ] -} diff --git a/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityCreditWithdrawal.json b/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityCreditWithdrawal.json deleted file mode 100644 index c689d54afd9..00000000000 --- a/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityCreditWithdrawal.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "protocolVersion": { - "type": "integer", - "$comment": "Maximum is the latest protocol version" - }, - "type": { - "type": "integer", - "const": 6 - }, - "identityId": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - }, - "amount": { - "type": "integer", - "description": "The amount to be withdrawn", - "minimum": 1000 - }, - "coreFeePerByte": { - "type": "integer", - "description": "This is the fee that you are willing to spend for this transaction in Duffs/Byte", - "minimum": 1, - "maximum": 4294967295 - }, - "pooling": { - "type": "integer", - "description": "This indicated the level at which Platform should try to pool this transaction", - "enum": [ - 0, - 1, - 2 - ] - }, - "outputScript": { - "type": "array", - "byteArray": true, - "minItems": 23, - "maxItems": 25 - }, - "signature": { - "type": "array", - "byteArray": true, - "minItems": 65, - "maxItems": 65 - }, - "signaturePublicKeyId": { - "type": "integer", - "minimum": 0 - }, - "revision": { - "type": "integer", - "minimum": 0, - "description": "Target identity revision" - } - }, - "additionalProperties": false, - "required": [ - "protocolVersion", - "type", - "identityId", - "amount", - "coreFeePerByte", - "pooling", - "outputScript", - "signature", - "signaturePublicKeyId", - "revision" - ] -} \ No newline at end of file diff --git a/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityTopUp.json b/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityTopUp.json deleted file mode 100644 index 73be31c5200..00000000000 --- a/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityTopUp.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "protocolVersion": { - "type": "integer", - "$comment": "Maximum is the latest protocol version" - }, - "type": { - "type": "integer", - "const": 3 - }, - "assetLockProof": { - "type": "object" - }, - "identityId": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - }, - "signature": { - "type": "array", - "byteArray": true, - "minItems": 65, - "maxItems": 65, - "description": "Signature made by AssetLock one time ECDSA key" - } - }, - "additionalProperties": false, - "required": [ - "protocolVersion", - "type", - "assetLockProof", - "identityId", - "signature" - ] -} diff --git a/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityUpdate.json b/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityUpdate.json deleted file mode 100644 index b31632dd9ec..00000000000 --- a/packages/rs-dpp/src/schema/identity/v0/stateTransition/identityUpdate.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "protocolVersion": { - "type": "integer", - "$comment": "Maximum is the latest protocol version" - }, - "type": { - "type": "integer", - "const": 5 - }, - "identityId": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier" - }, - "signature": { - "type": "array", - "byteArray": true, - "minItems": 65, - "maxItems": 96 - }, - "revision": { - "type": "integer", - "minimum": 0, - "description": "Identity update revision" - }, - "addPublicKeys": { - "type": "array", - "minItems": 1, - "maxItems": 10, - "uniqueItems": true - }, - "disablePublicKeys": { - "type": "array", - "minItems": 1, - "maxItems": 10, - "uniqueItems": true, - "items": { - "type": "integer", - "minimum": 0 - } - }, - "signaturePublicKeyId": { - "type": "integer", - "minimum": 0 - } - }, - "anyOf": [ - { - "type": "object", - "required": [ - "addPublicKeys" - ], - "properties": { - "addPublicKeys": true - } - }, - { - "type": "object", - "required": [ - "disablePublicKeys" - ], - "properties": { - "disablePublicKeys": true - } - } - ], - "additionalProperties": false, - "required": [ - "protocolVersion", - "type", - "identityId", - "signature", - "revision", - "signaturePublicKeyId" - ] -} diff --git a/packages/rs-dpp/src/schema/identity/v0/stateTransition/publicKey.json b/packages/rs-dpp/src/schema/identity/v0/stateTransition/publicKey.json deleted file mode 100644 index ef4b454a9a4..00000000000 --- a/packages/rs-dpp/src/schema/identity/v0/stateTransition/publicKey.json +++ /dev/null @@ -1,146 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "id": { - "type": "integer", - "minimum": 0, - "description": "Public key ID", - "$comment": "Must be unique for the identity. It can’t be changed after adding a key. Included when signing state transitions to indicate which identity key was used to sign." - }, - "type": { - "type": "integer", - "enum": [ - 0, - 1, - 2 - ], - "description": "Public key type. 0 - ECDSA Secp256k1, 1 - BLS 12-381, 2 - ECDSA Secp256k1 Hash160", - "$comment": "It can't be changed after adding a key" - }, - "purpose": { - "type": "integer", - "enum": [ - 0, - 1, - 2, - 3 - ], - "description": "Public key purpose. 0 - Authentication, 1 - Encryption, 2 - Decryption, 3 - Withdraw", - "$comment": "It can't be changed after adding a key" - }, - "securityLevel": { - "type": "integer", - "enum": [ - 0, - 1, - 2, - 3 - ], - "description": "Public key security level. 0 - Master, 1 - Critical, 2 - High, 3 - Medium", - "$comment": "It can't be changed after adding a key" - }, - "data": true, - "readOnly": { - "type": "boolean", - "description": "Read only", - "$comment": "Identity public key can't be modified with readOnly set to true. It can’t be changed after adding a key" - }, - "signature": true - }, - "allOf": [ - { - "if": { - "properties": { - "type": { - "const": 0 - } - } - }, - "then": { - "properties": { - "data": { - "type": "array", - "byteArray": true, - "minItems": 33, - "maxItems": 33, - "description": "Raw ECDSA Secp256k1 public key", - "$comment": "It must be a valid key of the specified type and unique for the identity. It can’t be changed after adding a key" - }, - "signature": { - "type": "array", - "byteArray": true, - "description": "ECDSA Secp256k1 signature to prove ownership of public key", - "minItems": 65, - "maxItems": 65 - } - } - } - }, - { - "if": { - "properties": { - "type": { - "const": 1 - } - } - }, - "then": { - "properties": { - "data": { - "type": "array", - "byteArray": true, - "minItems": 48, - "maxItems": 48, - "description": "Raw BLS public key", - "$comment": "It must be a valid key of the specified type and unique for the identity. It can’t be changed after adding a key" - }, - "signature": { - "type": "array", - "byteArray": true, - "description": "BLS signature to prove ownership of public key", - "minItems": 96, - "maxItems": 96 - } - } - } - }, - { - "if": { - "properties": { - "type": { - "const": 2 - } - } - }, - "then": { - "properties": { - "data": { - "type": "array", - "byteArray": true, - "minItems": 20, - "maxItems": 20, - "description": "ECDSA Secp256k1 public key Hash160", - "$comment": "It must be a valid key hash of the specified type and unique for the identity. It can’t be changed after adding a key" - }, - "signature": { - "type": "array", - "byteArray": true, - "description": "ECDSA signature to prove ownership of public key", - "minItems": 65, - "maxItems": 65 - } - } - } - } - ], - "required": [ - "id", - "type", - "data", - "purpose", - "securityLevel", - "signature" - ], - "additionalProperties": false -} diff --git a/packages/rs-dpp/src/schema/mod.rs b/packages/rs-dpp/src/schema/mod.rs deleted file mode 100644 index 92bc6186b45..00000000000 --- a/packages/rs-dpp/src/schema/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -use lazy_static::lazy_static; -use serde_json::Value as JsonValue; - -pub mod identity; - -lazy_static! { - pub static ref BASE_TRANSITION_SCHEMA: JsonValue = serde_json::from_str(include_str!( - "./document/v0/stateTransition/documentTransition/base.json" - )) - .unwrap(); - pub static ref CREATE_TRANSITION_SCHEMA: JsonValue = serde_json::from_str(include_str!( - "./document/v0/stateTransition/documentTransition/create.json" - )) - .unwrap(); - pub static ref REPLACE_TRANSITION_SCHEMA: JsonValue = serde_json::from_str(include_str!( - "./document/v0/stateTransition/documentTransition/replace.json" - )) - .unwrap(); - pub static ref DOCUMENTS_BATCH_TRANSITIONS_SCHEMA: JsonValue = serde_json::from_str( - include_str!("./document/v0/stateTransition/documentsBatch.json") - ) - .unwrap(); -} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/from_document.rs index 3132a4ba07f..740d7a4b0ef 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/from_document.rs @@ -16,8 +16,14 @@ impl DocumentCreateTransitionV0 { platform_version: &PlatformVersion, base_feature_version: Option, ) -> Result { - let prefunded_voting_balance = - document_type.prefunded_voting_balance_for_document(&document, platform_version)?; + let prefunded_voting_balance = None; + + #[cfg(feature = "contested-documents")] + { + if let Some(vote_poll) = document_type.contested_vote_poll_for_document(&document) { + prefunded_voting_balance = Some(vote_poll); + } + } Ok(DocumentCreateTransitionV0 { base: DocumentBaseTransition::from_document( &document, diff --git a/packages/rs-dpp/src/util/deserializer.rs b/packages/rs-dpp/src/util/deserializer.rs index 301bdf24d27..9be4ff6bba3 100644 --- a/packages/rs-dpp/src/util/deserializer.rs +++ b/packages/rs-dpp/src/util/deserializer.rs @@ -6,23 +6,9 @@ use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; use integer_encoding::VarInt; use platform_version::version::FeatureVersion; -use serde_json::{Map, Number, Value as JsonValue}; use crate::errors::ProtocolError; -pub fn parse_protocol_version( - protocol_bytes: &[u8], - json_map: &mut Map, -) -> Result<(), ProtocolError> { - let protocol_version = get_protocol_version(protocol_bytes)?; - - json_map.insert( - String::from("$protocolVersion"), - JsonValue::Number(Number::from(protocol_version)), - ); - Ok(()) -} - /// A protocol version pub type ProtocolVersion = u32; diff --git a/packages/rs-dpp/src/util/json_schema.rs b/packages/rs-dpp/src/util/json_schema.rs index eaf8fb0d909..081460ea08a 100644 --- a/packages/rs-dpp/src/util/json_schema.rs +++ b/packages/rs-dpp/src/util/json_schema.rs @@ -26,6 +26,7 @@ pub trait JsonSchemaExt { fn is_type_of_identifier(&self) -> bool; } +// TODO: This is big (due to using regex inside?) pub fn resolve_uri<'a>(value: &'a Value, uri: &str) -> Result<&'a Value, DataContractError> { if !uri.starts_with("#/") { return Err(DataContractError::InvalidURI( diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 3a74c364001..6cfaa756a61 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -39,7 +39,10 @@ tracing = { version = "0.1.37", default-features = false, features = [] } clap = { version = "4.4.10", features = ["derive"] } envy = { version = "0.4.2" } dotenvy = { version = "0.15.7" } -dapi-grpc = { path = "../dapi-grpc", features = ["server"] } +dapi-grpc = { path = "../dapi-grpc", default-features = false, features = [ + "server", + "platform", +] } tracing-subscriber = { version = "0.3.16", default-features = false, features = [ "env-filter", "ansi", @@ -49,9 +52,10 @@ tracing-subscriber = { version = "0.3.16", default-features = false, features = "registry", "tracing-log", ], optional = false } -tenderdash-abci = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.2.1", tag = "v1.2.1+1.3.0", features = [ +tenderdash-abci = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.2.1", rev = "a558c0a2deab149183f125a012b14b709150401c", features = [ "grpc", ] } + lazy_static = "1.4.0" itertools = { version = "0.13" } file-rotate = { version = "0.7.3" } diff --git a/packages/rs-drive-abci/src/execution/engine/finalize_block_proposal/v0/mod.rs b/packages/rs-drive-abci/src/execution/engine/finalize_block_proposal/v0/mod.rs index ecfc3d6edf3..c8d71074316 100644 --- a/packages/rs-drive-abci/src/execution/engine/finalize_block_proposal/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/engine/finalize_block_proposal/v0/mod.rs @@ -9,7 +9,7 @@ use dpp::block::extended_block_info::v0::ExtendedBlockInfoV0; use dpp::version::PlatformVersion; use tenderdash_abci::{ - proto::{serializers::timestamp::ToMilis, types::BlockId as ProtoBlockId}, + proto::{types::BlockId as ProtoBlockId, ToMillis}, signatures::Hashable, }; @@ -195,7 +195,10 @@ where .expect("current epoch info should be in range"), ); - to_commit_block_info.time_ms = block_header.time.to_milis(); + to_commit_block_info.time_ms = block_header + .time + .to_millis() + .map_err(|e| AbciError::BadRequest(format!("invalid block time: {}", e)))?; to_commit_block_info.core_height = block_header.core_chain_locked_height; diff --git a/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/v0/mod.rs b/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/v0/mod.rs index b67cd012531..4e3bc0eb5bf 100644 --- a/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/v0/mod.rs @@ -1,3 +1,4 @@ +use crate::abci::AbciError; use crate::error::execution::ExecutionError; use crate::error::Error; use crate::platform_types::platform::Platform; @@ -18,7 +19,7 @@ use dpp::version::PlatformVersion; use std::sync::Arc; use tenderdash_abci::proto::abci::{RequestInitChain, ResponseInitChain}; use tenderdash_abci::proto::google::protobuf::Timestamp; -use tenderdash_abci::proto::serializers::timestamp::FromMilis; +use tenderdash_abci::proto::FromMillis; impl Platform where @@ -154,7 +155,12 @@ where validator_set_update: Some(validator_set), next_core_chain_lock_update: None, initial_core_height: core_height, // we send back the core height when the fork happens - genesis_time: Some(Timestamp::from_milis(genesis_time)), + genesis_time: Some(Timestamp::from_millis(genesis_time).map_err(|e| { + AbciError::InvalidChainLock(format!( + "chainlock contains invalid genesis time: {}", + e + )) + })?), }) } } diff --git a/packages/rs-drive-abci/src/mimic/mod.rs b/packages/rs-drive-abci/src/mimic/mod.rs index f0c5f895bca..0cf59e80e0f 100644 --- a/packages/rs-drive-abci/src/mimic/mod.rs +++ b/packages/rs-drive-abci/src/mimic/mod.rs @@ -34,11 +34,11 @@ use tenderdash_abci::proto::abci::{ ValidatorSetUpdate, }; use tenderdash_abci::proto::google::protobuf::Timestamp; -use tenderdash_abci::proto::serializers::timestamp::ToMilis; use tenderdash_abci::proto::types::{ Block, BlockId, CanonicalVote, Data, EvidenceList, Header, PartSetHeader, SignedMsgType, StateId, VoteExtension, VoteExtensionType, }; +use tenderdash_abci::proto::ToMillis; use tenderdash_abci::signatures::Hashable; use tenderdash_abci::{proto::version::Consensus, signatures::Signable, Application}; @@ -239,7 +239,9 @@ impl<'a, C: CoreRPCLike> FullAbciApplication<'a, C> { app_version, core_chain_locked_height: core_height, height, - time: time.to_milis(), + time: time + .to_millis() + .expect("expected to convert time to millis"), }; let state_id_hash = state_id .calculate_msg_hash(CHAIN_ID, height as i64, round as i32) diff --git a/packages/rs-drive-abci/src/platform_types/block_proposal/v0.rs b/packages/rs-drive-abci/src/platform_types/block_proposal/v0.rs index 7ed2273d95d..783dd18ace0 100644 --- a/packages/rs-drive-abci/src/platform_types/block_proposal/v0.rs +++ b/packages/rs-drive-abci/src/platform_types/block_proposal/v0.rs @@ -5,10 +5,12 @@ use dpp::dashcore::hashes::Hash; use dpp::dashcore::{BlockHash, ChainLock}; use dpp::platform_value::Bytes32; use std::fmt; -use tenderdash_abci::proto::abci::{RequestPrepareProposal, RequestProcessProposal}; -use tenderdash_abci::proto::serializers::timestamp::ToMilis; -use tenderdash_abci::proto::types::CoreChainLock; -use tenderdash_abci::proto::version::Consensus; +use tenderdash_abci::proto::{ + abci::{RequestPrepareProposal, RequestProcessProposal}, + types::CoreChainLock, + version::Consensus, + ToMillis, +}; /// The block proposal is the combination of information that a proposer will propose, /// Or that a validator or full node will process @@ -37,7 +39,7 @@ pub struct BlockProposal<'a> { pub raw_state_transitions: &'a Vec>, } -impl<'a> fmt::Debug for BlockProposal<'a> { +impl fmt::Debug for BlockProposal<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "BlockProposal {{")?; writeln!(f, " consensus_versions: {:?},", self.consensus_versions)?; @@ -96,18 +98,16 @@ impl<'a> TryFrom<&'a RequestPrepareProposal> for BlockProposal<'a> { version, quorum_hash, } = value; - let consensus_versions = version - .as_ref() - .ok_or(AbciError::BadRequest( - "request is missing version".to_string(), - ))? - .clone(); + let consensus_versions = version.as_ref().ok_or(AbciError::BadRequest( + "request is missing version".to_string(), + ))?; let block_time_ms = time .as_ref() .ok_or(AbciError::BadRequest( "request is missing block time".to_string(), ))? - .to_milis(); + .to_millis() + .map_err(|e| AbciError::BadRequest(format!("invalid block time: {}", e)))?; let proposer_pro_tx_hash: [u8; 32] = proposer_pro_tx_hash.clone().try_into().map_err(|e| { AbciError::BadRequestDataSize(format!( @@ -135,7 +135,7 @@ impl<'a> TryFrom<&'a RequestPrepareProposal> for BlockProposal<'a> { .into()); } Ok(Self { - consensus_versions, + consensus_versions: *consensus_versions, block_hash: None, height: *height as u64, round: *round as u32, @@ -171,18 +171,18 @@ impl<'a> TryFrom<&'a RequestProcessProposal> for BlockProposal<'a> { version, quorum_hash, } = value; - let consensus_versions = version - .as_ref() - .ok_or(AbciError::BadRequest( - "process proposal request is missing version".to_string(), - ))? - .clone(); + let consensus_versions = version.as_ref().ok_or(AbciError::BadRequest( + "process proposal request is missing version".to_string(), + ))?; let block_time_ms = time .as_ref() .ok_or(Error::Abci(AbciError::BadRequest( "missing proposal time".to_string(), )))? - .to_milis(); + .to_millis() + .map_err(|e| { + Error::Abci(AbciError::BadRequest(format!("invalid block time: {}", e))) + })?; let proposer_pro_tx_hash: [u8; 32] = proposer_pro_tx_hash.clone().try_into().map_err(|e| { Error::Abci(AbciError::BadRequestDataSize(format!( @@ -239,7 +239,7 @@ impl<'a> TryFrom<&'a RequestProcessProposal> for BlockProposal<'a> { }) .transpose()?; Ok(Self { - consensus_versions, + consensus_versions: *consensus_versions, block_hash: Some(block_hash), height: *height as u64, round: *round as u32, diff --git a/packages/rs-drive-abci/src/platform_types/cleaned_abci_messages/request_init_chain_cleaned_params/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/cleaned_abci_messages/request_init_chain_cleaned_params/v0/mod.rs index cccbfb02342..886aa1fd574 100644 --- a/packages/rs-drive-abci/src/platform_types/cleaned_abci_messages/request_init_chain_cleaned_params/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/cleaned_abci_messages/request_init_chain_cleaned_params/v0/mod.rs @@ -38,7 +38,7 @@ use dpp::util::deserializer::ProtocolVersion; use drive::dpp::identity::TimestampMillis; use serde::{Deserialize, Serialize}; use tenderdash_abci::proto::abci::RequestInitChain; -use tenderdash_abci::proto::serializers::timestamp::ToMilis; +use tenderdash_abci::proto::ToMillis; /// A struct for handling chain initialization requests #[derive(Serialize, Deserialize)] @@ -65,7 +65,9 @@ impl TryFrom for RequestInitChainCleanedParams { .ok_or(AbciError::BadRequest( "genesis time is required in init chain".to_string(), ))? - .to_milis() as TimestampMillis; + .to_millis() + .map_err(|e| AbciError::BadRequest(format!("genesis time is invalid: {}", e)))? + as TimestampMillis; let initial_core_height = match request.initial_core_height { 0 => None, h => Some(h), diff --git a/packages/rs-drive-abci/tests/strategy_tests/execution.rs b/packages/rs-drive-abci/tests/strategy_tests/execution.rs index d02a11e9500..64948002729 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/execution.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/execution.rs @@ -43,7 +43,7 @@ use std::collections::{BTreeMap, HashMap}; use tenderdash_abci::proto::abci::{ResponseInitChain, ValidatorSetUpdate}; use tenderdash_abci::proto::crypto::public_key::Sum::Bls12381; use tenderdash_abci::proto::google::protobuf::Timestamp; -use tenderdash_abci::proto::serializers::timestamp::FromMilis; +use tenderdash_abci::proto::FromMillis; use tenderdash_abci::Application; pub const GENESIS_TIME_MS: u64 = 1681094380000; @@ -1156,7 +1156,7 @@ pub(crate) fn continue_chain_for_strategy( height: state_id.height as i64, block_hash: &block_hash, app_hash: &root_app_hash, - time: Timestamp::from_milis(state_id.time), + time: Timestamp::from_millis(state_id.time).expect("must convert to millis"), signature: &signature, public_key: ¤t_quorum_with_test_info.public_key, }, diff --git a/packages/rs-drive-abci/tests/strategy_tests/query.rs b/packages/rs-drive-abci/tests/strategy_tests/query.rs index 56f166ab749..4a4103c4dbc 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/query.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/query.rs @@ -24,8 +24,8 @@ use rand::{Rng, SeedableRng}; use std::collections::HashMap; use strategy_tests::frequency::Frequency; use tenderdash_abci::proto::google::protobuf::Timestamp; -use tenderdash_abci::proto::serializers::timestamp::ToMilis; use tenderdash_abci::proto::types::{CanonicalVote, SignedMsgType, StateId}; +use tenderdash_abci::proto::ToMillis; use tenderdash_abci::signatures::{Hashable, Signable}; #[derive(Clone, Debug, Default)] @@ -72,7 +72,7 @@ pub struct ProofVerification<'a> { pub public_key: &'a dpp::bls_signatures::PublicKey, } -impl<'a> ProofVerification<'a> { +impl ProofVerification<'_> { /// Verify proof signature /// /// Constructs new signature for provided state ID and checks if signature is still valid. @@ -157,7 +157,7 @@ impl<'a> ProofVerification<'a> { app_version: self.app_version, core_chain_locked_height: self.core_chain_locked_height, height: self.height as u64, - time: self.time.to_milis(), + time: self.time.to_millis().expect("time as milliseconds"), }; self.verify_signature(state_id, proof.round) @@ -168,7 +168,7 @@ impl QueryStrategy { pub(crate) fn query_chain_for_strategy( &self, proof_verification: &ProofVerification, - current_identities: &Vec, + current_identities: &[Identity], abci_app: &FullAbciApplication, seed: StrategyRandomness, platform_version: &PlatformVersion, @@ -194,7 +194,7 @@ impl QueryStrategy { pub(crate) fn query_identities_by_public_key_hashes( proof_verification: &ProofVerification, - current_identities: &Vec, + current_identities: &[Identity], frequency: &Frequency, abci_app: &FullAbciApplication, rng: &mut StdRng, diff --git a/packages/rs-drive-proof-verifier/Cargo.toml b/packages/rs-drive-proof-verifier/Cargo.toml index 2b04a1e7aae..e001016c56f 100644 --- a/packages/rs-drive-proof-verifier/Cargo.toml +++ b/packages/rs-drive-proof-verifier/Cargo.toml @@ -4,16 +4,12 @@ version = "1.8.0-dev.2" edition = "2021" rust-version.workspace = true -crate-type = ["cdylib"] - [features] -default = ["mocks"] +default = [] mocks = [ "dep:serde", "dep:serde_json", - "dep:bincode", "dep:platform-serialization-derive", - "dep:platform-serialization", "dpp/document-serde-conversion", "indexmap/serde", ] @@ -21,20 +17,23 @@ mocks = [ [dependencies] thiserror = { version = "1.0.63" } -dapi-grpc = { path = "../dapi-grpc" } +dapi-grpc = { path = "../dapi-grpc", default-features = false, features = [ + "platform", +] } + drive = { path = "../rs-drive", default-features = false, features = [ "verify", ] } dpp = { path = "../rs-dpp", features = [ "bls-signatures", - "document-value-conversion", - "extended-document", + # "document-value-conversion", + # "extended-document", "core-types-serialization", ], default-features = false } -bincode = { version = "2.0.0-rc.3", features = ["serde"], optional = true } +bincode = { version = "2.0.0-rc.3", features = ["serde"] } platform-serialization-derive = { path = "../rs-platform-serialization-derive", optional = true } -platform-serialization = { path = "../rs-platform-serialization", optional = true } -tenderdash-abci = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.2.1", tag = "v1.2.1+1.3.0", features = [ +platform-serialization = { path = "../rs-platform-serialization" } +tenderdash-abci = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.2.1", rev = "a558c0a2deab149183f125a012b14b709150401c", features = [ "crypto", ], default-features = false } tracing = { version = "0.1.37" } diff --git a/packages/rs-drive-proof-verifier/src/types.rs b/packages/rs-drive-proof-verifier/src/types.rs index 40fa528a546..a482f6ddc12 100644 --- a/packages/rs-drive-proof-verifier/src/types.rs +++ b/packages/rs-drive-proof-verifier/src/types.rs @@ -35,10 +35,11 @@ use drive::grovedb::Element; pub use indexmap::IndexMap; use std::collections::{BTreeMap, BTreeSet}; +use dpp::dashcore::hashes::Hash; #[cfg(feature = "mocks")] use { bincode::{Decode, Encode}, - dpp::{dashcore::hashes::Hash, version as platform_version, ProtocolError}, + dpp::{version as platform_version, ProtocolError}, platform_serialization::{PlatformVersionEncode, PlatformVersionedDecode}, platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}, }; @@ -239,6 +240,7 @@ pub type IdentityBalanceAndRevision = (u64, Revision); #[derive(Debug, Clone, PartialEq)] pub struct ContestedResource(pub Value); +#[cfg(feature = "mocks")] impl ContestedResource { /// Get the value. pub fn encode_to_vec( diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index 2dccfca2570..a7df2394c70 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -26,7 +26,7 @@ indexmap = { version = "2.0.2" } sqlparser = { version = "0.38.0" } # used for int maps and needed in the verifier nohash-hasher = { version = "0.2.0" } -dpp = { path = "../rs-dpp", features = [ +dpp = { package = "dpp", path = "../rs-dpp", features = [ "state-transitions", ], default-features = false, optional = true } thiserror = { version = "1.0.63" } diff --git a/packages/rs-platform-value/Cargo.toml b/packages/rs-platform-value/Cargo.toml index a6a21119dc2..1b2fed1147f 100644 --- a/packages/rs-platform-value/Cargo.toml +++ b/packages/rs-platform-value/Cargo.toml @@ -18,8 +18,6 @@ serde = { version = "1.0.197", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"], optional = true } rand = { version = "0.8.4", features = ["small_rng"] } treediff = "5.0.0" -regex = "1.7.1" -lazy_static = "1.4.0" platform-serialization = { path = "../rs-platform-serialization" } platform-version = { path = "../rs-platform-version" } indexmap = "2.0.2" diff --git a/packages/rs-platform-value/src/inner_value.rs b/packages/rs-platform-value/src/inner_value.rs index c92828e91c0..d8606bd478b 100644 --- a/packages/rs-platform-value/src/inner_value.rs +++ b/packages/rs-platform-value/src/inner_value.rs @@ -361,7 +361,7 @@ impl Value { Self::inner_array_mut_ref(map, key) } - pub fn get_array_slice<'a>(&'a self, key: &'a str) -> Result<&[Value], Error> { + pub fn get_array_slice<'a>(&'a self, key: &'a str) -> Result<&'a [Value], Error> { let map = self.to_map()?; Self::inner_array_slice(map, key) } diff --git a/packages/rs-platform-value/src/inner_value_at_path.rs b/packages/rs-platform-value/src/inner_value_at_path.rs index d98dc7cc6b8..b117c20e715 100644 --- a/packages/rs-platform-value/src/inner_value_at_path.rs +++ b/packages/rs-platform-value/src/inner_value_at_path.rs @@ -1,28 +1,40 @@ use crate::value_map::ValueMapHelper; use crate::{error, Error, Value, ValueMap}; -use lazy_static::lazy_static; -use regex::Regex; use std::collections::BTreeMap; pub(crate) fn is_array_path(text: &str) -> Result)>, Error> { - lazy_static! { - static ref RE: Regex = Regex::new(r"(\w+)\[(\d+)?\]").unwrap(); + // 1. Find the last '[' character. + let Some(open_bracket_pos) = text.rfind('[') else { + return Ok(None); + }; + + // 2. Check if `text` ends with ']'. + if !text.ends_with(']') { + return Ok(None); } - RE.captures(text) - .map(|captures| { - Ok(( - captures.get(1).unwrap().as_str(), - captures - .get(2) - .map(|m| { - m.as_str() - .parse::() - .map_err(|_| Error::IntegerSizeError) - }) - .transpose()?, - )) - }) - .transpose() + + // 3. Extract the portion before the '[' as the field name. + let field_name = &text[..open_bracket_pos]; + + // 4. Ensure the field name consists only of word characters + if field_name.is_empty() || !field_name.chars().all(|c| c.is_alphanumeric() || c == '_') { + return Ok(None); + } + + // 5. Extract the portion inside the brackets. + let inside_brackets = &text[open_bracket_pos + 1..text.len() - 1]; + + // 6. If the inside is empty, there is no index number + if inside_brackets.is_empty() { + return Ok(Some((field_name, None))); + } + + // 7. Otherwise, parse the inside as a number (usize). + let index = inside_brackets + .parse::() + .map_err(|_| Error::IntegerSizeError)?; + + Ok(Some((field_name, Some(index)))) } impl Value { @@ -371,7 +383,8 @@ impl Value { } } #[cfg(test)] -mod test { +mod tests { + use super::*; use crate::platform_value; #[test] @@ -406,4 +419,76 @@ mod test { platform_value!("new_value") ); } + + mod is_array_path { + use super::*; + + #[test] + fn test_valid_no_index() { + let result = is_array_path("array[]"); + assert!(result.is_ok()); + let maybe_tuple = result.unwrap(); + assert!(maybe_tuple.is_some()); + let (field_name, index) = maybe_tuple.unwrap(); + assert_eq!(field_name, "array"); + assert_eq!(index, None); + } + + #[test] + fn test_valid_with_index() { + let result = is_array_path("arr[123]"); + assert!(result.is_ok()); + let maybe_tuple = result.unwrap(); + assert!(maybe_tuple.is_some()); + let (field_name, index) = maybe_tuple.unwrap(); + assert_eq!(field_name, "arr"); + assert_eq!(index, Some(123)); + } + + #[test] + fn test_no_brackets() { + let result = is_array_path("no_brackets"); + assert!(result.is_ok()); + assert!(result.unwrap().is_none()); + } + + #[test] + fn test_missing_closing_bracket() { + let result = is_array_path("array["); + assert!(result.is_ok()); + assert!(result.unwrap().is_none()); + } + + #[test] + fn test_non_alphanumeric_field() { + let result = is_array_path("arr-test[123]"); + assert!(result.is_ok()); + assert!(result.unwrap().is_none()); + } + + #[test] + fn test_empty_field_name() { + let result = is_array_path("[123]"); + assert!(result.is_ok()); + assert!(result.unwrap().is_none()); + } + + #[test] + fn test_non_numeric_index() { + let result = is_array_path("array[abc]"); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), Error::IntegerSizeError); + } + + #[test] + fn test_empty_index() { + let result = is_array_path("array[]"); + assert!(result.is_ok()); + let maybe_tuple = result.unwrap(); + assert!(maybe_tuple.is_some()); + let (field_name, index) = maybe_tuple.unwrap(); + assert_eq!(field_name, "array"); + assert_eq!(index, None); + } + } } diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index 86da12f24ef..1be9978ede2 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -6,22 +6,24 @@ edition = "2021" [dependencies] arc-swap = { version = "1.7.1" } -backon = { version = "1.2", features = ["tokio-sleep"] } +backon = { version = "1.2", default-features = false } chrono = { version = "0.4.38" } dpp = { path = "../rs-dpp", default-features = false, features = [ "dash-sdk-features", ] } -dapi-grpc = { path = "../dapi-grpc" } + +dapi-grpc = { path = "../dapi-grpc", default-features = false } rs-dapi-client = { path = "../rs-dapi-client", default-features = false } drive = { path = "../rs-drive", default-features = false, features = [ "verify", ] } -drive-proof-verifier = { path = "../rs-drive-proof-verifier" } + +drive-proof-verifier = { path = "../rs-drive-proof-verifier", default-features = false } dapi-grpc-macros = { path = "../rs-dapi-grpc-macros" } http = { version = "1.1" } rustls-pemfile = { version = "2.0.0" } thiserror = "1.0.64" -tokio = { version = "1.40", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.40", features = ["macros", "time"] } tokio-util = { version = "0.7.12" } async-trait = { version = "0.1.83" } ciborium = { git = "https://github.com/qrayven/ciborium", branch = "feat-ser-null-as-undefined" } @@ -41,9 +43,13 @@ lru = { version = "0.12.5", optional = true } bip37-bloom-filter = { git = "https://github.com/dashpay/rs-bip37-bloom-filter", branch = "develop" } zeroize = { version = "1.8", features = ["derive"] } +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +tokio = { version = "1.40", features = ["macros", "time", "rt-multi-thread"] } + [dev-dependencies] +rs-dapi-client = { path = "../rs-dapi-client" } +drive-proof-verifier = { path = "../rs-drive-proof-verifier" } tokio = { version = "1.40", features = ["macros", "rt-multi-thread"] } -rs-dapi-client = { path = "../rs-dapi-client", features = ["mocks"] } base64 = { version = "0.22.1" } tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } dpp = { path = "../rs-dpp", features = [ @@ -54,12 +60,12 @@ dpp = { path = "../rs-dpp", features = [ data-contracts = { path = "../data-contracts" } tokio-test = { version = "0.4.4" } clap = { version = "4.5.4", features = ["derive"] } -sanitize-filename = { version = "0.5.0" } +sanitize-filename = { version = "0.6.0" } test-case = { version = "3.3.1" } assert_matches = "1.5.0" [features] -default = ["mocks", "offline-testing"] +default = ["mocks", "offline-testing", "dapi-grpc/client"] mocks = [ "dep:serde", @@ -107,3 +113,6 @@ system-data-contracts = ["dpp/data-contracts"] name = "read_contract" required-features = ["mocks"] + +[lib] +crate-type = ["cdylib", "rlib"] diff --git a/packages/rs-sdk/src/platform/transition/broadcast_identity.rs b/packages/rs-sdk/src/platform/transition/broadcast_identity.rs index 5bce4205cfe..dd38a1ce1a5 100644 --- a/packages/rs-sdk/src/platform/transition/broadcast_identity.rs +++ b/packages/rs-sdk/src/platform/transition/broadcast_identity.rs @@ -10,6 +10,7 @@ use std::fmt::Debug; use dapi_grpc::platform::v0::{self as proto, BroadcastStateTransitionRequest}; use dpp::dashcore::PrivateKey; use dpp::identity::signer::Signer; +#[cfg(not(target_arch = "wasm32"))] use dpp::native_bls::NativeBlsModule; use dpp::prelude::{AssetLockProof, Identity}; use dpp::state_transition::identity_create_transition::methods::IdentityCreateTransitionMethodsV0; @@ -104,16 +105,22 @@ impl BroadcastRequestForNewIdentity Result<(StateTransition, BroadcastStateTransitionRequest), Error> { - let identity_create_transition = IdentityCreateTransition::try_from_identity_with_signer( - self, - asset_lock_proof, - asset_lock_proof_private_key.inner.as_ref(), - signer, - &NativeBlsModule, - 0, - platform_version, - )?; - let request = identity_create_transition.broadcast_request_for_state_transition()?; - Ok((identity_create_transition, request)) + #[cfg(target_arch = "wasm32")] + unimplemented!("NativeBlsModule not implemented for wasm32"); + #[cfg(not(target_arch = "wasm32"))] + { + let identity_create_transition = + IdentityCreateTransition::try_from_identity_with_signer( + self, + asset_lock_proof, + asset_lock_proof_private_key.inner.as_ref(), + signer, + &NativeBlsModule, + 0, + platform_version, + )?; + let request = identity_create_transition.broadcast_request_for_state_transition()?; + Ok((identity_create_transition, request)) + } } } diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 64a5db66457..74fbd6ff468 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -10,6 +10,7 @@ use crate::platform::{Fetch, Identifier}; use arc_swap::{ArcSwapAny, ArcSwapOption}; use dapi_grpc::mock::Mockable; use dapi_grpc::platform::v0::{Proof, ResponseMetadata}; +#[cfg(not(target_arch = "wasm32"))] use dapi_grpc::tonic::transport::Certificate; use dpp::bincode; use dpp::bincode::error::DecodeError; @@ -36,6 +37,7 @@ use std::fmt::Debug; use std::num::NonZeroUsize; #[cfg(feature = "mocks")] use std::path::{Path, PathBuf}; +use std::str::FromStr; use std::sync::atomic::Ordering; use std::sync::{atomic, Arc}; use std::time::{SystemTime, UNIX_EPOCH}; @@ -274,6 +276,7 @@ impl Sdk { Ok(()) } + // TODO: Changed to public for tests /// Retrieve object `O` from proof contained in `request` (of type `R`) and `response`. /// /// This method is used to retrieve objects from proofs returned by Dash Platform. @@ -539,11 +542,14 @@ impl Sdk { } } + // TODO: Move to settings /// Indicate if the sdk should request and verify proofs. pub fn prove(&self) -> bool { self.proofs } + // TODO: If we remove this setter we don't need to use ArcSwap. + // It's good enough to set Context once when you initialize the SDK. /// Set the [ContextProvider] to use. /// /// [ContextProvider] is used to access state information, like data contracts and quorum public keys. @@ -753,6 +759,7 @@ pub struct SdkBuilder { pub(crate) cancel_token: CancellationToken, /// CA certificate to use for TLS connections. + #[cfg(not(target_arch = "wasm32"))] ca_certificate: Option, } @@ -784,7 +791,7 @@ impl Default for SdkBuilder { cancel_token: CancellationToken::new(), version: PlatformVersion::latest(), - + #[cfg(not(target_arch = "wasm32"))] ca_certificate: None, #[cfg(feature = "mocks")] @@ -822,10 +829,19 @@ impl SdkBuilder { /// /// This is a helper method that preconfigures [SdkBuilder] for production use. /// Use this method if you want to connect to Dash Platform mainnet with production-ready product. + /// + /// ## Panics + /// + /// This method panics if the mainnet configuration cannot be loaded. + /// + /// ## Unstable + /// + /// This method is unstable and can be changed in the future. pub fn new_mainnet() -> Self { - unimplemented!( - "Mainnet address list not implemented yet. Use new() and provide address list." - ) + // TODO this is just some test mainnet node, we need to implement proper lookup of nodes + let addresses = AddressList::from_str("https://34.223.102.43:443") + .expect("hardcoded mainnet addresses must be valid"); + Self::new(addresses).with_network(Network::Dash) } /// Configure network type. @@ -841,6 +857,7 @@ impl SdkBuilder { /// Used mainly for testing purposes and local networks. /// /// If not set, uses standard system CA certificates. + #[cfg(not(target_arch = "wasm32"))] pub fn with_ca_certificate(mut self, pem_certificate: Certificate) -> Self { self.ca_certificate = Some(pem_certificate); self @@ -850,6 +867,7 @@ impl SdkBuilder { /// /// This is a convenience method that reads the certificate from a file and sets it using /// [SdkBuilder::with_ca_certificate()]. + #[cfg(not(target_arch = "wasm32"))] pub fn with_ca_certificate_file( self, certificate_file_path: impl AsRef, @@ -1003,7 +1021,9 @@ impl SdkBuilder { let sdk= match self.addresses { // non-mock mode Some(addresses) => { + #[allow(unused_mut)] // needs to be mutable for features other than wasm let mut dapi = DapiClient::new(addresses, dapi_client_settings); + #[cfg(not(target_arch = "wasm32"))] if let Some(pem) = self.ca_certificate { dapi = dapi.with_ca_certificate(pem); } diff --git a/packages/rs-sdk/src/sync.rs b/packages/rs-sdk/src/sync.rs index 5f5d2666699..14a74acadd8 100644 --- a/packages/rs-sdk/src/sync.rs +++ b/packages/rs-sdk/src/sync.rs @@ -15,13 +15,14 @@ use std::{ future::Future, sync::{mpsc::SendError, Arc}, }; -use tokio::{runtime::TryCurrentError, sync::Mutex}; +use tokio::sync::Mutex; #[derive(Debug, thiserror::Error)] pub enum AsyncError { /// Not running inside tokio runtime + #[cfg(not(target_arch = "wasm32"))] #[error("not running inside tokio runtime: {0}")] - NotInTokioRuntime(#[from] TryCurrentError), + NotInTokioRuntime(#[from] tokio::runtime::TryCurrentError), /// Cannot receive response from async function #[error("cannot receive response from async function: {0}")] @@ -61,6 +62,7 @@ impl From for crate::Error { /// /// Due to limitations of tokio runtime, we cannot use `tokio::runtime::Runtime::block_on` if we are already inside a tokio runtime. /// This function is a workaround for that limitation. +#[cfg(not(target_arch = "wasm32"))] pub fn block_on(fut: F) -> Result where F: Future + Send + 'static, @@ -83,6 +85,15 @@ where Ok(resp) } +#[cfg(target_arch = "wasm32")] +pub fn block_on(_fut: F) -> Result +where + F: Future + Send + 'static, + F::Output: Send, +{ + unimplemented!("block_on is not supported in wasm"); +} + /// Worker function that runs the provided future and sends the result back to the caller using oneshot channel. async fn worker( fut: F, @@ -229,6 +240,7 @@ where false } }) + .sleep(rs_dapi_client::transport::BackonSleeper::default()) .notify(|error, duration| { tracing::warn!(?duration, ?error, "request failed, retrying"); }) @@ -244,7 +256,6 @@ where mod test { use super::*; use derive_more::Display; - use http::Uri; use rs_dapi_client::ExecutionError; use std::{ future::Future, diff --git a/packages/wasm-dpp/Cargo.toml b/packages/wasm-dpp/Cargo.toml index 40ce329f2ce..8411d641794 100644 --- a/packages/wasm-dpp/Cargo.toml +++ b/packages/wasm-dpp/Cargo.toml @@ -6,7 +6,7 @@ rust-version.workspace = true authors = ["Anton Suprunchuk "] [lib] -crate-type = ["cdylib"] +crate-type = ["cdylib", "rlib"] [dependencies] serde = { version = "1.0.197", features = ["derive"] } diff --git a/packages/wasm-dpp/scripts/build-wasm.sh b/packages/wasm-dpp/scripts/build-wasm.sh index b7ada5425ef..4dd833c452f 100755 --- a/packages/wasm-dpp/scripts/build-wasm.sh +++ b/packages/wasm-dpp/scripts/build-wasm.sh @@ -49,7 +49,7 @@ fi if command -v wasm-opt &> /dev/null; then echo "Optimizing wasm using Binaryen" - wasm-opt -Oz "$OUTPUT_FILE" -o "$OUTPUT_FILE" + wasm-opt -tnh --flatten --rereloop -Oz --gufa -Oz --gufa -Oz "$OUTPUT_FILE" -o "$OUTPUT_FILE" else echo "wasm-opt command not found. Skipping wasm optimization." fi diff --git a/packages/wasm-sdk/Cargo.toml b/packages/wasm-sdk/Cargo.toml new file mode 100644 index 00000000000..3b0d525fd80 --- /dev/null +++ b/packages/wasm-sdk/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "wasm-sdk" +version = "0.1.0" +edition = "2021" +rust-version.workspace = true +publish = false +[lib] +crate-type = ["cdylib"] + +[dependencies] +dash-sdk = { path = "../rs-sdk", default-features = false } +console_error_panic_hook = { version = "0.1.6" } +thiserror = { version = "2.0.9" } +web-sys = { version = "0.3.4", features = [ + 'console', + 'Document', + 'Element', + 'HtmlElement', + 'Node', + 'Window', +] } +wasm-bindgen = { version = "=0.2.99" } +wasm-bindgen-futures = { version = "0.4.49" } +drive-proof-verifier = { path = "../rs-drive-proof-verifier" } # TODO: I think it's not needed (LKl) +# tonic = { version = "*", features = ["transport"], default-features = false } +# client = [ +# "tonic/channel", FAIL +# "tonic/transport", FAIL +# "tonic/tls", +# "tonic/tls-roots", +# "tonic/tls-webpki-roots", +# "platform", +# ] +tracing-wasm = { version = "0.2.1" } +wee_alloc = "0.4" +platform-value = { path = "../rs-platform-value", features = ["json"] } +serde-wasm-bindgen = { version = "0.6.5" } + +[profile.release] +lto = "fat" +opt-level = "z" +panic = "abort" +debug = false + +#[package.metadata.wasm-pack.profile.release] +#wasm-opt = ['-g', '-O'] # -g for profiling +# -Oz -Oz -g diff --git a/packages/wasm-sdk/index.html b/packages/wasm-sdk/index.html new file mode 100644 index 00000000000..f871a8566f5 --- /dev/null +++ b/packages/wasm-sdk/index.html @@ -0,0 +1,85 @@ + + + + + + + + + +
Loading...
+
+ + +
+ +
+ + +
+
+ + + + + diff --git a/packages/wasm-sdk/src/context_provider.rs b/packages/wasm-sdk/src/context_provider.rs new file mode 100644 index 00000000000..173c8a4948b --- /dev/null +++ b/packages/wasm-sdk/src/context_provider.rs @@ -0,0 +1,101 @@ +use std::sync::Arc; + +use dash_sdk::{ + dpp::{ + prelude::CoreBlockHeight, + util::vec::{decode_hex, encode_hex}, + }, + error::ContextProviderError, + platform::{DataContract, Identifier}, +}; +use drive_proof_verifier::ContextProvider; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +pub struct WasmContext {} +/// Quorum keys for the testnet +/// This is a hardcoded list of quorum keys for the testnet. +/// This list was generated using the following script: +/// ```bash +// #!/bin/bash +/// function dash-cli() { +/// docker exec -ti dashmate_2d59c0c6_mainnet-core-1 dash-cli $@ +/// } +/// +/// +/// # Get the list of all quorum hashes +/// quorum_hashes=$(dash-cli quorum list | jq -r '.llmq_100_67[]') +/// +/// count=$(wc -w <<< $quorum_hashes) +/// +/// echo "const QUORUM_KEYS: [&str; $count] = [" +/// # Iterate over each quorum hash and get the respective public key +/// for quorum_hash in $quorum_hashes; do +/// quorum_public_key=$(dash-cli quorum info 4 $quorum_hash | jq -r '.quorumPublicKey') +/// echo "\"$quorum_hash:$quorum_public_key\"," +/// done +/// echo "]; +/// ``` +const QUORUM_KEYS: [&str; 24] = [ + "0000000000000010c832afa3f737b24aa0a19cb8c5fa8a7ebd51d195965c204e:a7123c10b0083c96665954dacbc92779b9bf5ee15b6e0b37de6c3ac6b5e611490611fbdf8128ea8012e1b8d79faf70e1", + "000000000000000b7ef1903452e3a0234b893567fe4f0f093b0de655756e413d:a75bca441f781fde0ae048181ab64e5bc85a2541b25267148bced1d1cbc1ff223e9b0d767f06b4a0773b65a7f374f72d", + "000000000000000aaf16a867b579ddbafc421ebf52b991c445aba9d42cc70f62:9665f284f989b998c053e4d34d022d7a9c1744214356150b6b815ba0c4b28dd6312ff3f6d86eb2ab49d84cb2a20518c5", + "00000000000000097177f56b1d83fcaa96101cb3c5e5cc1e624422552265aab0:ab96113d539e30e7f8f1ec605ab9228b6825bef1ea55cdf66826bb8308edf92fa782db1c3c6c348fb2daf5e13422fdff", + "00000000000000210518749e17c00b035a2a4982c906236c28c41ea2231bf7ef:803c3341a037217c6b8d6bf9a1f08b140749039fcbf2bd79d639ee6d70b16c9911f979e6f7014429d1a805876a9cb8dd", + "000000000000000d9085a108ae45615da3fc0b43313959a7fde892bb307d4f6a:ab880781c7ef1b5a38202065a90afc92ff25009f231a16daa766528bf36b78856d2a9a35c4d396326df434eb09fb3897", + "000000000000001871d3dab13ccefca7dd9735c27028e6612e8f1ac16114b080:ae5334bc41a2a2b1b52c8c454957f00a4554fb0ec82e7ca61b9391a4371346ab4679b55a15220af7ea657e153af867be", + "00000000000000223578d6be39205e0cddd36a0c73cde66aee0a7ad4bf451931:986eb45b5cd503f6ae09070b93fbf101ac69999147cce55a2f1f4b04b2aaf0ad7ea57ea96ee3f4335bcdd13dce6577f6", + "000000000000000208d59d5275610de33bca248e4055974573775affb2d99b0a:b4c419af96d4a053e90c6cc3be88c09f47543a8af9b5e94f0e345f91604843a60d8b19d045908b22ce52084f82f3a627", + "00000000000000065644145a3a5f94f9786245f4242a09fadfe277de7059b44a:95bebdad569bfe6c870f6f96c6a5d265f2d8561997b2a8be2d3192ad16ee872b833593a8096d8d7b142ba6ba2f662147", + "000000000000000ab82df09faf91a3e07b756dfc715c309a21feca21dd233559:91ebfc1415bf0e87e88024a1a794735130b8b438abdd29313f26bb3dece7577f77c80b0103a6c97c9a888f8e4334f44a", + "0000000000000023b4287203df6f4e1e67726b4f9bbeeec96a3b2e47227bcf7c:b1cc46b8d00f193238550b035860994e95c1515d95ef675c890bf38257dfc44631cc1da786550c1df7bda83dea17299c", + "000000000000000dd6431b32390b87c7c3c2377c46ecb8be2e36e0625400204b:a84f43efe056cd1221b9d4449dc3d0b3ce2e260f6378790f3e6123903d204ae83589e5a144533eb556acd05f920869a6", + "0000000000000005609c7e47752ff16847a49bd81f12885d3047c26c1d4de394:8f08f63fdd26e3e15f4c6daf45943c6ae097a40f46f4344cea63bcdfa9498525cfe0891c9d04057692738fa8f5e7b30d", + "000000000000001fb29b450739378551cd7539357e0ee49fd93c186eb8dd9db4:8cc74c3c7f10dd11845894dafafe47e60395d40bb151299638736dd078cc1052da13b3676e945d84cd4139a519a37975", + "0000000000000005f3b003f2b70096157046005944b316950c2d6f31a7fbdb6c:82780a7c99e2e09589a42a38e7be3d78d53072b09d964762cd9025b5b0b88bbed7e9e6c294a4fc8310d5025668240eaa", + "000000000000001f7bdf487d9ab675b9d4c53d8601b2b9dd619cf6f91271c1ef:ac79a22006a9c5d96250bd91784919a65259b5e1cf72af8294a998a420684ab3b9064094f247b0ebf1c5e39a545ac176", + "00000000000000127ae21d0e85ab8f511309b3492a689e680872d05d3d5e27b9:887332518d8a6d8806dfb1dd9588d2d4a2ec80193b5357ed87fc49567a72752ec8022dfaf4f5dec22c85aff4139daeb3", + "000000000000001c5d877e4b2b5964277c71377acd0e83d2b949426b54b761a2:a7149631eed0fdef466de0360ae09700b96fc29e76d46465efe60677596e7f93f8ff5e5e39917e04a3a26febe12b3b8a", + "000000000000000dab4691b25d967682b1902c05eefe691312cf520f6f2a3063:acc45cbf3ead9a04347438a68d72f86ffec76211562786f86125bbc2a444026343149cfb3d21fd27b386b50094250099", + "000000000000001aad53ced4755062f69421f7ca6c0bbe259e2626738c310759:8037c5282d443eb274a819a1d83758b29a97c12fdbbfa65a255e460045e71d9a5301f96ae76743787b12edf4f4e79e1c", + "0000000000000003e9cc2a59ebbede397e73e951f0968d4c94e04a92edb5586f:a62305e5154688adcc129da4a11bd0da388a731e52a361896f27473056d4dccb3642526086f83f36accbcaea43468121", + "000000000000001fd65c58acf87be67925c89348c5a76cc61cb467bbd9991a80:818283cbc34445f0c294d8ac071d4e43099fd318dad53337cd1daccc8a2aa760ee108c80f3f3c5bb01c41bba69ab2e8b", + "0000000000000028113a56cdec51df03d0a4786886455b56c405888820ef0941:a9cc0b5debb51078cc74666ce230512b5cc8a210e92e7a61143a94f2d39e0f2396fdb8a236f9e4f08bb9f9efade56aa0", +]; + +impl ContextProvider for WasmContext { + fn get_quorum_public_key( + &self, + _quorum_type: u32, + quorum_hash: [u8; 32], + _core_chain_locked_height: u32, + ) -> Result<[u8; 48], ContextProviderError> { + let quorum_label = encode_hex(&quorum_hash) + ":"; + let key_hex = QUORUM_KEYS + .iter() + .find(|key| key.starts_with(&quorum_label)) + .ok_or(ContextProviderError::InvalidQuorum(format!( + "key for quorum {:?} not found in hardcoded dictionary", + &quorum_label[0..quorum_label.len() - 1] + )))?; + let key = decode_hex(&key_hex[quorum_label.len()..]) + .map_err(|e| ContextProviderError::InvalidQuorum(e.to_string()))? + .try_into() + .map_err(|_e| { + ContextProviderError::InvalidQuorum("invalid quorum key size".to_string()) + })?; + + Ok(key) + } + + fn get_data_contract( + &self, + _id: &Identifier, + ) -> Result>, ContextProviderError> { + todo!() + } + + fn get_platform_activation_height(&self) -> Result { + todo!() + } +} diff --git a/packages/wasm-sdk/src/dpp.rs b/packages/wasm-sdk/src/dpp.rs new file mode 100644 index 00000000000..678f2c23b56 --- /dev/null +++ b/packages/wasm-sdk/src/dpp.rs @@ -0,0 +1,313 @@ +use dash_sdk::dpp::identity::accessors::{IdentityGettersV0, IdentitySettersV0}; +use dash_sdk::dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; +use dash_sdk::dpp::identity::{IdentityPublicKey, KeyID}; +use dash_sdk::dpp::metadata::Metadata; +use dash_sdk::dpp::platform_value::ReplacementType; +use dash_sdk::dpp::serialization::PlatformDeserializable; +use dash_sdk::dpp::serialization::PlatformSerializable; +use dash_sdk::dpp::serialization::ValueConvertible; + +use crate::error::{to_js_error, WasmError}; +use dash_sdk::dashcore_rpc::dashcore::hashes::serde::Serialize; +use dash_sdk::dpp::data_contract::accessors::v0::DataContractV0Getters; +use dash_sdk::dpp::data_contract::conversion::json::DataContractJsonConversionMethodsV0; +use dash_sdk::dpp::version::PlatformVersion; +use dash_sdk::platform::{DataContract, Identity}; +use dash_sdk::Error; +use platform_value::string_encoding::Encoding; +use wasm_bindgen::prelude::*; +use wasm_bindgen::JsValue; +use web_sys::js_sys; + +#[wasm_bindgen] +#[derive(Clone)] +pub struct IdentityWasm { + inner: Identity, + // metadata: Option, +} + +impl From for Identity { + fn from(identity: IdentityWasm) -> Self { + identity.inner + } +} + +impl From for IdentityWasm { + fn from(identity: Identity) -> Self { + Self { + inner: identity, + // metadata: None, + } + } +} +#[wasm_bindgen] +impl IdentityWasm { + #[wasm_bindgen(constructor)] + pub fn new(platform_version: u32) -> Result { + let platform_version = &PlatformVersion::get(platform_version).map_err(to_js_error)?; + + Identity::default_versioned(platform_version) + .map(Into::into) + .map_err(to_js_error) + } + // + // #[wasm_bindgen(js_name=getId)] + // pub fn get_id(&self) -> IdentifierWrapper { + // self.inner.id().into() + // } + // + // #[wasm_bindgen(js_name=setId)] + // pub fn set_id(&mut self, id: IdentifierWrapper) { + // self.inner.set_id(id.into()); + // } + + #[wasm_bindgen(js_name=setPublicKeys)] + pub fn set_public_keys(&mut self, public_keys: js_sys::Array) -> Result { + if public_keys.length() == 0 { + return Err(format!("Setting public keys failed. The input ('{}') is invalid. You must use array of PublicKeys", public_keys.to_string()).into()); + } + + // let public_keys = public_keys + // .iter() + // .map(|key| { + // key.to_wasm::("IdentityPublicKey") + // .map(|key| { + // let key = IdentityPublicKey::from(key.to_owned()); + // (key.id(), key) + // }) + // }) + // .collect::>()?; + // + // self.inner.set_public_keys(public_keys); + + Ok(self.inner.public_keys().len()) + } + // + // #[wasm_bindgen(js_name=getPublicKeys)] + // pub fn get_public_keys(&self) -> Vec { + // self.inner + // .public_keys() + // .iter() + // .map(|(_, k)| k.to_owned()) + // .map(IdentityPublicKeyWasm::from) + // .map(JsValue::from) + // .collect() + // } + // + // #[wasm_bindgen(js_name=getPublicKeyById)] + // pub fn get_public_key_by_id(&self, key_id: u32) -> Option { + // let key_id = key_id as KeyID; + // self.inner + // .get_public_key_by_id(key_id) + // .map(IdentityPublicKey::to_owned) + // .map(Into::into) + // } + + #[wasm_bindgen(getter)] + pub fn balance(&self) -> f64 { + self.inner.balance() as f64 + } + + #[wasm_bindgen(js_name=getBalance)] + pub fn get_balance(&self) -> f64 { + self.inner.balance() as f64 + } + + #[wasm_bindgen(js_name=setBalance)] + pub fn set_balance(&mut self, balance: f64) { + self.inner.set_balance(balance as u64); + } + + #[wasm_bindgen(js_name=increaseBalance)] + pub fn increase_balance(&mut self, amount: f64) -> f64 { + self.inner.increase_balance(amount as u64) as f64 + } + + #[wasm_bindgen(js_name=reduceBalance)] + pub fn reduce_balance(&mut self, amount: f64) -> f64 { + self.inner.reduce_balance(amount as u64) as f64 + } + + #[wasm_bindgen(js_name=setRevision)] + pub fn set_revision(&mut self, revision: f64) { + self.inner.set_revision(revision as u64); + } + + #[wasm_bindgen(js_name=getRevision)] + pub fn get_revision(&self) -> f64 { + self.inner.revision() as f64 + } + // + // #[wasm_bindgen(js_name=setMetadata)] + // pub fn set_metadata(&mut self, metadata: JsValue) -> Result<(), JsValue> { + // if !metadata.is_falsy() { + // let metadata = metadata.to_wasm::("Metadata")?.to_owned(); + // self.metadata = Some(metadata.into()); + // } + // + // Ok(()) + // } + // + // #[wasm_bindgen(js_name=getMetadata)] + // pub fn get_metadata(&self) -> Option { + // self.metadata.map(|metadata| metadata.to_owned().into()) + // } + + // #[wasm_bindgen(js_name=from)] + // pub fn from(object: JsValue) -> Self { + // let i: Identity = serde_json::from_str(&object.as_string().unwrap()).unwrap(); + // IdentityWasm { + // inner: i, + // metadata: None, + // } + // } + + #[wasm_bindgen(js_name=toJSON)] + pub fn to_json(&self) -> Result { + let mut value = self.inner.to_object().map_err(to_js_error)?; + + value + .replace_at_paths( + dash_sdk::dpp::identity::IDENTIFIER_FIELDS_RAW_OBJECT, + ReplacementType::TextBase58, + ) + .map_err(|e| e.to_string())?; + + // Monkey patch public keys data to be deserializable + let public_keys = value + .get_array_mut_ref(dash_sdk::dpp::identity::property_names::PUBLIC_KEYS) + .map_err(|e| e.to_string())?; + + for key in public_keys.iter_mut() { + key.replace_at_paths( + dash_sdk::dpp::identity::identity_public_key::BINARY_DATA_FIELDS, + ReplacementType::TextBase64, + ) + .map_err(|e| e.to_string())?; + } + + let json = value + .try_into_validating_json() + .map_err(|e| e.to_string())? + .to_string(); + + js_sys::JSON::parse(&json) + } + // + // #[wasm_bindgen(js_name=toObject)] + // pub fn to_object(&self) -> Result { + // let js_public_keys = js_sys::Array::new(); + // for pk in self.inner.public_keys().values() { + // let pk_wasm = IdentityPublicKeyWasm::from(pk.to_owned()); + // js_public_keys.push(&pk_wasm.to_object()?); + // } + // + // let value = self.inner.to_object().with_js_error()?; + // + // let serializer = serde_wasm_bindgen::Serializer::json_compatible(); + // let js_object = with_js_error!(value.serialize(&serializer))?; + // + // let id = Buffer::from_bytes(self.inner.id().as_slice()); + // + // js_sys::Reflect::set(&js_object, &"id".to_owned().into(), &id)?; + // + // js_sys::Reflect::set( + // &js_object, + // &"publicKeys".to_owned().into(), + // &JsValue::from(&js_public_keys), + // )?; + // + // Ok(js_object) + // } + // + // #[wasm_bindgen(js_name=toBuffer)] + // pub fn to_buffer(&self) -> Result { + // let bytes = + // PlatformSerializable::serialize_to_bytes(&self.inner.clone()).with_js_error()?; + // Ok(Buffer::from_bytes(&bytes)) + // } + + #[wasm_bindgen] + pub fn hash(&self) -> Result, JsError> { + self.inner.hash().map_err(to_js_error) + } + + // #[wasm_bindgen(js_name=addPublicKey)] + // pub fn add_public_key(&mut self, public_key: IdentityPublicKeyWasm) { + // self.inner + // .public_keys_mut() + // .insert(public_key.get_id(), public_key.into()); + // } + // + // #[wasm_bindgen(js_name=addPublicKeys)] + // pub fn add_public_keys(&mut self, public_keys: js_sys::Array) -> Result<(), JsValue> { + // if public_keys.length() == 0 { + // return Err(format!("Setting public keys failed. The input ('{}') is invalid. You must use array of PublicKeys", public_keys.to_string()).into()); + // } + // + // let public_keys: Vec = public_keys + // .iter() + // .map(|key| { + // key.to_wasm::("IdentityPublicKey") + // .map(|key| key.to_owned().into()) + // }) + // .collect::>()?; + // + // self.inner.add_public_keys(public_keys); + // + // Ok(()) + // } + + #[wasm_bindgen(js_name=getPublicKeyMaxId)] + pub fn get_public_key_max_id(&self) -> f64 { + self.inner.get_public_key_max_id() as f64 + } + + #[wasm_bindgen(js_name=fromBuffer)] + pub fn from_buffer(buffer: Vec) -> Result { + let identity: Identity = PlatformDeserializable::deserialize_from_bytes(buffer.as_slice()) + .map_err(to_js_error)?; + Ok(identity.into()) + } +} +// +// impl Inner for IdentityWasm { +// type InnerItem = Identity; +// +// fn into_inner(self) -> Self::InnerItem { +// self.inner +// } +// +// fn inner(&self) -> &Self::InnerItem { +// &self.inner +// } +// +// fn inner_mut(&mut self) -> &mut Self::InnerItem { +// &mut self.inner +// } +// } + +#[wasm_bindgen] +pub struct DataContractWasm(DataContract); + +impl From for DataContractWasm { + fn from(value: DataContract) -> Self { + Self(value) + } +} + +#[wasm_bindgen] +impl DataContractWasm { + pub fn id(&self) -> String { + self.0.id().to_string(Encoding::Base58) + } + + #[wasm_bindgen(js_name=toJSON)] + pub fn to_json(&self) -> Result { + let platform_version = PlatformVersion::first(); + + let json = self.0.to_json(platform_version)?; + let serializer = ::serde_wasm_bindgen::Serializer::json_compatible(); + json.serialize(&serializer).map_err(to_js_error) + } +} diff --git a/packages/wasm-sdk/src/error.rs b/packages/wasm-sdk/src/error.rs new file mode 100644 index 00000000000..0e3742b368f --- /dev/null +++ b/packages/wasm-sdk/src/error.rs @@ -0,0 +1,13 @@ +use dash_sdk::Error; +use std::fmt::Display; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsError; + +#[wasm_bindgen] +#[derive(thiserror::Error, Debug)] +#[error("Dash SDK error: {0:?}")] +pub struct WasmError(#[from] Error); + +pub(crate) fn to_js_error(e: impl Display) -> JsError { + JsError::new(&format!("{}", e)) +} diff --git a/packages/wasm-sdk/src/lib.rs b/packages/wasm-sdk/src/lib.rs new file mode 100644 index 00000000000..b56e5a4f009 --- /dev/null +++ b/packages/wasm-sdk/src/lib.rs @@ -0,0 +1,24 @@ +use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; + +pub mod context_provider; +pub mod dpp; +pub mod error; +pub mod sdk; +pub mod state_transitions; +pub mod verify; + +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + +// TODO: Remove tracing or use +//https://github.com/old-storyai/tracing-wasm +//https://github.com/jquesada2016/tracing_subscriber_wasm +//https://crates.io/crates/tracing-web + +#[wasm_bindgen(start)] +pub async fn start() -> Result<(), JsValue> { + console_error_panic_hook::set_once(); + tracing_wasm::set_as_global_default(); + + Ok(()) +} diff --git a/packages/wasm-sdk/src/sdk.rs b/packages/wasm-sdk/src/sdk.rs new file mode 100644 index 00000000000..12a3233d9f0 --- /dev/null +++ b/packages/wasm-sdk/src/sdk.rs @@ -0,0 +1,206 @@ +use crate::context_provider::WasmContext; +use crate::dpp::{DataContractWasm, IdentityWasm}; +use dash_sdk::dpp::block::extended_epoch_info::ExtendedEpochInfo; +use dash_sdk::dpp::dashcore::{Network, PrivateKey}; +use dash_sdk::dpp::data_contract::accessors::v0::DataContractV0Getters; +use dash_sdk::dpp::data_contract::DataContractFactory; +use dash_sdk::dpp::document::serialization_traits::DocumentPlatformConversionMethodsV0; +use dash_sdk::dpp::identity::signer::Signer; +use dash_sdk::dpp::identity::IdentityV0; +use dash_sdk::dpp::prelude::AssetLockProof; +use dash_sdk::dpp::serialization::PlatformSerializableWithPlatformVersion; +use dash_sdk::platform::transition::broadcast::BroadcastStateTransition; +use dash_sdk::platform::transition::put_identity::PutIdentity; +use dash_sdk::platform::{DataContract, Document, DocumentQuery, Fetch, Identifier, Identity}; +use dash_sdk::sdk::AddressList; +use dash_sdk::{Error, Sdk, SdkBuilder}; +use platform_value::platform_value; +use std::collections::BTreeMap; +use std::fmt::{Debug, Display}; +use std::ops::{Deref, DerefMut}; +use std::str::FromStr; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsError; +use web_sys::{console, js_sys, window}; + +#[wasm_bindgen] +pub struct WasmSdk(Sdk); +// Dereference JsSdk to Sdk so that we can use &JsSdk everywhere where &sdk is needed +impl std::ops::Deref for WasmSdk { + type Target = Sdk; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl AsRef for WasmSdk { + fn as_ref(&self) -> &Sdk { + &self.0 + } +} + +impl From for WasmSdk { + fn from(sdk: Sdk) -> Self { + WasmSdk(sdk) + } +} + +#[wasm_bindgen] +pub struct WasmSdkBuilder(SdkBuilder); + +impl Deref for WasmSdkBuilder { + type Target = SdkBuilder; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for WasmSdkBuilder { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[wasm_bindgen] +impl WasmSdkBuilder { + pub fn new_mainnet() -> Self { + let sdk_builder = SdkBuilder::new_mainnet().with_context_provider(WasmContext {}); + + Self(sdk_builder) + } + + pub fn new_testnet() -> Self { + WasmSdkBuilder(SdkBuilder::new_testnet()) + } + + pub fn build(self) -> Result { + Ok(WasmSdk(self.0.build()?)) + } + + pub fn with_context_provider(self, context_provider: WasmContext) -> Self { + WasmSdkBuilder(self.0.with_context_provider(context_provider)) + } +} + +#[wasm_bindgen] +pub async fn identity_fetch(sdk: &WasmSdk, base58_id: &str) -> Result { + let id = Identifier::from_string( + base58_id, + dash_sdk::dpp::platform_value::string_encoding::Encoding::Base58, + )?; + + Identity::fetch_by_identifier(sdk, id) + .await? + .ok_or_else(|| JsError::new("Identity not found")) + .map(Into::into) +} + +#[wasm_bindgen] +pub async fn data_contract_fetch( + sdk: &WasmSdk, + base58_id: &str, +) -> Result { + let id = Identifier::from_string( + base58_id, + dash_sdk::dpp::platform_value::string_encoding::Encoding::Base58, + )?; + + DataContract::fetch_by_identifier(sdk, id) + .await? + .ok_or_else(|| JsError::new("Data contract not found")) + .map(Into::into) +} + +#[wasm_bindgen] +pub async fn identity_put(sdk: &WasmSdk) { + let id = Identifier::from_bytes(&[0; 32]).expect("create identifier"); + + let identity = Identity::V0(IdentityV0 { + id, + public_keys: BTreeMap::new(), + balance: 0, + revision: 0, + }); + + let asset_lock_proof = AssetLockProof::default(); + let asset_lock_proof_private_key = + PrivateKey::from_slice(&[0; 32], Network::Testnet).expect("create private key"); + + let signer = MockSigner; + let _pushed: Identity = identity + .put_to_platform( + sdk, + asset_lock_proof, + &asset_lock_proof_private_key, + &signer, + None, + ) + .await + .expect("put identity") + .broadcast_and_wait(sdk, None) + .await + .unwrap(); +} + +#[wasm_bindgen] +pub async fn epoch_testing() { + let sdk = SdkBuilder::new(AddressList::new()) + .build() + .expect("build sdk"); + + let ei = ExtendedEpochInfo::fetch(&sdk, 0) + .await + .expect("fetch extended epoch info") + .expect("extended epoch info not found"); +} + +#[wasm_bindgen] +pub async fn docs_testing(sdk: &WasmSdk) { + let id = Identifier::random(); + + let factory = DataContractFactory::new(1).expect("create data contract factory"); + factory + .create(id, 1, platform_value!({}), None, None) + .expect("create data contract"); + + let dc = DataContract::fetch(&sdk, id) + .await + .expect("fetch data contract") + .expect("data contract not found"); + + let dcs = dc + .serialize_to_bytes_with_platform_version(sdk.version()) + .expect("serialize data contract"); + + let query = DocumentQuery::new(dc.clone(), "asd").expect("create query"); + let doc = Document::fetch(sdk, query) + .await + .expect("fetch document") + .expect("document not found"); + + let document_type = dc + .document_type_for_name("aaa") + .expect("document type for name"); + let doc_serialized = doc + .serialize(document_type, sdk.version()) + .expect("serialize document"); + + let msg = js_sys::JsString::from_str(&format!("{:?} {:?} ", dcs, doc_serialized)) + .expect("create js string"); + console::log_1(&msg); +} + +#[derive(Clone, Debug)] +struct MockSigner; +impl Signer for MockSigner { + fn can_sign_with(&self, _identity_public_key: &dash_sdk::platform::IdentityPublicKey) -> bool { + true + } + fn sign( + &self, + _identity_public_key: &dash_sdk::platform::IdentityPublicKey, + _data: &[u8], + ) -> Result { + todo!() + } +} diff --git a/packages/wasm-sdk/src/state_transitions/documents.rs b/packages/wasm-sdk/src/state_transitions/documents.rs new file mode 100644 index 00000000000..9a7e0fb2090 --- /dev/null +++ b/packages/wasm-sdk/src/state_transitions/documents.rs @@ -0,0 +1,73 @@ +use crate::error::to_js_error; +use dash_sdk::dashcore_rpc::jsonrpc::serde_json::Value; +use dash_sdk::dpp::data_contract::document_type::DocumentTypeRef; +use dash_sdk::dpp::identity::KeyID; +use dash_sdk::dpp::platform_value::string_encoding::Encoding; +use dash_sdk::dpp::platform_value::Bytes32; +use dash_sdk::dpp::serialization::PlatformSerializable; +use dash_sdk::dpp::state_transition::documents_batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; +use dash_sdk::dpp::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use dash_sdk::dpp::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransitionV0; +use dash_sdk::dpp::state_transition::documents_batch_transition::document_transition::action_type::DocumentTransitionActionType; +use dash_sdk::dpp::state_transition::documents_batch_transition::document_transition::DocumentTransition; +use dash_sdk::dpp::state_transition::documents_batch_transition::{ + DocumentCreateTransition, DocumentsBatchTransition, DocumentsBatchTransitionV0, +}; +use dash_sdk::platform::{Document, Identifier}; +use std::collections::{BTreeMap, HashMap, HashSet}; +use std::fmt::Display; +use wasm_bindgen::prelude::*; +use web_sys::js_sys::{Number, Uint32Array, Uint8Array}; + +#[wasm_bindgen] +pub fn create_document( + document: JsValue, + identity_contract_nonce: Number, + signature_public_key_id: Number, +) -> Result { + // TODO: Extract document fields from JsValue + + let base = DocumentBaseTransition::V0(DocumentBaseTransitionV0 { + id: Default::default(), + identity_contract_nonce: 1, + document_type_name: "".to_string(), + data_contract_id: Default::default(), + }); + + let transition = DocumentCreateTransition::V0(DocumentCreateTransitionV0 { + base: Default::default(), + entropy: [0; 32], + data: Default::default(), + prefunded_voting_balance: None, + }); + + create_batch_transition( + vec![DocumentTransition::Create(transition)], + signature_public_key_id, + ) +} + +fn create_batch_transition( + transitions: Vec, + signature_public_key_id: Number, +) -> Result { + let signature_public_key_id = signature_public_key_id + .as_f64() + .ok_or_else(|| JsError::new("public_key_id must be a number"))?; + + // TODO: This is unsafe convertion + let signature_public_key_id = signature_public_key_id as KeyID; + + let document_batch_transition = DocumentsBatchTransition::V0(DocumentsBatchTransitionV0 { + owner_id: Default::default(), + transitions, + user_fee_increase: 0, + signature_public_key_id, + signature: Default::default(), + }); + + document_batch_transition + .serialize_to_bytes() + .map_err(to_js_error) + .map(|bytes| Uint8Array::from(bytes.as_slice())) +} diff --git a/packages/wasm-sdk/src/state_transitions/mod.rs b/packages/wasm-sdk/src/state_transitions/mod.rs new file mode 100644 index 00000000000..487a38d50d4 --- /dev/null +++ b/packages/wasm-sdk/src/state_transitions/mod.rs @@ -0,0 +1 @@ +pub mod documents; diff --git a/packages/wasm-sdk/src/verify.rs b/packages/wasm-sdk/src/verify.rs new file mode 100644 index 00000000000..88bc35d0707 --- /dev/null +++ b/packages/wasm-sdk/src/verify.rs @@ -0,0 +1,190 @@ +use dash_sdk::dpp::dashcore::Network; +use dash_sdk::dpp::data_contract::accessors::v0::DataContractV0Getters; +use dash_sdk::dpp::data_contract::DataContract; +use dash_sdk::dpp::document::{Document, DocumentV0Getters}; +use dash_sdk::dpp::identity::accessors::IdentityGettersV0; +use dash_sdk::dpp::identity::Identity; +use dash_sdk::dpp::platform_value::string_encoding::Encoding; +use dash_sdk::dpp::serialization::PlatformDeserializableWithPotentialValidationFromVersionedStructure; +use dash_sdk::dpp::version::PlatformVersion; +use dash_sdk::platform::proto::get_identity_request::{ + GetIdentityRequestV0, Version as GetIdentityRequestVersion, +}; +use dash_sdk::platform::proto::get_identity_response::{ + get_identity_response_v0, GetIdentityResponseV0, Version, +}; +use dash_sdk::platform::proto::{ + GetDocumentsResponse, GetIdentityRequest, Proof, ResponseMetadata, +}; +use dash_sdk::platform::DocumentQuery; +use drive_proof_verifier::types::Documents; +use drive_proof_verifier::FromProof; +use wasm_bindgen::prelude::wasm_bindgen; + +use crate::context_provider::WasmContext; +use crate::dpp::{DataContractWasm, IdentityWasm}; + +#[wasm_bindgen] +pub async fn verify_identity_response() -> Option { + let request = dash_sdk::dapi_grpc::platform::v0::GetIdentityRequest { + version: Some(GetIdentityRequestVersion::V0(GetIdentityRequestV0 { + id: vec![], + prove: true, + })), + }; + + let response = dash_sdk::dapi_grpc::platform::v0::GetIdentityResponse { + version: Some(Version::V0(GetIdentityResponseV0 { + result: Some(get_identity_response_v0::Result::Proof(Proof { + grovedb_proof: vec![], + quorum_hash: vec![], + signature: vec![], + round: 0, + block_id_hash: vec![], + quorum_type: 0, + })), + metadata: Some(ResponseMetadata { + height: 0, + core_chain_locked_height: 0, + epoch: 0, + time_ms: 0, + protocol_version: 0, + chain_id: "".to_string(), + }), + })), + }; + + let context = WasmContext {}; + + let (response, _metadata, _proof) = + >::maybe_from_proof_with_metadata( + request, + response, + Network::Dash, + PlatformVersion::latest(), + &context, + ) + .expect("parse proof"); + + response.map(IdentityWasm::from) +} + +#[wasm_bindgen] +pub async fn verify_data_contract() -> Option { + let request = dash_sdk::dapi_grpc::platform::v0::GetDataContractRequest { + version: Some( + dash_sdk::platform::proto::get_data_contract_request::Version::V0( + dash_sdk::platform::proto::get_data_contract_request::GetDataContractRequestV0 { + id: vec![], + prove: true, + }, + ), + ), + }; + + let response = dash_sdk::dapi_grpc::platform::v0::GetDataContractResponse { + version: Some( + dash_sdk::platform::proto::get_data_contract_response::Version::V0( + dash_sdk::platform::proto::get_data_contract_response::GetDataContractResponseV0 { + result: Some( + dash_sdk::platform::proto::get_data_contract_response::get_data_contract_response_v0::Result::Proof( + dash_sdk::platform::proto::Proof { + grovedb_proof: vec![], + quorum_hash: vec![], + signature: vec![], + round: 0, + block_id_hash: vec![], + quorum_type: 0, + }, + ), + ), + metadata: Some(dash_sdk::platform::proto::ResponseMetadata { + height: 0, + core_chain_locked_height: 0, + epoch: 0, + time_ms: 0, + protocol_version: 0, + chain_id: "".to_string(), + }), + }, + ), + ), + }; + + let context = WasmContext {}; + + let (response, _, _) = >::maybe_from_proof_with_metadata( + request, + response, + Network::Dash, + PlatformVersion::latest(), + &context, + ) + .expect("parse proof"); + + response.map(DataContractWasm::from) +} + +#[wasm_bindgen] +pub async fn verify_documents() -> Vec { + let data_contract = + DataContract::versioned_deserialize(&[13, 13, 13], false, PlatformVersion::latest()) + .expect("create data contract"); + + let query = DocumentQuery::new(data_contract, "asd").expect("create query"); + + let response = GetDocumentsResponse { + version: Some(dash_sdk::platform::proto::get_documents_response::Version::V0( + dash_sdk::platform::proto::get_documents_response::GetDocumentsResponseV0 { + result: Some( + dash_sdk::platform::proto::get_documents_response::get_documents_response_v0::Result::Proof( + Proof { + grovedb_proof: vec![], + quorum_hash: vec![], + signature: vec![], + round: 0, + block_id_hash: vec![], + quorum_type: 0, + }, + ), + ), + metadata: Some(ResponseMetadata { + height: 0, + core_chain_locked_height: 0, + epoch: 0, + time_ms: 0, + protocol_version: 0, + chain_id: "".to_string(), + }), + }, + )), + }; + + let (documents, _, _) = + >::maybe_from_proof_with_metadata( + query, + response, + Network::Dash, + PlatformVersion::latest(), + &WasmContext {}, + ) + .expect("parse proof"); + + documents + .unwrap() + .into_iter() + .filter(|(_, doc)| doc.is_some()) + .map(|(_, doc)| DocumentWasm(doc.unwrap())) + .collect() +} + +#[wasm_bindgen] +pub struct DocumentWasm(Document); +#[wasm_bindgen] +impl DocumentWasm { + pub fn id(&self) -> String { + self.0.id().to_string(Encoding::Base58) + } +}