diff --git a/.cargo/config.toml b/.cargo/config.toml index d60af81d9..109adb97e 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -7,5 +7,3 @@ linker = "x86_64-linux-gnu-gcc" [net] git-fetch-with-cli = true # use the `git` executable for git operations -[source.crates-io] -registry = "git://github.com/rust-lang/crates.io-index.git" diff --git a/Cargo.lock b/Cargo.lock index 917db5c17..c24a3f253 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,7 +88,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", "once_cell", "version_check", ] @@ -101,7 +101,7 @@ checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "const-random", - "getrandom 0.2.14", + "getrandom 0.2.15", "once_cell", "serde", "version_check", @@ -155,47 +155,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -203,9 +204,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" dependencies = [ "backtrace", ] @@ -242,7 +243,7 @@ dependencies = [ "metrics", "metrics-exporter-prometheus", "opa", - "opentelemetry 0.22.0", + "opentelemetry", "parking_lot 0.12.2", "poem", "protocol-substrate", @@ -426,9 +427,9 @@ checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" [[package]] name = "array-bytes" -version = "6.2.2" +version = "6.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f840fb7195bcfc5e17ea40c26e5ce6d5b9ce5d584466e17703209657e459ae0" +checksum = "5d5dde061bd34119e902bbb2d9b90c5692635cf59fb91d582c2b68043f1b8293" [[package]] name = "arrayref" @@ -506,7 +507,7 @@ dependencies = [ "chrono", "chrono-tz", "half", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "num", ] @@ -652,7 +653,7 @@ dependencies = [ "arrow-data", "arrow-schema", "half", - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -774,13 +775,12 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d4d23bcc79e27423727b36823d86233aad06dfea531837b038394d11e9928" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener 5.3.0", - "event-listener-strategy 0.5.1", + "event-listener-strategy 0.5.2", "futures-core", "pin-project-lite 0.2.14", ] @@ -800,9 +800,9 @@ dependencies = [ [[package]] name = "async-fs" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc19683171f287921f2405677dd2ed2549c3b3bda697a563ebc3a121ace2aba1" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" dependencies = [ "async-lock 3.3.0", "blocking", @@ -811,30 +811,30 @@ dependencies = [ [[package]] name = "async-graphql" -version = "7.0.3" +version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261fa27d5bff5afdf7beff291b3bc73f99d1529804c70e51b0fbc51e70b1c6a9" +checksum = "d0808e3dc8be9cee801000b9261081cd7caae9935658be7e52d4df3d5c22bdce" dependencies = [ "async-graphql-derive", "async-graphql-parser", "async-graphql-value", "async-stream", "async-trait", - "base64 0.21.7", + "base64 0.22.1", "blocking", "bytes", "chrono", "fast_chemail", "fnv", "futures-util", - "handlebars", + "handlebars 5.1.2", "http 1.1.0", "indexmap 2.2.6", "mime", "multer", "num-traits", "once_cell", - "opentelemetry 0.21.0", + "opentelemetry", "pin-project-lite 0.2.14", "regex", "serde", @@ -848,26 +848,26 @@ dependencies = [ [[package]] name = "async-graphql-derive" -version = "7.0.3" +version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3188809947798ea6db736715a60cf645ba3b87ea031c710130e1476b48e45967" +checksum = "ae80fb7b67deeae84441a9eb156359b99be7902d2d706f43836156eec69a8226" dependencies = [ "Inflector", "async-graphql-parser", - "darling 0.20.8", - "proc-macro-crate 1.1.3", + "darling 0.20.9", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", "strum 0.26.2", - "syn 2.0.60", + "syn 2.0.64", "thiserror", ] [[package]] name = "async-graphql-parser" -version = "7.0.3" +version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e65a0b83027f35b2a5d9728a098bc66ac394caa8191d2c65ed9eb2985cf3d8" +checksum = "8f0fffb19cd96eb084428289f4568b5ad48df32f782f891f709db96384fbdeb2" dependencies = [ "async-graphql-value", "pest", @@ -877,9 +877,9 @@ dependencies = [ [[package]] name = "async-graphql-poem" -version = "7.0.4" +version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397d63c0b27828a7e0af8ebedeed7d77bcd9d61cf085314bf382f0f2d9652f8d" +checksum = "ee8483d34d012aea467463c4de9a3bddee965fac6f99ed4a4a859171e4ecadb4" dependencies = [ "async-graphql", "futures-util", @@ -894,9 +894,9 @@ dependencies = [ [[package]] name = "async-graphql-value" -version = "7.0.3" +version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e40849c29a39012d38bff87bfed431f1ed6c53fbec493294c1045d61a7ae75" +checksum = "c224c93047a7197fe0f1d6eee98245ba6049706c6c04a372864557fb61495e94" dependencies = [ "bytes", "indexmap 2.2.6", @@ -960,7 +960,7 @@ version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a53fc6301894e04a92cb2584fedde80cb25ba8e02d9dc39d4a87d036e22f397d" dependencies = [ - "async-channel 2.2.1", + "async-channel 2.3.1", "async-io", "async-lock 3.3.0", "async-signal", @@ -1022,14 +1022,14 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] name = "async-task" -version = "4.7.0" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" @@ -1039,7 +1039,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1086,9 +1086,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" @@ -1188,9 +1188,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -1228,13 +1228,13 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "prettyplease 0.2.19", + "prettyplease 0.2.20", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1402,18 +1402,16 @@ dependencies = [ [[package]] name = "blocking" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" dependencies = [ - "async-channel 2.2.1", + "async-channel 2.3.1", "async-lock 3.3.0", "async-task", - "fastrand", "futures-io", "futures-lite", "piper", - "tracing", ] [[package]] @@ -1499,9 +1497,9 @@ checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" [[package]] name = "bytemuck" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5" dependencies = [ "bytemuck_derive", ] @@ -1514,7 +1512,7 @@ checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1593,9 +1591,9 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "camino" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" dependencies = [ "serde", ] @@ -1623,7 +1621,7 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", - "semver 1.0.22", + "semver 1.0.23", "serde", "serde_json", "thiserror", @@ -1637,9 +1635,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.95" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" dependencies = [ "jobserver", "libc", @@ -1744,7 +1742,7 @@ dependencies = [ "libc", "mockito", "opa", - "opentelemetry 0.22.0", + "opentelemetry", "percent-encoding", "protocol-abstract", "protocol-substrate", @@ -1814,8 +1812,7 @@ dependencies = [ "arrow-flight", "arrow-ipc", "arrow-schema", - "clap 3.2.25", - "clap_complete", + "clap 4.5.4", "prettytable-rs", "tokio", "tonic 0.10.2", @@ -2147,7 +2144,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -2177,9 +2174,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "colored" @@ -2276,9 +2273,9 @@ checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" [[package]] name = "concurrent-queue" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -2354,7 +2351,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", "once_cell", "tiny-keccak", ] @@ -2792,7 +2789,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -2803,9 +2800,9 @@ checksum = "4f8a51dd197fa6ba5b4dc98a990a43cc13693c23eb0089ebb0fcc1f04152bca6" [[package]] name = "cxx" -version = "1.0.121" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21db378d04296a84d8b7d047c36bb3954f0b46529db725d7e62fb02f9ba53ccc" +checksum = "bb497fad022245b29c2a0351df572e2d67c1046bcef2260ebc022aec81efea82" dependencies = [ "cc", "cxxbridge-flags", @@ -2815,9 +2812,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.121" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5262a7fa3f0bae2a55b767c223ba98032d7c328f5c13fa5cdc980b77fc0658" +checksum = "9327c7f9fbd6329a200a5d4aa6f674c60ab256525ff0084b52a889d4e4c60cee" dependencies = [ "cc", "codespan-reporting", @@ -2825,24 +2822,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] name = "cxxbridge-flags" -version = "1.0.121" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8dcadd2e2fb4a501e1d9e93d6e88e6ea494306d8272069c92d5a9edf8855c0" +checksum = "688c799a4a846f1c0acb9f36bb9c6272d9b3d9457f3633c7753c6057270df13c" [[package]] name = "cxxbridge-macro" -version = "1.0.121" +version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad08a837629ad949b73d032c637653d069e909cffe4ee7870b02301939ce39cc" +checksum = "928bc249a7e3cd554fd2e8e08a426e9670c50bbfc9a621653cfa9accc9641783" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -2867,12 +2864,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" dependencies = [ - "darling_core 0.20.8", - "darling_macro 0.20.8", + "darling_core 0.20.9", + "darling_macro 0.20.9", ] [[package]] @@ -2905,16 +2902,16 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 2.0.60", + "strsim 0.11.1", + "syn 2.0.64", ] [[package]] @@ -2941,26 +2938,26 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ - "darling_core 0.20.8", + "darling_core 0.20.9", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "data-encoding-macro" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20c01c06f5f429efdf2bae21eb67c28b3df3cf85b7dd2d8ef09c0838dac5d33e" +checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -2968,9 +2965,9 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0047d07f2c89b17dd631c80450d69841a6b5d7fb17278cbc43d7e4cfcf2576f3" +checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" dependencies = [ "data-encoding", "syn 1.0.109", @@ -3056,7 +3053,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -3128,7 +3125,7 @@ dependencies = [ "diesel_table_macro_syntax", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -3148,7 +3145,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" dependencies = [ - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -3256,7 +3253,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -3286,9 +3283,9 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.60", + "syn 2.0.64", "termcolor", - "toml 0.8.12", + "toml 0.8.13", "walkdir", ] @@ -3417,7 +3414,7 @@ checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" dependencies = [ "curve25519-dalek 4.1.2", "ed25519", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "hex", "rand_core 0.6.4", "sha2 0.10.8", @@ -3554,9 +3551,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3602,9 +3599,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332f51cb23d20b0de8458b86580878211da09bcd4503cb579c225b3d124cabb3" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener 5.3.0", "pin-project-lite 0.2.14", @@ -3630,7 +3627,7 @@ dependencies = [ "prettier-please", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -3666,9 +3663,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fdlimit" @@ -3701,9 +3698,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38793c55593b33412e3ae40c2c9781ffaa6f438f6f8c10f24e71846fbd7ae01e" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "file-per-thread-logger" @@ -3773,9 +3770,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4556222738635b7a3417ae6130d8f52201e45a0c4d1a907f0826383adb5f85e7" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "libz-sys", @@ -3879,7 +3876,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67e51c371bff90ba44767a79e72a036d7d648cee621cd2fe9f693e8c1d62941e" dependencies = [ "Inflector", - "array-bytes 6.2.2", + "array-bytes 6.2.3", "chrono", "clap 4.5.4", "comfy-table", @@ -3887,7 +3884,7 @@ dependencies = [ "frame-support", "frame-system", "gethostname", - "handlebars", + "handlebars 4.5.0", "itertools 0.10.5", "lazy_static", "linked-hash-map", @@ -4043,7 +4040,7 @@ dependencies = [ "proc-macro2", "quote", "sp-core-hashing 13.0.0", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -4056,7 +4053,7 @@ dependencies = [ "proc-macro-crate 1.1.3", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -4067,7 +4064,7 @@ checksum = "d9c078db2242ea7265faa486004e7fd8daaf1a577cfcac0070ce55d926922883" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -4224,7 +4221,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -4354,9 +4351,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -4530,6 +4527,20 @@ dependencies = [ "thiserror", ] +[[package]] +name = "handlebars" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "hash-db" version = "0.16.0" @@ -4565,9 +4576,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash 0.8.11", "allocator-api2", @@ -4580,7 +4591,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -4819,7 +4830,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite 0.2.14", - "socket2 0.5.6", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -4857,7 +4868,7 @@ dependencies = [ "http 0.2.12", "hyper 0.14.28", "log", - "rustls 0.21.11", + "rustls 0.21.12", "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", @@ -4918,7 +4929,7 @@ dependencies = [ "http-body 1.0.0", "hyper 1.3.1", "pin-project-lite 0.2.14", - "socket2 0.5.6", + "socket2 0.5.7", "tokio", "tower", "tower-service", @@ -5086,7 +5097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] @@ -5120,9 +5131,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.38.0" +version = "1.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eab73f58e59ca6526037208f0e98851159ec1633cf17b6cd2e1f2c3fd5d53cc" +checksum = "810ae6042d48e2c9e9215043563a58a80b877bc863228a74cf10c49d4620a6f5" dependencies = [ "console", "lazy_static", @@ -5175,7 +5186,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.6", + "socket2 0.5.7", "widestring", "windows-sys 0.48.0", "winreg", @@ -5218,6 +5229,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "iso8601" version = "0.6.1" @@ -5687,7 +5704,7 @@ dependencies = [ "clap 4.5.4", "fancy-regex", "fraction", - "getrandom 0.2.14", + "getrandom 0.2.15", "iso8601", "itoa", "memchr", @@ -5902,9 +5919,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libloading" @@ -5931,7 +5948,7 @@ dependencies = [ "bytes", "futures", "futures-timer", - "getrandom 0.2.14", + "getrandom 0.2.15", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -6509,7 +6526,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -6565,7 +6582,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -6579,7 +6596,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -6590,7 +6607,7 @@ checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -6601,7 +6618,7 @@ checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -6747,7 +6764,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d58e362dc7206e9456ddbcdbd53c71ba441020e62104703075a69151e38d85f" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "http-body-util", "hyper 1.3.1", "hyper-tls 0.6.0", @@ -6770,7 +6787,7 @@ checksum = "8b07a5eb561b8cbc16be2d216faf7757f9baf3bfb94dbb0fae3df8387a5bb47f" dependencies = [ "crossbeam-epoch", "crossbeam-utils", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "metrics", "num_cpus", "quanta", @@ -6909,16 +6926,15 @@ checksum = "e7627d8bbeb17edbf1c3f74b21488e4af680040da89713b4217d0010e9cbd97e" [[package]] name = "multer" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15d522be0a9c3e46fd2632e272d178f56387bdb5c9fbb3a36c649062e9b5219" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" dependencies = [ "bytes", "encoding_rs", "futures-util", "http 1.1.0", "httparse", - "log", "memchr", "mime", "spin 0.9.8", @@ -7269,9 +7285,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", @@ -7283,11 +7299,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -7300,9 +7315,9 @@ checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa" [[package]] name = "num-complex" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] @@ -7334,9 +7349,9 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -7345,11 +7360,10 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-bigint", "num-integer", "num-traits", @@ -7357,9 +7371,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -7398,7 +7412,7 @@ checksum = "c38841cdd844847e3e7c8d29cef9dcfed8877f8f56f9071f77843ecf3baf937f" dependencies = [ "base64 0.13.1", "chrono", - "getrandom 0.2.14", + "getrandom 0.2.15", "http 0.2.12", "rand 0.8.5", "reqwest", @@ -7550,7 +7564,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -7571,22 +7585,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "opentelemetry" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e32339a5dc40459130b3bd269e9892439f55b33e772d2a9d402a789baaf4e8a" -dependencies = [ - "futures-core", - "futures-sink", - "indexmap 2.2.6", - "js-sys", - "once_cell", - "pin-project-lite 0.2.14", - "thiserror", - "urlencoding", -] - [[package]] name = "opentelemetry" version = "0.22.0" @@ -7611,7 +7609,7 @@ dependencies = [ "async-trait", "bytes", "http 0.2.12", - "opentelemetry 0.22.0", + "opentelemetry", ] [[package]] @@ -7623,7 +7621,7 @@ dependencies = [ "async-trait", "futures-core", "http 0.2.12", - "opentelemetry 0.22.0", + "opentelemetry", "opentelemetry-proto", "opentelemetry-semantic-conventions", "opentelemetry_sdk", @@ -7639,7 +7637,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a8fddc9b68f5b80dae9d6f510b88e02396f006ad48cac349411fbecc80caae4" dependencies = [ - "opentelemetry 0.22.0", + "opentelemetry", "opentelemetry_sdk", "prost 0.12.4", "tonic 0.11.0", @@ -7664,7 +7662,7 @@ dependencies = [ "futures-util", "glob", "once_cell", - "opentelemetry 0.22.0", + "opentelemetry", "ordered-float", "percent-encoding", "rand 0.8.5", @@ -7893,9 +7891,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.9" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec 0.7.4", "bitvec", @@ -7908,11 +7906,11 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.9" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ - "proc-macro-crate 2.0.0", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", "syn 1.0.109", @@ -7986,9 +7984,9 @@ dependencies = [ [[package]] name = "parse-zoneinfo" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" +checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" dependencies = [ "regex", ] @@ -8001,9 +7999,9 @@ checksum = "7924d1d0ad836f665c9065e26d016c673ece3993f30d340068b16f282afc1156" [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" @@ -8079,9 +8077,9 @@ checksum = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" [[package]] name = "pest" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" dependencies = [ "memchr", "thiserror", @@ -8090,9 +8088,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" dependencies = [ "pest", "pest_generator", @@ -8100,22 +8098,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] name = "pest_meta" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" dependencies = [ "once_cell", "pest", @@ -8124,9 +8122,9 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", "indexmap 2.2.6", @@ -8225,7 +8223,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8248,9 +8246,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +checksum = "464db0c665917b13ebb5d453ccdec4add5658ee1adc7affc7677615356a8afaf" dependencies = [ "atomic-waker", "fastrand", @@ -8323,7 +8321,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b735eaaaa6bc7ed2dcbcab1d5373afe1f6d03a37d8695ba3c42101f733a8455" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "bytes", "futures-util", "headers", @@ -8333,7 +8331,7 @@ dependencies = [ "hyper-util", "mime", "nix 0.28.0", - "opentelemetry 0.22.0", + "opentelemetry", "opentelemetry-http", "opentelemetry-semantic-conventions", "parking_lot 0.12.2", @@ -8364,7 +8362,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8489,7 +8487,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22020dfcf177fcc7bf5deaf7440af371400c67c0de14c399938d8ed4fb4645d3" dependencies = [ "proc-macro2", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8513,12 +8511,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac2cf0f2e4f42b49f5ffd07dae8d746508ef7526c13940e5f524012ae6c6550" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8558,15 +8556,6 @@ dependencies = [ "toml 0.5.11", ] -[[package]] -name = "proc-macro-crate" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" -dependencies = [ - "toml_edit 0.20.7", -] - [[package]] name = "proc-macro-crate" version = "3.1.0" @@ -8608,23 +8597,23 @@ checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] [[package]] name = "prometheus" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" dependencies = [ "cfg-if", "fnv", @@ -8654,7 +8643,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8742,7 +8731,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8857,9 +8846,9 @@ dependencies = [ [[package]] name = "psl" -version = "2.1.34" +version = "2.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe63c1c8bb438205c1245719638a0b14fe6e3b33f4406ac36b4770a706655345" +checksum = "7b320cda4ad7e8f4269fa415754418f83b38c666a5e2e99ea48825b274a373f3" dependencies = [ "psl-types", ] @@ -9043,7 +9032,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", ] [[package]] @@ -9094,9 +9083,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.0.1" +version = "11.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1" +checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd" dependencies = [ "bitflags 2.5.0", ] @@ -9186,29 +9175,29 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", "libredox", "thiserror", ] [[package]] name = "ref-cast" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9269,9 +9258,9 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "relative-path" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "reqwest" @@ -9298,7 +9287,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite 0.2.14", - "rustls 0.21.11", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", "serde_json", @@ -9380,7 +9369,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.14", + "getrandom 0.2.15", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -9508,7 +9497,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.60", + "syn 2.0.64", "walkdir", ] @@ -9525,9 +9514,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -9547,7 +9536,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.22", + "semver 1.0.23", ] [[package]] @@ -9581,9 +9570,9 @@ dependencies = [ [[package]] name = "rustify_derive" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58135536c18c04f4634bedad182a3f41baf33ef811cc38a3ec7b7061c57134c8" +checksum = "7345f32672da54338227b727bd578c897859ddfaad8952e0b0d787fb4e58f07d" dependencies = [ "proc-macro2", "quote", @@ -9634,9 +9623,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.11" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", @@ -9653,7 +9642,7 @@ dependencies = [ "log", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.3", + "rustls-webpki 0.102.4", "subtle 2.5.0", "zeroize", ] @@ -9698,15 +9687,15 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.5.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" @@ -9720,9 +9709,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.3" +version = "0.102.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -9731,9 +9720,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-fork" @@ -9791,9 +9780,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "ryu-js" @@ -9906,7 +9895,7 @@ dependencies = [ "proc-macro-crate 1.1.3", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9915,7 +9904,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22c61058223f80c1f961b03f7737529609a3283eef91129e971a1966101c18ea" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "chrono", "clap 4.5.4", "fdlimit", @@ -10068,7 +10057,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30cbc5db21ea2c4ba65b23315e73e69e8155630fb47c84b93d40b0e759c9d86d" dependencies = [ "ahash 0.8.11", - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-trait", "dyn-clone", "finality-grandpa", @@ -10205,7 +10194,7 @@ version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abecdf9778fccc254c0b5e227ea8b90fd59247044a30ad293a068b180427d244" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "parking_lot 0.12.2", "serde_json", "sp-application-crypto 27.0.0", @@ -10249,7 +10238,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01f519592a971199c486d412dbf38ba54096857080bf4b9d29c9ffabcfee3745" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-channel 1.9.0", "async-trait", "asynchronous-codec", @@ -10349,7 +10338,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aac888fd720ef8bb2ff7d2b7f7b2e54d17bb85a417cf1e1b6f0f64f7e644936d" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-channel 1.9.0", "futures", "libp2p-identity", @@ -10371,7 +10360,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10c697aa8f52cf194b9f00113a7d0d3ce5d1456bedd6169a9caae10737f02907" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "async-channel 1.9.0", "async-trait", "fork-tree", @@ -10407,7 +10396,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb7c9bfc7b58ce229d1512158b8f13dc849ec24857d1c29a41a867fb8afb5c09" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "futures", "libp2p", "log", @@ -10426,7 +10415,7 @@ version = "26.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47950facab8dedf71c39667ccce8834252944e8f091f3a3bcdfc0b4503573da4" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "bytes", "fnv", "futures", @@ -10541,7 +10530,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "198ea9287111b4060ce1d70dce99804b99d1a92b5fb23a79d94bf0cb460ca3ce" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "futures", "futures-util", "hex", @@ -10740,7 +10729,7 @@ dependencies = [ "proc-macro-crate 1.1.3", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -10910,9 +10899,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.11.2" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c453e59a955f81fb62ee5d596b450383d699f152d350e9d23a0db2adb78e4c0" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" dependencies = [ "bitvec", "cfg-if", @@ -10924,11 +10913,11 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.2" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18cf6c6447f813ef19eb450e985bcce6705f9ce7660db221b59093d15c79c4b7" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", "syn 1.0.109", @@ -10953,7 +10942,7 @@ dependencies = [ "proc-macro2", "quote", "scale-info", - "syn 2.0.60", + "syn 2.0.64", "thiserror", ] @@ -11018,9 +11007,9 @@ dependencies = [ [[package]] name = "schnellru" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" +checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" dependencies = [ "ahash 0.8.11", "cfg-if", @@ -11190,11 +11179,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "core-foundation", "core-foundation-sys", "libc", @@ -11203,9 +11192,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -11222,9 +11211,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ "serde", ] @@ -11237,18 +11226,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.198" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" dependencies = [ "serde_derive", ] [[package]] name = "serde_arrow" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f81256cee4b728b13738aa6ff96818bdee153cba26e22a86b714883cc97b5a9" +checksum = "42134606eddcd2475fb1d5ecdba0d7dda5ef287b6cf1c44949e09849b2cdb27f" dependencies = [ "arrow-array", "arrow-buffer", @@ -11271,20 +11260,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -11303,9 +11292,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -11569,7 +11558,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e635339259e51ef85ac7aa29a1cd991b957047507288697a690e80ab97d07cad" dependencies = [ - "async-channel 2.2.1", + "async-channel 2.3.1", "async-executor", "async-fs", "async-io", @@ -11602,7 +11591,7 @@ dependencies = [ "fnv", "futures-lite", "futures-util", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "hex", "hmac 0.12.1", "itertools 0.12.1", @@ -11641,7 +11630,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5496f2d116b7019a526b1039ec2247dd172b8670633b1a64a614c9ea12c9d8c7" dependencies = [ - "async-channel 2.2.1", + "async-channel 2.3.1", "async-lock 3.3.0", "base64 0.21.7", "blake2-rfc", @@ -11652,7 +11641,7 @@ dependencies = [ "futures-channel", "futures-lite", "futures-util", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "hex", "itertools 0.12.1", "log", @@ -11706,9 +11695,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -11765,7 +11754,7 @@ dependencies = [ "proc-macro-crate 1.1.3", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -11949,7 +11938,7 @@ version = "25.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9ebb090ead698a6df04347c86a31ba91a387edb8a58534ec70c4f977d1e1e87" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "bitflags 1.3.2", "blake2 0.10.6", "bounded-collections", @@ -11996,7 +11985,7 @@ version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f230cb12575455070da0fc174815958423a0b9a641d5e304a9457113c7cb4007" dependencies = [ - "array-bytes 6.2.2", + "array-bytes 6.2.3", "bip39", "bitflags 1.3.2", "blake2 0.10.6", @@ -12086,7 +12075,7 @@ checksum = "42ce3e6931303769197da81facefa86159fa1085dcd96ecb7e7407b5b93582a0" dependencies = [ "quote", "sp-core-hashing 13.0.0", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -12107,7 +12096,7 @@ checksum = "50535e1a5708d3ba5c1195b59ebefac61cc8679c2c24716b87a86e8b7ed2e4a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -12118,7 +12107,7 @@ checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -12435,7 +12424,7 @@ dependencies = [ "proc-macro-crate 1.1.3", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -12449,7 +12438,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -12741,7 +12730,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -12970,7 +12959,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -13124,7 +13113,7 @@ dependencies = [ "scale-info", "scale-typegen", "subxt-metadata", - "syn 2.0.60", + "syn 2.0.64", "thiserror", "tokio", ] @@ -13152,13 +13141,13 @@ version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "365251668613323064803427af8c7c7bc366cd8b28e33639640757669dafebd5" dependencies = [ - "darling 0.20.8", + "darling 0.20.9", "parity-scale-codec", "proc-macro-error", "quote", "scale-typegen", "subxt-codegen", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -13187,9 +13176,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f" dependencies = [ "proc-macro2", "quote", @@ -13330,22 +13319,22 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -13501,7 +13490,7 @@ dependencies = [ "parking_lot 0.12.2", "pin-project-lite 0.2.14", "signal-hook-registry", - "socket2 0.5.6", + "socket2 0.5.7", "tokio-macros", "tracing", "windows-sys 0.48.0", @@ -13525,7 +13514,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -13555,7 +13544,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.11", + "rustls 0.21.12", "tokio", ] @@ -13596,9 +13585,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", @@ -13606,7 +13595,6 @@ dependencies = [ "futures-sink", "pin-project-lite 0.2.14", "tokio", - "tracing", ] [[package]] @@ -13632,21 +13620,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.12", + "toml_edit 0.22.13", ] [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] @@ -13664,17 +13652,6 @@ dependencies = [ "winnow 0.5.40", ] -[[package]] -name = "toml_edit" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" -dependencies = [ - "indexmap 2.2.6", - "toml_datetime", - "winnow 0.5.40", -] - [[package]] name = "toml_edit" version = "0.21.1" @@ -13688,15 +13665,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.12" +version = "0.22.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" dependencies = [ "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.6", + "winnow 0.6.8", ] [[package]] @@ -13823,7 +13800,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -13887,7 +13864,7 @@ checksum = "a9be14ba1bbe4ab79e9229f7f89fab8d120b865859f10527f31c033e599d2284" dependencies = [ "js-sys", "once_cell", - "opentelemetry 0.22.0", + "opentelemetry", "opentelemetry_sdk", "smallvec", "tracing", @@ -14180,9 +14157,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unicode-xid" @@ -14287,7 +14264,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", ] [[package]] @@ -14296,7 +14273,7 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", "serde", ] @@ -14451,7 +14428,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", "wasm-bindgen-shared", ] @@ -14485,7 +14462,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -14864,9 +14841,9 @@ dependencies = [ [[package]] name = "wide" -version = "0.7.16" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a1851a719f11d1d2fea40e15c72f6c00de8c142d7ac47c1441cc7e4d0d5bc6" +checksum = "aab6594190de06d718a5dbc5fa781ab62f8903797056480e549ca74add6b7065" dependencies = [ "bytemuck", "safe_arch", @@ -15159,9 +15136,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" dependencies = [ "memchr", ] @@ -15274,22 +15251,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -15309,7 +15286,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index b2f7631d9..0406a75d8 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -1,18 +1,18 @@ [package] -build = "build.rs" +build = "build.rs" edition = "2021" -name = "api" +name = "api" version = "0.7.5" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] anyhow = { workspace = true } async-graphql = { workspace = true, features = [ - "opentelemetry", - "chrono", - "unblock", - "default", - "uuid", + "opentelemetry", + "chrono", + "unblock", + "default", + "uuid", ] } async-graphql-poem = { workspace = true } async-stream = { workspace = true } @@ -56,10 +56,10 @@ chronicle-persistence = { path = "../chronicle-persistence" } chronicle-signing = { workspace = true } chronicle-telemetry = { path = "../chronicle-telemetry" } common = { path = "../common", features = [ - "json-ld", - "diesel-bindings", - "graphql-bindings", - "std", + "json-ld", + "diesel-bindings", + "graphql-bindings", + "std", ] } protocol-substrate = { path = "../protocol-substrate" } protocol-substrate-chronicle = { path = "../protocol-substrate-chronicle" } @@ -69,8 +69,8 @@ r2d2 = { version = "^0.8.1" } [dev-dependencies] assert_fs = { workspace = true } -insta = { workspace = true, features = ["json", "yaml"] } -tempfile = { workspace = true } +insta = { workspace = true, features = ["json", "yaml"] } +tempfile = { workspace = true } [build-dependencies] diff --git a/crates/api/diesel.toml b/crates/api/diesel.toml index a3c8c3d33..52bccde84 100644 --- a/crates/api/diesel.toml +++ b/crates/api/diesel.toml @@ -2,5 +2,5 @@ # see diesel.rs/guides/configuring-diesel-cli [print_schema] -file = "src/persistence/schema.rs" +file = "src/persistence/schema.rs" import_types = ["diesel::sql_types::*", "common::prov::*"] diff --git a/crates/api/src/api.rs b/crates/api/src/api.rs new file mode 100644 index 000000000..f04c11b04 --- /dev/null +++ b/crates/api/src/api.rs @@ -0,0 +1,1484 @@ +use std::marker::PhantomData; +use std::time::{Duration, Instant}; + +use async_graphql::futures_util::select; +use chrono::{DateTime, Utc}; +use diesel::PgConnection; +use diesel::r2d2::ConnectionManager; +use diesel_migrations::MigrationHarness; +use futures::FutureExt; +use futures::StreamExt; +use metrics::histogram; +use metrics_exporter_prometheus::PrometheusBuilder; +use r2d2::Pool; +use tokio::sync::broadcast::Sender; +use tokio::sync::mpsc; +use tokio::sync::mpsc::Receiver; +use tracing::{debug, error, info, info_span, instrument, Instrument, trace, warn}; +use uuid::Uuid; + +use chronicle_persistence::{MIGRATIONS, Store, StoreError}; +use chronicle_signing::ChronicleSigning; +use common::attributes::Attributes; +use common::identity::AuthId; +use common::ledger::{Commit, SubmissionError, SubmissionStage}; +use common::opa::PolicyAddress; +use common::prov::{ActivityId, AgentId, ChronicleIri, ChronicleTransactionId, EntityId, ExternalId, ExternalIdPart, NamespaceId, ProvModel, Role, SYSTEM_ID, SYSTEM_UUID, UuidPart}; +use common::prov::json_ld::ToJson; +use common::prov::operations::{ActivityExists, ActivityUses, ActsOnBehalfOf, AgentExists, ChronicleOperation, CreateNamespace, DerivationType, EndActivity, EntityDerive, EntityExists, SetAttributes, StartActivity, WasAssociatedWith, WasAttributedTo, WasGeneratedBy, WasInformedBy}; +use protocol_substrate::SubxtClientError; +use protocol_substrate_chronicle::{ChronicleEvent, ChronicleTransaction}; +use protocol_substrate_chronicle::protocol::{BlockId, FromBlock, LedgerReader, LedgerWriter}; + +use crate::{ApiError, ChronicleSigned}; +use crate::commands::{ActivityCommand, AgentCommand, ApiCommand, ApiResponse, DepthChargeCommand, EntityCommand, ImportCommand, NamespaceCommand, QueryCommand}; +use crate::dispatch::{ApiDispatch, ApiSendWithReply}; + +#[derive(Clone)] +pub struct Api< + U: UuidGen + Send + Sync + Clone, + W: LedgerWriter + + Clone + + Send + + Sync + + 'static, +> { + submit_tx: tokio::sync::broadcast::Sender, + signing: ChronicleSigning, + ledger_writer: W, + store: Store, + uuid_source: PhantomData, +} + +impl Api + where + U: UuidGen + Send + Sync + Clone + core::fmt::Debug + 'static, + LEDGER: LedgerWriter + + LedgerReader + + Clone + + Send + + Sync + + 'static, +{ + #[instrument(skip(ledger))] + pub async fn new( + pool: Pool>, + ledger: LEDGER, + uuidgen: U, + signing: ChronicleSigning, + namespace_bindings: Vec, + policy_address: Option, + liveness_check_interval: Option, + ) -> Result { + let (commit_tx, mut commit_rx) = mpsc::channel::(10); + + let (commit_notify_tx, _) = tokio::sync::broadcast::channel(20); + let dispatch = + ApiDispatch { tx: commit_tx.clone(), notify_commit: commit_notify_tx.clone() }; + + let store = Store::new(pool.clone())?; + + pool.get()? + .build_transaction() + .run(|connection| connection.run_pending_migrations(MIGRATIONS).map(|_| ())) + .map_err(StoreError::DbMigration)?; + + let system_namespace_uuid = (SYSTEM_ID, Uuid::try_from(SYSTEM_UUID).unwrap()); + + // Append namespace bindings and system namespace + store.namespace_binding(system_namespace_uuid.0, system_namespace_uuid.1)?; + for ns in namespace_bindings { + info!( + "Binding namespace with external ID: {}, UUID: {}", + ns.external_id_part().as_str(), + ns.uuid_part() + ); + store.namespace_binding(ns.external_id_part().as_str(), ns.uuid_part().to_owned())? + } + + let reuse_reader = ledger.clone(); + + let last_seen_block = store.get_last_block_id(); + + let start_from_block = if let Ok(Some(start_from_block)) = last_seen_block { + FromBlock::BlockId(start_from_block) + } else { + FromBlock::First //Full catch up, as we have no last seen block + }; + + debug!(start_from_block = ?start_from_block, "Starting from block"); + + Self::event_loop(ledger, signing, commit_rx, commit_notify_tx, store, reuse_reader, start_from_block); + + Self::depth_charge_loop(liveness_check_interval, &dispatch, system_namespace_uuid); + + Ok(dispatch) + } + + fn depth_charge_loop(liveness_check_interval: Option, dispatch: &ApiDispatch, system_namespace_uuid: (&'static str, Uuid)) { + if let Some(interval) = liveness_check_interval { + debug!("Starting liveness depth charge task"); + + let depth_charge_api = dispatch.clone(); + + tokio::task::spawn(async move { + // Configure and install Prometheus exporter + install_prometheus_metrics_exporter(); + + loop { + tokio::time::sleep(Duration::from_secs(interval)).await; + let api = depth_charge_api.clone(); + + let start_time = Instant::now(); + + let response = api + .handle_depth_charge(system_namespace_uuid.0, &system_namespace_uuid.1) + .await; + + match response { + Ok(ApiResponse::DepthChargeSubmitted { tx_id }) => { + let mut tx_notifications = api.notify_commit.subscribe(); + + loop { + let stage = match tx_notifications.recv().await { + Ok(stage) => stage, + Err(e) => { + error!("Error receiving depth charge transaction notifications: {}", e); + continue; + } + }; + + match stage { + SubmissionStage::Submitted(Ok(id)) => + if id == tx_id { + debug!("Depth charge operation submitted: {id}"); + continue; + }, + SubmissionStage::Submitted(Err(err)) => { + if err.tx_id() == &tx_id { + error!("Depth charge transaction rejected by Chronicle: {} {}", + err, + err.tx_id() + ); + break; + } + } + SubmissionStage::Committed(commit, _) => { + if commit.tx_id == tx_id { + let end_time = Instant::now(); + let elapsed_time = end_time - start_time; + debug!( + "Depth charge transaction committed: {}", + commit.tx_id + ); + debug!( + "Depth charge round trip time: {:.2?}", + elapsed_time + ); + let hist = histogram!("depth_charge_round_trip",); + + hist.record(elapsed_time.as_millis() as f64); + + break; + } + } + SubmissionStage::NotCommitted((id, contradiction, _)) => { + if id == tx_id { + error!("Depth charge transaction rejected by ledger: {id} {contradiction}"); + break; + } + } + } + } + } + Ok(res) => error!("Unexpected ApiResponse from depth charge: {res:?}"), + Err(e) => error!("ApiError submitting depth charge: {e}"), + } + } + }); + } + } + + fn event_loop(ledger: LEDGER, signing: ChronicleSigning, mut commit_rx: Receiver, commit_notify_tx: Sender, store: Store, reuse_reader: LEDGER, start_from_block: FromBlock) { + tokio::task::spawn(async move { + let mut api = Api:: { + submit_tx: commit_notify_tx.clone(), + signing, + ledger_writer: ledger, + store: store.clone(), + uuid_source: PhantomData, + }; + + loop { + let state_updates = reuse_reader.clone(); + + let state_updates = state_updates.state_updates(start_from_block, None).await; + + if let Err(e) = state_updates { + error!(subscribe_to_events = ?e); + tokio::time::sleep(Duration::from_secs(2)).await; + continue; + } + + let mut state_updates = state_updates.unwrap(); + + loop { + select! { + state = state_updates.next().fuse() =>{ + + match state { + None => { + debug!("Ledger reader stream ended"); + break; + } + // Ledger contradicted or error, so nothing to + // apply, but forward notification + Some((ChronicleEvent::Contradicted{contradiction,identity,..},tx,_block_id,_position, _span)) => { + commit_notify_tx.send(SubmissionStage::not_committed( + tx,contradiction, identity + )).ok(); + }, + // Successfully committed to ledger, so apply + // to db and broadcast notification to + // subscription subscribers + Some((ChronicleEvent::Committed{ref diff, ref identity, ..},tx,block_id,_position,_span )) => { + + debug!(diff = ?diff.summarize()); + trace!(delta = %serde_json::to_string_pretty(&diff.to_json().compact().await.unwrap()).unwrap()); + + api.sync( diff.clone().into(), &block_id,tx ) + .instrument(info_span!("Incoming confirmation", offset = ?block_id, tx = %tx)) + .await + .map_err(|e| { + error!(?e, "Api sync to confirmed commit"); + }).map(|_| commit_notify_tx.send(SubmissionStage::committed(Commit::new( + tx,block_id.to_string(), Box::new(diff.clone()) + ), identity.clone() )).ok()) + .ok(); + }, + } + }, + cmd = commit_rx.recv().fuse() => { + if let Some((command, reply)) = cmd { + + let result = api + .dispatch(command) + .await; + + reply + .send(result) + .await + .map_err(|e| { + warn!(?e, "Send reply to Api consumer failed"); + }) + .ok(); + } + } + complete => break + } + } + } + }); + } + + /// Notify after a successful submission, depending on the consistency requirement TODO: set in + /// the transaction + fn submit_blocking( + &mut self, + tx: ChronicleTransaction, + ) -> Result { + let (submission, _id) = futures::executor::block_on(self.ledger_writer.pre_submit(tx))?; + + let res = + futures::executor::block_on(self.ledger_writer.do_submit( + protocol_substrate_chronicle::protocol::WriteConsistency::Weak, + submission, + )); + match res { + Ok(tx_id) => { + self.submit_tx.send(SubmissionStage::submitted(&tx_id)).ok(); + Ok(tx_id) + } + Err((e, id)) => { + // We need the cloneable SubmissionError wrapper here + let submission_error = SubmissionError::communication(&id, e.into()); + self.submit_tx.send(SubmissionStage::submitted_error(&submission_error)).ok(); + Err(submission_error.into()) + } + } + } + + /// Generate and submit the signed identity to send to the Transaction Processor along with the + /// transactions to be applied + fn submit( + &mut self, + id: impl Into, + identity: AuthId, + to_apply: Vec, + ) -> Result { + let identity = identity.signed_identity(&self.signing)?; + let model = ProvModel::from_tx(&to_apply).map_err(ApiError::Contradiction)?; + let tx_id = self.submit_blocking(futures::executor::block_on( + ChronicleTransaction::new(&self.signing, identity, to_apply), + )?)?; + + Ok(ApiResponse::submission(id, model, tx_id)) + } + + /// Checks if ChronicleOperations resulting from Chronicle API calls will result in any changes + /// in state + /// + /// # Arguments + /// * `connection` - Connection to the Chronicle database + /// * `to_apply` - Chronicle operations resulting from an API call + #[instrument(skip(self, connection, to_apply))] + fn check_for_effects( + &mut self, + connection: &mut PgConnection, + to_apply: &Vec, + ) -> Result>, ApiError> { + debug!(checking_for_effects = to_apply.len()); + let mut model = ProvModel::default(); + let mut transactions = Vec::::with_capacity(to_apply.len()); + for op in to_apply { + let mut applied_model = match op { + ChronicleOperation::CreateNamespace(CreateNamespace { id, .. }) => { + let (namespace, _) = + self.ensure_namespace(connection, id.external_id_part())?; + model.namespace_context(&namespace); + model + } + ChronicleOperation::AgentExists(AgentExists { ref namespace, ref id }) => + self.store.apply_prov_model_for_agent_id( + connection, + model, + id, + namespace.external_id_part(), + )?, + ChronicleOperation::ActivityExists(ActivityExists { ref namespace, ref id }) => + self.store.apply_prov_model_for_activity_id( + connection, + model, + id, + namespace.external_id_part(), + )?, + ChronicleOperation::EntityExists(EntityExists { ref namespace, ref id }) => + self.store.apply_prov_model_for_entity_id( + connection, + model, + id, + namespace.external_id_part(), + )?, + ChronicleOperation::ActivityUses(ActivityUses { + ref namespace, + ref id, + ref activity, + }) => self.store.prov_model_for_usage( + connection, + model, + id, + activity, + namespace.external_id_part(), + )?, + ChronicleOperation::SetAttributes(ref o) => match o { + SetAttributes::Activity { namespace, id, .. } => + self.store.apply_prov_model_for_activity_id( + connection, + model, + id, + namespace.external_id_part(), + )?, + SetAttributes::Agent { namespace, id, .. } => + self.store.apply_prov_model_for_agent_id( + connection, + model, + id, + namespace.external_id_part(), + )?, + SetAttributes::Entity { namespace, id, .. } => + self.store.apply_prov_model_for_entity_id( + connection, + model, + id, + namespace.external_id_part(), + )?, + }, + ChronicleOperation::StartActivity(StartActivity { namespace, id, .. }) => + self.store.apply_prov_model_for_activity_id( + connection, + model, + id, + namespace.external_id_part(), + )?, + ChronicleOperation::EndActivity(EndActivity { namespace, id, .. }) => + self.store.apply_prov_model_for_activity_id( + connection, + model, + id, + namespace.external_id_part(), + )?, + ChronicleOperation::WasInformedBy(WasInformedBy { + namespace, + activity, + informing_activity, + }) => { + let model = self.store.apply_prov_model_for_activity_id( + connection, + model, + activity, + namespace.external_id_part(), + )?; + self.store.apply_prov_model_for_activity_id( + connection, + model, + informing_activity, + namespace.external_id_part(), + )? + } + ChronicleOperation::AgentActsOnBehalfOf(ActsOnBehalfOf { + activity_id, + responsible_id, + delegate_id, + namespace, + .. + }) => { + let model = self.store.apply_prov_model_for_agent_id( + connection, + model, + responsible_id, + namespace.external_id_part(), + )?; + let model = self.store.apply_prov_model_for_agent_id( + connection, + model, + delegate_id, + namespace.external_id_part(), + )?; + if let Some(id) = activity_id { + self.store.apply_prov_model_for_activity_id( + connection, + model, + id, + namespace.external_id_part(), + )? + } else { + model + } + } + ChronicleOperation::WasAssociatedWith(WasAssociatedWith { + namespace, + activity_id, + agent_id, + .. + }) => { + let model = self.store.apply_prov_model_for_activity_id( + connection, + model, + activity_id, + namespace.external_id_part(), + )?; + + self.store.apply_prov_model_for_agent_id( + connection, + model, + agent_id, + namespace.external_id_part(), + )? + } + ChronicleOperation::WasGeneratedBy(WasGeneratedBy { namespace, id, activity }) => { + let model = self.store.apply_prov_model_for_activity_id( + connection, + model, + activity, + namespace.external_id_part(), + )?; + + self.store.apply_prov_model_for_entity_id( + connection, + model, + id, + namespace.external_id_part(), + )? + } + ChronicleOperation::EntityDerive(EntityDerive { + namespace, + id, + used_id, + activity_id, + .. + }) => { + let model = self.store.apply_prov_model_for_entity_id( + connection, + model, + id, + namespace.external_id_part(), + )?; + + let model = self.store.apply_prov_model_for_entity_id( + connection, + model, + used_id, + namespace.external_id_part(), + )?; + + if let Some(id) = activity_id { + self.store.apply_prov_model_for_activity_id( + connection, + model, + id, + namespace.external_id_part(), + )? + } else { + model + } + } + ChronicleOperation::WasAttributedTo(WasAttributedTo { + namespace, + entity_id, + agent_id, + .. + }) => { + let model = self.store.apply_prov_model_for_entity_id( + connection, + model, + entity_id, + namespace.external_id_part(), + )?; + + self.store.apply_prov_model_for_agent_id( + connection, + model, + agent_id, + namespace.external_id_part(), + )? + } + }; + let state = applied_model.clone(); + applied_model.apply(op)?; + if state != applied_model { + transactions.push(op.clone()); + } + + model = applied_model; + } + + if transactions.is_empty() { + Ok(None) + } else { + Ok(Some(transactions)) + } + } + + fn apply_effects_and_submit( + &mut self, + connection: &mut PgConnection, + id: impl Into, + identity: AuthId, + to_apply: Vec, + applying_new_namespace: bool, + ) -> Result { + if applying_new_namespace { + self.submit(id, identity, to_apply) + } else if let Some(to_apply) = self.check_for_effects(connection, &to_apply)? { + info!(sending_operations = to_apply.len()); + self.submit(id, identity, to_apply) + } else { + info!("API call will not result in any data changes"); + let model = ProvModel::from_tx(&to_apply)?; + Ok(ApiResponse::already_recorded(id, model)) + } + } + + /// Ensures that the named namespace exists, returns an existing namespace, and a vector + /// containing a `ChronicleTransaction` to create one if not present + /// + /// A namespace uri is of the form chronicle:ns:{external_id}:{uuid} + /// Namespaces must be globally unique, so are disambiguated by uuid but are locally referred to + /// by external_id only For coordination between chronicle nodes we also need a namespace + /// binding operation to tie the UUID from another instance to an external_id # Arguments + /// * `external_id` - an arbitrary namespace identifier + #[instrument(skip(self, connection))] + fn ensure_namespace( + &mut self, + connection: &mut PgConnection, + id: &ExternalId, + ) -> Result<(NamespaceId, Vec), ApiError> { + match self.store.namespace_by_external_id(connection, id) { + Ok((namespace_id, _)) => { + trace!(%id, "Namespace already exists."); + Ok((namespace_id, vec![])) + } + Err(e) => { + debug!(error = %e, %id, "Namespace does not exist, creating."); + let uuid = Uuid::new_v4(); + let namespace_id = NamespaceId::from_external_id(id, uuid); + let create_namespace_op = + ChronicleOperation::CreateNamespace(CreateNamespace::new(namespace_id.clone())); + Ok((namespace_id, vec![create_namespace_op])) + } + } + } + + /// Creates and submits a (ChronicleTransaction::GenerateEntity), and possibly + /// (ChronicleTransaction::Domaintype) if specified + /// + /// We use our local store for the best guess at the activity, either by external_id or the last + /// one started as a convenience for command line + #[instrument(skip(self))] + async fn activity_generate( + &self, + id: EntityId, + namespace: ExternalId, + activity_id: ActivityId, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let create = ChronicleOperation::WasGeneratedBy(WasGeneratedBy { + namespace, + id: id.clone(), + activity: activity_id, + }); + + to_apply.push(create); + + api.apply_effects_and_submit( + connection, + id, + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + /// Creates and submits a (ChronicleTransaction::ActivityUses), and possibly + /// (ChronicleTransaction::Domaintype) if specified We use our local store for the best guess at + /// the activity, either by name or the last one started as a convenience for command line + #[instrument(skip(self))] + async fn activity_use( + &self, + id: EntityId, + namespace: ExternalId, + activity_id: ActivityId, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let (id, to_apply) = { + let create = ChronicleOperation::ActivityUses(ActivityUses { + namespace, + id: id.clone(), + activity: activity_id, + }); + + to_apply.push(create); + + (id, to_apply) + }; + + api.apply_effects_and_submit( + connection, + id, + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + /// Creates and submits a (ChronicleTransaction::ActivityWasInformedBy) + /// + /// We use our local store for the best guess at the activity, either by external_id or the last + /// one started as a convenience for command line + #[instrument(skip(self))] + async fn activity_was_informed_by( + &self, + id: ActivityId, + namespace: ExternalId, + informing_activity_id: ActivityId, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let (id, to_apply) = { + let create = ChronicleOperation::WasInformedBy(WasInformedBy { + namespace, + activity: id.clone(), + informing_activity: informing_activity_id, + }); + + to_apply.push(create); + + (id, to_apply) + }; + + api.apply_effects_and_submit( + connection, + id, + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + /// Submits operations [`CreateEntity`], and [`SetAttributes::Entity`] + /// + /// We use our local store to see if the agent already exists, disambiguating the URI if so + #[instrument(skip(self))] + async fn create_entity( + &self, + id: EntityId, + namespace_id: ExternalId, + attributes: Attributes, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace_id)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let create = ChronicleOperation::EntityExists(EntityExists { + namespace: namespace.clone(), + id: id.clone(), + }); + + to_apply.push(create); + + let set_type = ChronicleOperation::SetAttributes(SetAttributes::Entity { + id: id.clone(), + namespace, + attributes, + }); + + to_apply.push(set_type); + + api.apply_effects_and_submit( + connection, + id, + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + /// Submits operations [`CreateActivity`], and [`SetAttributes::Activity`] + /// + /// We use our local store to see if the activity already exists, disambiguating the URI if so + #[instrument(skip(self))] + async fn create_activity( + &self, + activity_id: ExternalId, + namespace_id: ExternalId, + attributes: Attributes, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace_id)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let create = ChronicleOperation::ActivityExists(ActivityExists { + namespace: namespace.clone(), + id: ActivityId::from_external_id(&activity_id), + }); + + to_apply.push(create); + + let set_type = ChronicleOperation::SetAttributes(SetAttributes::Activity { + id: ActivityId::from_external_id(&activity_id), + namespace, + attributes, + }); + + to_apply.push(set_type); + + api.apply_effects_and_submit( + connection, + ActivityId::from_external_id(&activity_id), + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + /// Submits operations [`CreateAgent`], and [`SetAttributes::Agent`] + /// + /// We use our local store to see if the agent already exists, disambiguating the URI if so + #[instrument(skip(self))] + async fn create_agent( + &self, + agent_id: ExternalId, + namespace: ExternalId, + attributes: Attributes, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let create = ChronicleOperation::AgentExists(AgentExists { + id: AgentId::from_external_id(&agent_id), + namespace: namespace.clone(), + }); + + to_apply.push(create); + + let id = AgentId::from_external_id(&agent_id); + let set_type = ChronicleOperation::SetAttributes(SetAttributes::Agent { + id: id.clone(), + namespace, + attributes, + }); + + to_apply.push(set_type); + + api.apply_effects_and_submit( + connection, + id, + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + /// Creates and submits a (ChronicleTransaction::CreateNamespace) if the external_id part does + /// not already exist in local storage + async fn create_namespace( + &self, + name: &ExternalId, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + let name = name.to_owned(); + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + connection.build_transaction().run(|connection| { + let (namespace, to_apply) = api.ensure_namespace(connection, &name)?; + + api.submit(namespace, identity, to_apply) + }) + }) + .await? + } + + #[instrument(skip(self))] + async fn depth_charge( + &self, + namespace: NamespaceId, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + let id = ActivityId::from_external_id(Uuid::new_v4().to_string()); + tokio::task::spawn_blocking(move || { + let to_apply = vec![ + ChronicleOperation::StartActivity(StartActivity { + namespace: namespace.clone(), + id: id.clone(), + time: Utc::now().into(), + }), + ChronicleOperation::EndActivity(EndActivity { + namespace, + id, + time: Utc::now().into(), + }), + ]; + api.submit_depth_charge(identity, to_apply) + }) + .await? + } + + fn submit_depth_charge( + &mut self, + identity: AuthId, + to_apply: Vec, + ) -> Result { + let identity = identity.signed_identity(&self.signing)?; + let tx_id = self.submit_blocking(futures::executor::block_on( + ChronicleTransaction::new(&self.signing, identity, to_apply), + )?)?; + Ok(ApiResponse::depth_charge_submission(tx_id)) + } + + #[instrument(skip(self))] + async fn dispatch(&mut self, command: (ApiCommand, AuthId)) -> Result { + match command { + (ApiCommand::DepthCharge(DepthChargeCommand { namespace }), identity) => + self.depth_charge(namespace, identity).await, + (ApiCommand::Import(ImportCommand { operations }), identity) => + self.submit_import_operations(identity, operations).await, + (ApiCommand::NameSpace(NamespaceCommand::Create { id }), identity) => + self.create_namespace(&id, identity).await, + (ApiCommand::Agent(AgentCommand::Create { id, namespace, attributes }), identity) => + self.create_agent(id, namespace, attributes, identity).await, + (ApiCommand::Agent(AgentCommand::UseInContext { id, namespace }), _identity) => + self.use_agent_in_cli_context(id, namespace).await, + ( + ApiCommand::Agent(AgentCommand::Delegate { + id, + delegate, + activity, + namespace, + role, + }), + identity, + ) => self.delegate(namespace, id, delegate, activity, role, identity).await, + ( + ApiCommand::Activity(ActivityCommand::Create { id, namespace, attributes }), + identity, + ) => self.create_activity(id, namespace, attributes, identity).await, + ( + ApiCommand::Activity(ActivityCommand::Instant { id, namespace, time, agent }), + identity, + ) => self.instant(id, namespace, time, agent, identity).await, + ( + ApiCommand::Activity(ActivityCommand::Start { id, namespace, time, agent }), + identity, + ) => self.start_activity(id, namespace, time, agent, identity).await, + ( + ApiCommand::Activity(ActivityCommand::End { id, namespace, time, agent }), + identity, + ) => self.end_activity(id, namespace, time, agent, identity).await, + (ApiCommand::Activity(ActivityCommand::Use { id, namespace, activity }), identity) => + self.activity_use(id, namespace, activity, identity).await, + ( + ApiCommand::Activity(ActivityCommand::WasInformedBy { + id, + namespace, + informing_activity, + }), + identity, + ) => self.activity_was_informed_by(id, namespace, informing_activity, identity).await, + ( + ApiCommand::Activity(ActivityCommand::Associate { + id, + namespace, + responsible, + role, + }), + identity, + ) => self.associate(namespace, responsible, id, role, identity).await, + ( + ApiCommand::Entity(EntityCommand::Attribute { id, namespace, responsible, role }), + identity, + ) => self.attribute(namespace, responsible, id, role, identity).await, + (ApiCommand::Entity(EntityCommand::Create { id, namespace, attributes }), identity) => + self.create_entity(EntityId::from_external_id(&id), namespace, attributes, identity) + .await, + ( + ApiCommand::Activity(ActivityCommand::Generate { id, namespace, activity }), + identity, + ) => self.activity_generate(id, namespace, activity, identity).await, + ( + ApiCommand::Entity(EntityCommand::Derive { + id, + namespace, + activity, + used_entity, + derivation, + }), + identity, + ) => + self.entity_derive(id, namespace, activity, used_entity, derivation, identity) + .await, + (ApiCommand::Query(query), _identity) => self.query(query).await, + } + } + + #[instrument(skip(self))] + async fn delegate( + &self, + namespace: ExternalId, + responsible_id: AgentId, + delegate_id: AgentId, + activity_id: Option, + role: Option, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let tx = ChronicleOperation::agent_acts_on_behalf_of( + namespace, + responsible_id.clone(), + delegate_id, + activity_id, + role, + ); + + to_apply.push(tx); + + api.apply_effects_and_submit( + connection, + responsible_id, + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + #[instrument(skip(self))] + async fn associate( + &self, + namespace: ExternalId, + responsible_id: AgentId, + activity_id: ActivityId, + role: Option, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let tx = ChronicleOperation::was_associated_with( + namespace, + activity_id, + responsible_id.clone(), + role, + ); + + to_apply.push(tx); + + api.apply_effects_and_submit( + connection, + responsible_id, + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + #[instrument(skip(self))] + async fn attribute( + &self, + namespace: ExternalId, + responsible_id: AgentId, + entity_id: EntityId, + role: Option, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let tx = ChronicleOperation::was_attributed_to( + namespace, + entity_id, + responsible_id.clone(), + role, + ); + + to_apply.push(tx); + + api.apply_effects_and_submit( + connection, + responsible_id, + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + #[instrument(skip(self))] + async fn entity_derive( + &self, + id: EntityId, + namespace: ExternalId, + activity_id: Option, + used_id: EntityId, + typ: DerivationType, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let tx = ChronicleOperation::EntityDerive(EntityDerive { + namespace, + id: id.clone(), + used_id: used_id.clone(), + activity_id: activity_id.clone(), + typ, + }); + + to_apply.push(tx); + + api.apply_effects_and_submit( + connection, + id, + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + async fn query(&self, query: QueryCommand) -> Result { + let api = self.clone(); + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + + let (id, _) = api + .store + .namespace_by_external_id(&mut connection, &ExternalId::from(&query.namespace))?; + Ok(ApiResponse::query_reply(api.store.load_prov_model_for_namespace(&mut connection, &id)?)) + }) + .await? + } + + async fn submit_import_operations( + &self, + identity: AuthId, + operations: Vec, + ) -> Result { + let mut api = self.clone(); + let identity = identity.signed_identity(&self.signing)?; + let model = ProvModel::from_tx(&operations)?; + let signer = self.signing.clone(); + tokio::task::spawn_blocking(move || { + // Check here to ensure that import operations result in data changes + let mut connection = api.store.connection()?; + connection.build_transaction().run(|connection| { + if let Some(operations_to_apply) = api.check_for_effects(connection, &operations)? { + trace!( + operations_to_apply = operations_to_apply.len(), + "Import operations submitted" + ); + let tx_id = api.submit_blocking(futures::executor::block_on( + ChronicleTransaction::new(&signer, identity, operations_to_apply), + )?)?; + Ok(ApiResponse::import_submitted(model, tx_id)) + } else { + info!("Import will not result in any data changes"); + Ok(ApiResponse::AlreadyRecordedAll) + } + }) + }) + .await? + } + + #[instrument(level = "trace", skip(self), ret(Debug))] + async fn sync( + &self, + prov: Box, + block_id: &BlockId, + tx_id: ChronicleTransactionId, + ) -> Result { + let api = self.clone(); + let block_id = *block_id; + tokio::task::spawn_blocking(move || { + api.store.apply_prov(&prov)?; + api.store.set_last_block_id(&block_id, tx_id)?; + + Ok(ApiResponse::Unit) + }) + .await? + } + + /// Creates and submits a (ChronicleTransaction::StartActivity) determining the appropriate + /// agent by external_id, or via [use_agent] context + #[instrument(skip(self))] + async fn instant( + &self, + id: ActivityId, + namespace: ExternalId, + time: Option>, + agent: Option, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let agent_id = { + if let Some(agent) = agent { + Some(agent) + } else { + api.store + .get_current_agent(connection) + .ok() + .map(|x| AgentId::from_external_id(x.external_id)) + } + }; + + let now = Utc::now(); + + to_apply.push(ChronicleOperation::StartActivity(StartActivity { + namespace: namespace.clone(), + id: id.clone(), + time: time.unwrap_or(now).into(), + })); + + to_apply.push(ChronicleOperation::EndActivity(EndActivity { + namespace: namespace.clone(), + id: id.clone(), + time: time.unwrap_or(now).into(), + })); + + if let Some(agent_id) = agent_id { + to_apply.push(ChronicleOperation::was_associated_with( + namespace, + id.clone(), + agent_id, + None, + )); + } + + api.apply_effects_and_submit( + connection, + id, + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + /// Creates and submits a (ChronicleTransaction::StartActivity), determining the appropriate + /// agent by name, or via [use_agent] context + #[instrument(skip(self))] + async fn start_activity( + &self, + id: ActivityId, + namespace: ExternalId, + time: Option>, + agent: Option, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let agent_id = { + if let Some(agent) = agent { + Some(agent) + } else { + api.store + .get_current_agent(connection) + .ok() + .map(|x| AgentId::from_external_id(x.external_id)) + } + }; + + to_apply.push(ChronicleOperation::StartActivity(StartActivity { + namespace: namespace.clone(), + id: id.clone(), + time: time.unwrap_or_else(Utc::now).into(), + })); + + if let Some(agent_id) = agent_id { + to_apply.push(ChronicleOperation::was_associated_with( + namespace, + id.clone(), + agent_id, + None, + )); + } + + api.apply_effects_and_submit( + connection, + id, + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + /// Creates and submits a (ChronicleTransaction::EndActivity), determining the appropriate agent + /// by name or via [use_agent] context + #[instrument(skip(self))] + async fn end_activity( + &self, + id: ActivityId, + namespace: ExternalId, + time: Option>, + agent: Option, + identity: AuthId, + ) -> Result { + let mut api = self.clone(); + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + connection.build_transaction().run(|connection| { + let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; + + let applying_new_namespace = !to_apply.is_empty(); + + let agent_id = { + if let Some(agent) = agent { + Some(agent) + } else { + api.store + .get_current_agent(connection) + .ok() + .map(|x| AgentId::from_external_id(x.external_id)) + } + }; + + to_apply.push(ChronicleOperation::EndActivity(EndActivity { + namespace: namespace.clone(), + id: id.clone(), + time: time.unwrap_or_else(Utc::now).into(), + })); + + if let Some(agent_id) = agent_id { + to_apply.push(ChronicleOperation::was_associated_with( + namespace, + id.clone(), + agent_id, + None, + )); + } + + api.apply_effects_and_submit( + connection, + id, + identity, + to_apply, + applying_new_namespace, + ) + }) + }) + .await? + } + + #[instrument(skip(self))] + async fn use_agent_in_cli_context( + &self, + id: AgentId, + namespace: ExternalId, + ) -> Result { + let api = self.clone(); + tokio::task::spawn_blocking(move || { + let mut connection = api.store.connection()?; + + connection.build_transaction().run(|connection| { + api.store.apply_use_agent(connection, id.external_id_part(), &namespace) + })?; + + Ok(ApiResponse::Unit) + }) + .await? + } +} + +pub trait UuidGen { + fn uuid() -> Uuid { + Uuid::new_v4() + } +} + +fn install_prometheus_metrics_exporter() { + let metrics_endpoint = "127.0.0.1:9000"; + let metrics_listen_socket = match metrics_endpoint.parse::() { + Ok(addr) => addr, + Err(e) => { + error!("Unable to parse metrics listen socket address: {e:?}"); + return; + } + }; + + if let Err(e) = PrometheusBuilder::new().with_http_listener(metrics_listen_socket).install() { + error!("Prometheus exporter installation for liveness check metrics failed: {e:?}"); + } else { + debug!("Liveness check metrics Prometheus exporter installed with endpoint on {metrics_endpoint}/metrics"); + } +} diff --git a/crates/api/src/chronicle_graphql/activity.rs b/crates/api/src/chronicle_graphql/activity.rs index 99c68e6d1..005c18e8e 100644 --- a/crates/api/src/chronicle_graphql/activity.rs +++ b/crates/api/src/chronicle_graphql/activity.rs @@ -1,174 +1,173 @@ +use std::collections::HashMap; + use async_graphql::Context; -use chronicle_persistence::{ - queryable::{Activity, Agent, Entity, Namespace}, - Store, -}; -use common::prov::Role; use diesel::prelude::*; -use std::collections::HashMap; + +use chronicle_persistence::queryable::{Activity, Agent, Entity, Namespace}; +use common::prov::Role; use crate::chronicle_graphql::DatabaseContext; pub async fn namespace<'a>( - namespaceid: i32, - ctx: &Context<'a>, + namespaceid: i32, + ctx: &Context<'a>, ) -> async_graphql::Result { - use chronicle_persistence::schema::namespace::{self, dsl}; - let store = ctx.data::()?; + use chronicle_persistence::schema::namespace::{self, dsl}; + let store = ctx.data::()?; - let mut connection = store.connection()?; + let mut connection = store.connection()?; - Ok(namespace::table - .filter(dsl::id.eq(namespaceid)) - .first::(&mut connection)?) + Ok(namespace::table + .filter(dsl::id.eq(namespaceid)) + .first::(&mut connection)?) } pub async fn was_associated_with<'a>( - id: i32, - ctx: &Context<'a>, + id: i32, + ctx: &Context<'a>, ) -> async_graphql::Result, Option, Option)>> { - use chronicle_persistence::schema::{agent, association, delegation}; - - #[derive(Queryable)] - struct DelegationAgents { - responsible_id: i32, - delegate: Agent, - role: String, - } - - let store = ctx.data::()?; - let mut connection = store.connection()?; - - let delegation_entries = delegation::table - .filter(delegation::dsl::activity_id.eq(id)) - .inner_join(agent::table.on(agent::id.eq(delegation::delegate_id))) - .select((delegation::responsible_id, Agent::as_select(), delegation::role)) - .load::(&mut connection)? - .into_iter(); - - let mut agent_reservoir = HashMap::new(); - let mut agent_delegations = HashMap::new(); - - for delegation_entry in delegation_entries { - let delegate_id = delegation_entry.delegate.id; - agent_reservoir.insert(delegate_id, delegation_entry.delegate); - agent_delegations.insert( - delegation_entry.responsible_id, - ( - delegate_id, - if delegation_entry.role.is_empty() { - None - } else { - Some(Role(delegation_entry.role)) - }, - ), - ); - } - - let res = association::table - .filter(association::dsl::activity_id.eq(id)) - .inner_join(chronicle_persistence::schema::agent::table) - .order(chronicle_persistence::schema::agent::external_id) - .select((Agent::as_select(), association::role)) - .load::<(Agent, Role)>(&mut connection)? - .into_iter() - .map(|(responsible_agent, responsible_role)| { - let responsible_role = - if responsible_role.0.is_empty() { None } else { Some(responsible_role) }; - let (delegate_agent, delegate_role): (Option, Option) = - match agent_delegations.get(&responsible_agent.id) { - Some((delegate_id, optional_role)) => { - let delegate = agent_reservoir.remove(delegate_id).unwrap_or_else(|| { - agent::table.find(delegate_id).first::(&mut connection).unwrap() - }); - let optional_role = optional_role.as_ref().cloned(); - (Some(delegate), optional_role) - }, - None => (None, None), - }; - (responsible_agent, responsible_role, delegate_agent, delegate_role) - }) - .collect(); - - Ok(res) + use chronicle_persistence::schema::{agent, association, delegation}; + + #[derive(Queryable)] + struct DelegationAgents { + responsible_id: i32, + delegate: Agent, + role: String, + } + + let store = ctx.data::()?; + let mut connection = store.connection()?; + + let delegation_entries = delegation::table + .filter(delegation::dsl::activity_id.eq(id)) + .inner_join(agent::table.on(agent::id.eq(delegation::delegate_id))) + .select((delegation::responsible_id, Agent::as_select(), delegation::role)) + .load::(&mut connection)? + .into_iter(); + + let mut agent_reservoir = HashMap::new(); + let mut agent_delegations = HashMap::new(); + + for delegation_entry in delegation_entries { + let delegate_id = delegation_entry.delegate.id; + agent_reservoir.insert(delegate_id, delegation_entry.delegate); + agent_delegations.insert( + delegation_entry.responsible_id, + ( + delegate_id, + if delegation_entry.role.is_empty() { + None + } else { + Some(Role(delegation_entry.role)) + }, + ), + ); + } + + let res = association::table + .filter(association::dsl::activity_id.eq(id)) + .inner_join(chronicle_persistence::schema::agent::table) + .order(chronicle_persistence::schema::agent::external_id) + .select((Agent::as_select(), association::role)) + .load::<(Agent, Role)>(&mut connection)? + .into_iter() + .map(|(responsible_agent, responsible_role)| { + let responsible_role = + if responsible_role.0.is_empty() { None } else { Some(responsible_role) }; + let (delegate_agent, delegate_role): (Option, Option) = + match agent_delegations.get(&responsible_agent.id) { + Some((delegate_id, optional_role)) => { + let delegate = agent_reservoir.remove(delegate_id).unwrap_or_else(|| { + agent::table.find(delegate_id).first::(&mut connection).unwrap() + }); + let optional_role = optional_role.as_ref().cloned(); + (Some(delegate), optional_role) + } + None => (None, None), + }; + (responsible_agent, responsible_role, delegate_agent, delegate_role) + }) + .collect(); + + Ok(res) } pub async fn used<'a>(id: i32, ctx: &Context<'a>) -> async_graphql::Result> { - use chronicle_persistence::schema::usage::{self, dsl}; + use chronicle_persistence::schema::usage::{self, dsl}; - let store = ctx.data::()?; + let store = ctx.data::()?; - let mut connection = store.connection()?; + let mut connection = store.connection()?; - let res = usage::table - .filter(dsl::activity_id.eq(id)) - .inner_join(chronicle_persistence::schema::entity::table) - .order(chronicle_persistence::schema::entity::external_id) - .select(Entity::as_select()) - .load::(&mut connection)?; + let res = usage::table + .filter(dsl::activity_id.eq(id)) + .inner_join(chronicle_persistence::schema::entity::table) + .order(chronicle_persistence::schema::entity::external_id) + .select(Entity::as_select()) + .load::(&mut connection)?; - Ok(res) + Ok(res) } pub async fn was_informed_by<'a>( - id: i32, - ctx: &Context<'a>, + id: i32, + ctx: &Context<'a>, ) -> async_graphql::Result> { - use chronicle_persistence::schema::wasinformedby::{self, dsl}; + use chronicle_persistence::schema::wasinformedby::{self, dsl}; - let store = ctx.data::()?; + let store = ctx.data::()?; - let mut connection = store.connection()?; + let mut connection = store.connection()?; - let res = wasinformedby::table - .filter(dsl::activity_id.eq(id)) - .inner_join(chronicle_persistence::schema::activity::table.on( - wasinformedby::informing_activity_id.eq(chronicle_persistence::schema::activity::id), - )) - .order(chronicle_persistence::schema::activity::external_id) - .select(Activity::as_select()) - .load::(&mut connection)?; + let res = wasinformedby::table + .filter(dsl::activity_id.eq(id)) + .inner_join(chronicle_persistence::schema::activity::table.on( + wasinformedby::informing_activity_id.eq(chronicle_persistence::schema::activity::id), + )) + .order(chronicle_persistence::schema::activity::external_id) + .select(Activity::as_select()) + .load::(&mut connection)?; - Ok(res) + Ok(res) } pub async fn generated<'a>(id: i32, ctx: &Context<'a>) -> async_graphql::Result> { - use chronicle_persistence::schema::generation::{self, dsl}; + use chronicle_persistence::schema::generation::{self, dsl}; - let store = ctx.data::()?; + let store = ctx.data::()?; - let mut connection = store.connection()?; + let mut connection = store.connection()?; - let res = generation::table - .filter(dsl::activity_id.eq(id)) - .inner_join(chronicle_persistence::schema::entity::table) - .select(Entity::as_select()) - .load::(&mut connection)?; + let res = generation::table + .filter(dsl::activity_id.eq(id)) + .inner_join(chronicle_persistence::schema::entity::table) + .select(Entity::as_select()) + .load::(&mut connection)?; - Ok(res) + Ok(res) } pub async fn load_attribute<'a>( - id: i32, - external_id: &str, - ctx: &Context<'a>, + id: i32, + external_id: &str, + ctx: &Context<'a>, ) -> async_graphql::Result> { - use chronicle_persistence::schema::activity_attribute; - - let store = ctx.data::()?; - - let mut connection = store.connection()?; - - Ok(activity_attribute::table - .filter( - activity_attribute::activity_id - .eq(id) - .and(activity_attribute::typename.eq(external_id)), - ) - .select(activity_attribute::value) - .first::(&mut connection) - .optional()? - .as_deref() - .map(serde_json::from_str) - .transpose()?) + use chronicle_persistence::schema::activity_attribute; + + let store = ctx.data::()?; + + let mut connection = store.connection()?; + + Ok(activity_attribute::table + .filter( + activity_attribute::activity_id + .eq(id) + .and(activity_attribute::typename.eq(external_id)), + ) + .select(activity_attribute::value) + .first::(&mut connection) + .optional()? + .as_deref() + .map(serde_json::from_str) + .transpose()?) } diff --git a/crates/api/src/chronicle_graphql/agent.rs b/crates/api/src/chronicle_graphql/agent.rs index 1f5a14f14..a9681d318 100644 --- a/crates/api/src/chronicle_graphql/agent.rs +++ b/crates/api/src/chronicle_graphql/agent.rs @@ -1,94 +1,92 @@ use async_graphql::Context; -use chronicle_persistence::{ - queryable::{Agent, Entity, Namespace}, - Store, -}; -use common::prov::Role; use diesel::prelude::*; +use chronicle_persistence::queryable::{Agent, Entity, Namespace}; +use common::prov::Role; + use crate::chronicle_graphql::DatabaseContext; pub async fn namespace<'a>( - namespace_id: i32, - ctx: &Context<'a>, + namespace_id: i32, + ctx: &Context<'a>, ) -> async_graphql::Result { - use chronicle_persistence::schema::namespace::{self, dsl}; - let store = ctx.data::()?; + use chronicle_persistence::schema::namespace::{self, dsl}; + let store = ctx.data::()?; - let mut connection = store.connection()?; + let mut connection = store.connection()?; - Ok(namespace::table - .filter(dsl::id.eq(namespace_id)) - .first::(&mut connection)?) + Ok(namespace::table + .filter(dsl::id.eq(namespace_id)) + .first::(&mut connection)?) } pub async fn acted_on_behalf_of<'a>( - id: i32, - ctx: &Context<'a>, + id: i32, + ctx: &Context<'a>, ) -> async_graphql::Result)>> { - use chronicle_persistence::schema::{ - agent as agentdsl, - delegation::{self, dsl}, - }; - - let store = ctx.data::()?; - - let mut connection = store.connection()?; - - Ok(delegation::table - .filter(dsl::delegate_id.eq(id)) - .inner_join(agentdsl::table.on(dsl::responsible_id.eq(agentdsl::id))) - .order(agentdsl::external_id) - .select((Agent::as_select(), dsl::role)) - .load::<(Agent, Role)>(&mut connection)? - .into_iter() - .map(|(a, r)| (a, if r.0.is_empty() { None } else { Some(r) })) - .collect()) + use chronicle_persistence::schema::{ + agent as agentdsl, + delegation::{self, dsl}, + }; + + let store = ctx.data::()?; + + let mut connection = store.connection()?; + + Ok(delegation::table + .filter(dsl::delegate_id.eq(id)) + .inner_join(agentdsl::table.on(dsl::responsible_id.eq(agentdsl::id))) + .order(agentdsl::external_id) + .select((Agent::as_select(), dsl::role)) + .load::<(Agent, Role)>(&mut connection)? + .into_iter() + .map(|(a, r)| (a, if r.0.is_empty() { None } else { Some(r) })) + .collect()) } /// Return the entities an agent has attributed to it along with the roles in which they were /// attributed pub async fn attribution<'a>( - id: i32, - ctx: &Context<'a>, + id: i32, + ctx: &Context<'a>, ) -> async_graphql::Result)>> { - use chronicle_persistence::schema::{ - attribution::{self, dsl}, - entity as entity_dsl, - }; - - let store = ctx.data::()?; - - let mut connection = store.connection()?; - - Ok(attribution::table - .filter(dsl::agent_id.eq(id)) - .inner_join(entity_dsl::table.on(dsl::entity_id.eq(entity_dsl::id))) - .order(entity_dsl::external_id) - .select((Entity::as_select(), dsl::role)) - .load::<(Entity, Role)>(&mut connection)? - .into_iter() - .map(|(entity, role)| (entity, if role.0.is_empty() { None } else { Some(role) })) - .collect()) + use chronicle_persistence::schema::{ + attribution::{self, dsl}, + entity as entity_dsl, + }; + + let store = ctx.data::()?; + + let mut connection = store.connection()?; + + Ok(attribution::table + .filter(dsl::agent_id.eq(id)) + .inner_join(entity_dsl::table.on(dsl::entity_id.eq(entity_dsl::id))) + .order(entity_dsl::external_id) + .select((Entity::as_select(), dsl::role)) + .load::<(Entity, Role)>(&mut connection)? + .into_iter() + .map(|(entity, role)| (entity, if role.0.is_empty() { None } else { Some(role) })) + .collect()) } pub async fn load_attribute<'a>( - id: i32, - external_id: &str, - ctx: &Context<'a>, + id: i32, + external_id: &str, + ctx: &Context<'a>, ) -> async_graphql::Result> { - use chronicle_persistence::schema::agent_attribute; + use chronicle_persistence::schema::agent_attribute; - let store = ctx.data::()?; + let store = ctx.data::()?; - let mut connection = store.connection()?; + let mut connection = store.connection()?; - Ok(agent_attribute::table - .filter(agent_attribute::agent_id.eq(id).and(agent_attribute::typename.eq(external_id))) - .select(agent_attribute::value) - .first::(&mut connection) - .optional()? - .as_deref() - .map(serde_json::from_str) - .transpose()?) + Ok(agent_attribute::table + .filter(agent_attribute::agent_id.eq(id).and(agent_attribute::typename.eq(external_id))) + .select(agent_attribute::value) + .first::(&mut connection) + .optional()? + .as_deref() + .map(serde_json::from_str) + .transpose()?) } diff --git a/crates/api/src/chronicle_graphql/authorization.rs b/crates/api/src/chronicle_graphql/authorization.rs index 842d87159..7602c6d70 100644 --- a/crates/api/src/chronicle_graphql/authorization.rs +++ b/crates/api/src/chronicle_graphql/authorization.rs @@ -1,9 +1,10 @@ +use std::{sync::Arc, time::Duration}; + use base64::Engine; use cached::{Cached, TimedCache}; use jwtk::jwk::RemoteJwksVerifier; use reqwest::StatusCode; use serde_json::{Map, Value}; -use std::{sync::Arc, time::Duration}; use thiserror::Error; use tokio::sync::Mutex; use tracing::instrument; @@ -12,194 +13,194 @@ use super::{JwksUri, UserInfoUri}; #[derive(Debug, Error)] pub enum Error { - #[error("Base64 decoding failure: {0}", source)] - Base64 { - #[from] - #[source] - source: base64::DecodeError, - }, - #[error("JSON decoding failure: {0}", source)] - Json { - #[from] - #[source] - source: serde_json::Error, - }, - #[error("JWT validation failure: {0}", source)] - Jwks { - #[from] - #[source] - source: jwtk::Error, - }, - #[error("web access failure: {0}", source)] - Reqwest { - #[from] - #[source] - source: reqwest::Error, - }, - #[error("formatting error: {0}", message)] - Format { message: String }, - #[error("unexpected response: {0} responded with status {1}", server, status)] - UnexpectedResponse { server: String, status: StatusCode }, + #[error("Base64 decoding failure: {0}", source)] + Base64 { + #[from] + #[source] + source: base64::DecodeError, + }, + #[error("JSON decoding failure: {0}", source)] + Json { + #[from] + #[source] + source: serde_json::Error, + }, + #[error("JWT validation failure: {0}", source)] + Jwks { + #[from] + #[source] + source: jwtk::Error, + }, + #[error("web access failure: {0}", source)] + Reqwest { + #[from] + #[source] + source: reqwest::Error, + }, + #[error("formatting error: {0}", message)] + Format { message: String }, + #[error("unexpected response: {0} responded with status {1}", server, status)] + UnexpectedResponse { server: String, status: StatusCode }, } #[derive(Clone)] pub struct TokenChecker { - client: reqwest::Client, - verifier: Option>, - jwks_uri: Option, - userinfo_uri: Option, - userinfo_cache: Arc>>>, + client: reqwest::Client, + verifier: Option>, + jwks_uri: Option, + userinfo_uri: Option, + userinfo_cache: Arc>>>, } impl TokenChecker { - #[instrument(level = "debug")] - pub fn new( - jwks_uri: Option<&JwksUri>, - userinfo_uri: Option<&UserInfoUri>, - cache_expiry_seconds: u32, - ) -> Self { - Self { - client: reqwest::Client::new(), - verifier: jwks_uri.map(|uri| { - { - RemoteJwksVerifier::new( - uri.full_uri(), - None, - Duration::from_secs(cache_expiry_seconds.into()), - ) - } - .into() - }), - jwks_uri: jwks_uri.cloned(), - userinfo_uri: userinfo_uri.cloned(), - userinfo_cache: Arc::new(Mutex::new(TimedCache::with_lifespan( - cache_expiry_seconds.into(), - ))), - } - } + #[instrument(level = "debug")] + pub fn new( + jwks_uri: Option<&JwksUri>, + userinfo_uri: Option<&UserInfoUri>, + cache_expiry_seconds: u32, + ) -> Self { + Self { + client: reqwest::Client::new(), + verifier: jwks_uri.map(|uri| { + { + RemoteJwksVerifier::new( + uri.full_uri(), + None, + Duration::from_secs(cache_expiry_seconds.into()), + ) + } + .into() + }), + jwks_uri: jwks_uri.cloned(), + userinfo_uri: userinfo_uri.cloned(), + userinfo_cache: Arc::new(Mutex::new(TimedCache::with_lifespan( + cache_expiry_seconds.into(), + ))), + } + } - pub async fn check_status(&self) -> Result<(), Error> { - if let Some(uri) = &self.jwks_uri { - let status = self.client.get(uri.full_uri()).send().await?.status(); - // should respond with JSON web key set - if !status.is_success() { - tracing::warn!("{uri:?} returns {status}"); - return Err(Error::UnexpectedResponse { server: format!("{uri:?}"), status }); - } - } - if let Some(uri) = &self.userinfo_uri { - let status = self.client.get(uri.full_uri()).send().await?.status(); - // should require an authorization token - if !status.is_client_error() || status == StatusCode::NOT_FOUND { - tracing::warn!("{uri:?} without authorization token returns {status}"); - return Err(Error::UnexpectedResponse { server: format!("{uri:?}"), status }); - } - } - Ok(()) - } + pub async fn check_status(&self) -> Result<(), Error> { + if let Some(uri) = &self.jwks_uri { + let status = self.client.get(uri.full_uri()).send().await?.status(); + // should respond with JSON web key set + if !status.is_success() { + tracing::warn!("{uri:?} returns {status}"); + return Err(Error::UnexpectedResponse { server: format!("{uri:?}"), status }); + } + } + if let Some(uri) = &self.userinfo_uri { + let status = self.client.get(uri.full_uri()).send().await?.status(); + // should require an authorization token + if !status.is_client_error() || status == StatusCode::NOT_FOUND { + tracing::warn!("{uri:?} without authorization token returns {status}"); + return Err(Error::UnexpectedResponse { server: format!("{uri:?}"), status }); + } + } + Ok(()) + } - #[instrument(level = "trace", skip_all, err)] - async fn attempt_jwt(&self, token: &str) -> Result, Error> { - use base64::engine::general_purpose::{GeneralPurpose, URL_SAFE_NO_PAD}; - const BASE64_ENGINE: GeneralPurpose = URL_SAFE_NO_PAD; + #[instrument(level = "trace", skip_all, err)] + async fn attempt_jwt(&self, token: &str) -> Result, Error> { + use base64::engine::general_purpose::{GeneralPurpose, URL_SAFE_NO_PAD}; + const BASE64_ENGINE: GeneralPurpose = URL_SAFE_NO_PAD; - if let Some(verifier) = &self.verifier { - verifier.verify::>(token).await?; - } else { - return Err(Error::Format { message: "no JWKS endpoint configured".to_string() }); - } + if let Some(verifier) = &self.verifier { + verifier.verify::>(token).await?; + } else { + return Err(Error::Format { message: "no JWKS endpoint configured".to_string() }); + } - // JWT is composed of three base64-encoded components - let components = token - .split('.') - .map(|component| BASE64_ENGINE.decode(component)) - .collect::>, base64::DecodeError>>()?; - if components.len() != 3 { - return Err(Error::Format { message: format!("JWT has unexpected format: {token}") }); - }; + // JWT is composed of three base64-encoded components + let components = token + .split('.') + .map(|component| BASE64_ENGINE.decode(component)) + .collect::>, base64::DecodeError>>()?; + if components.len() != 3 { + return Err(Error::Format { message: format!("JWT has unexpected format: {token}") }); + }; - if let Value::Object(claims) = serde_json::from_slice(components[1].as_slice())? { - Ok(claims) - } else { - Err(Error::Format { - message: format!("JWT claims have unexpected format: {:?}", components[1]), - }) - } - } + if let Value::Object(claims) = serde_json::from_slice(components[1].as_slice())? { + Ok(claims) + } else { + Err(Error::Format { + message: format!("JWT claims have unexpected format: {:?}", components[1]), + }) + } + } - #[instrument(level = "debug", skip_all, err)] - pub async fn verify_token(&self, token: &str) -> Result, Error> { - let mut claims = Map::new(); - let mut error = None; - match self.attempt_jwt(token).await { - Ok(claims_as_provided) => claims.extend(claims_as_provided), - Err(Error::Jwks { source }) => { - match source { - jwtk::Error::IoError(_) | jwtk::Error::Reqwest(_) => { - tracing::error!(fatal_error = ?source); - super::trigger_shutdown(); - }, - _ => (), - } - return Err(Error::Jwks { source }); // abort on JWKS verifier failure - }, - Err(err) => error = Some(err), // could tolerate error from what may be opaque token - }; - if let Some(userinfo_uri) = &self.userinfo_uri { - let mut cache = self.userinfo_cache.lock().await; - if let Some(claims_from_userinfo) = cache.cache_get(&token.to_string()) { - tracing::trace!("userinfo cache hit"); - error = None; - claims.extend(claims_from_userinfo.clone()); - } else { - tracing::trace!("userinfo cache miss"); - drop(cache); - let request = self - .client - .get(userinfo_uri.full_uri()) - .header("Authorization", format!("Bearer {token}")); - let response = request.send().await?; - cache = self.userinfo_cache.lock().await; - if response.status() == 200 { - let response_text = &response.text().await?; - if let Ok(claims_from_userinfo) = self.attempt_jwt(response_text).await { - error = None; - claims.extend(claims_from_userinfo.clone()); - cache.cache_set(token.to_string(), claims_from_userinfo); - } else if let Ok(Value::Object(claims_from_userinfo)) = - serde_json::from_str(response_text) - { - error = None; - claims.extend(claims_from_userinfo.clone()); - cache.cache_set(token.to_string(), claims_from_userinfo); - } else { - error = Some(Error::Format { - message: format!( - "UserInfo response has unexpected format: {response_text}" - ), - }); - tracing::error!(fatal_error = ?error.as_ref().unwrap()); - super::trigger_shutdown(); - } - } else { - if error.is_some() { - tracing::trace!("first error before UserInfo was {error:?}"); - } - error = Some(Error::UnexpectedResponse { - server: format!("{userinfo_uri:?}"), - status: response.status(), - }); - if response.status() != StatusCode::UNAUTHORIZED { - tracing::error!(fatal_error = ?error.as_ref().unwrap()); - super::trigger_shutdown(); - } - } - } - } - if let Some(error) = error { - Err(error) - } else { - Ok(claims) - } - } + #[instrument(level = "debug", skip_all, err)] + pub async fn verify_token(&self, token: &str) -> Result, Error> { + let mut claims = Map::new(); + let mut error = None; + match self.attempt_jwt(token).await { + Ok(claims_as_provided) => claims.extend(claims_as_provided), + Err(Error::Jwks { source }) => { + match source { + jwtk::Error::IoError(_) | jwtk::Error::Reqwest(_) => { + tracing::error!(fatal_error = ?source); + super::trigger_shutdown(); + } + _ => (), + } + return Err(Error::Jwks { source }); // abort on JWKS verifier failure + } + Err(err) => error = Some(err), // could tolerate error from what may be opaque token + }; + if let Some(userinfo_uri) = &self.userinfo_uri { + let mut cache = self.userinfo_cache.lock().await; + if let Some(claims_from_userinfo) = cache.cache_get(&token.to_string()) { + tracing::trace!("userinfo cache hit"); + error = None; + claims.extend(claims_from_userinfo.clone()); + } else { + tracing::trace!("userinfo cache miss"); + drop(cache); + let request = self + .client + .get(userinfo_uri.full_uri()) + .header("Authorization", format!("Bearer {token}")); + let response = request.send().await?; + cache = self.userinfo_cache.lock().await; + if response.status() == 200 { + let response_text = &response.text().await?; + if let Ok(claims_from_userinfo) = self.attempt_jwt(response_text).await { + error = None; + claims.extend(claims_from_userinfo.clone()); + cache.cache_set(token.to_string(), claims_from_userinfo); + } else if let Ok(Value::Object(claims_from_userinfo)) = + serde_json::from_str(response_text) + { + error = None; + claims.extend(claims_from_userinfo.clone()); + cache.cache_set(token.to_string(), claims_from_userinfo); + } else { + error = Some(Error::Format { + message: format!( + "UserInfo response has unexpected format: {response_text}" + ), + }); + tracing::error!(fatal_error = ?error.as_ref().unwrap()); + super::trigger_shutdown(); + } + } else { + if error.is_some() { + tracing::trace!("first error before UserInfo was {error:?}"); + } + error = Some(Error::UnexpectedResponse { + server: format!("{userinfo_uri:?}"), + status: response.status(), + }); + if response.status() != StatusCode::UNAUTHORIZED { + tracing::error!(fatal_error = ?error.as_ref().unwrap()); + super::trigger_shutdown(); + } + } + } + } + if let Some(error) = error { + Err(error) + } else { + Ok(claims) + } + } } diff --git a/crates/api/src/chronicle_graphql/cursor_project.rs b/crates/api/src/chronicle_graphql/cursor_project.rs index 2f773e014..46fd72ac7 100644 --- a/crates/api/src/chronicle_graphql/cursor_project.rs +++ b/crates/api/src/chronicle_graphql/cursor_project.rs @@ -1,31 +1,31 @@ use async_graphql::{ - connection::{Edge, EmptyFields}, - OutputType, + connection::{Edge, EmptyFields}, + OutputType, }; pub fn project_to_nodes( - rx: I, - start: i64, - limit: i64, + rx: I, + start: i64, + limit: i64, ) -> async_graphql::connection::Connection -where - T: OutputType, - I: IntoIterator, + where + T: OutputType, + I: IntoIterator, { - let rx = Vec::from_iter(rx); - let mut gql = async_graphql::connection::Connection::new( - rx.first().map(|(_, _total)| start > 0).unwrap_or(false), - rx.first().map(|(_, total)| start + limit < *total).unwrap_or(false), - ); + let rx = Vec::from_iter(rx); + let mut gql = async_graphql::connection::Connection::new( + rx.first().map(|(_, _total)| start > 0).unwrap_or(false), + rx.first().map(|(_, total)| start + limit < *total).unwrap_or(false), + ); - gql.edges.append( - &mut rx - .into_iter() - .enumerate() - .map(|(pos, (agent, _count))| { - Edge::with_additional_fields((pos as i32) + (start as i32), agent, EmptyFields) - }) - .collect(), - ); - gql + gql.edges.append( + &mut rx + .into_iter() + .enumerate() + .map(|(pos, (agent, _count))| { + Edge::with_additional_fields((pos as i32) + (start as i32), agent, EmptyFields) + }) + .collect(), + ); + gql } diff --git a/crates/api/src/chronicle_graphql/entity.rs b/crates/api/src/chronicle_graphql/entity.rs index 2ba951186..177d30e70 100644 --- a/crates/api/src/chronicle_graphql/entity.rs +++ b/crates/api/src/chronicle_graphql/entity.rs @@ -1,154 +1,153 @@ use async_graphql::Context; -use chronicle_persistence::{ - queryable::{Activity, Agent, Entity, Namespace}, - Store, -}; -use common::prov::{operations::DerivationType, Role}; use diesel::prelude::*; +use chronicle_persistence::queryable::{Activity, Agent, Entity, Namespace}; +use common::prov::{operations::DerivationType, Role}; + use crate::chronicle_graphql::DatabaseContext; async fn typed_derivation<'a>( - id: i32, - ctx: &Context<'a>, - typ: DerivationType, + id: i32, + ctx: &Context<'a>, + typ: DerivationType, ) -> async_graphql::Result> { - use chronicle_persistence::schema::{ - derivation::{self, dsl}, - entity as entitydsl, - }; + use chronicle_persistence::schema::{ + derivation::{self, dsl}, + entity as entitydsl, + }; - let store = ctx.data::()?; + let store = ctx.data::()?; - let mut connection = store.connection()?; + let mut connection = store.connection()?; - let res = derivation::table - .filter(dsl::generated_entity_id.eq(id).and(dsl::typ.eq(typ))) - .inner_join(entitydsl::table.on(dsl::used_entity_id.eq(entitydsl::id))) - .select(Entity::as_select()) - .load::(&mut connection)?; + let res = derivation::table + .filter(dsl::generated_entity_id.eq(id).and(dsl::typ.eq(typ))) + .inner_join(entitydsl::table.on(dsl::used_entity_id.eq(entitydsl::id))) + .select(Entity::as_select()) + .load::(&mut connection)?; - Ok(res) + Ok(res) } pub async fn namespace<'a>( - namespace_id: i32, - ctx: &Context<'a>, + namespace_id: i32, + ctx: &Context<'a>, ) -> async_graphql::Result { - use chronicle_persistence::schema::namespace::{self, dsl}; + use chronicle_persistence::schema::namespace::{self, dsl}; - let store = ctx.data::()?; + let store = ctx.data::()?; - let mut connection = store.connection()?; + let mut connection = store.connection()?; - Ok(namespace::table - .filter(dsl::id.eq(namespace_id)) - .first::(&mut connection)?) + Ok(namespace::table + .filter(dsl::id.eq(namespace_id)) + .first::(&mut connection)?) } /// Return the agents to which an entity was attributed along with the roles in which it was /// attributed pub async fn was_attributed_to<'a>( - id: i32, - ctx: &Context<'a>, + id: i32, + ctx: &Context<'a>, ) -> async_graphql::Result)>> { - use chronicle_persistence::schema::{agent, attribution}; - - let store = ctx.data::()?; - let mut connection = store.connection()?; - - let res = attribution::table - .filter(attribution::dsl::entity_id.eq(id)) - .inner_join(agent::table) - .order(agent::external_id) - .select((Agent::as_select(), attribution::role)) - .load::<(Agent, Role)>(&mut connection)? - .into_iter() - .map(|(agent, role)| { - let role = if role.0.is_empty() { None } else { Some(role) }; - (agent, role) - }) - .collect(); - - Ok(res) + use chronicle_persistence::schema::{agent, attribution}; + + let store = ctx.data::()?; + let mut connection = store.connection()?; + + let res = attribution::table + .filter(attribution::dsl::entity_id.eq(id)) + .inner_join(agent::table) + .order(agent::external_id) + .select((Agent::as_select(), attribution::role)) + .load::<(Agent, Role)>(&mut connection)? + .into_iter() + .map(|(agent, role)| { + let role = if role.0.is_empty() { None } else { Some(role) }; + (agent, role) + }) + .collect(); + + Ok(res) } pub async fn was_generated_by<'a>( - id: i32, - ctx: &Context<'a>, + id: i32, + ctx: &Context<'a>, ) -> async_graphql::Result> { - use chronicle_persistence::schema::generation::{self, dsl}; + use chronicle_persistence::schema::generation::{self, dsl}; - let store = ctx.data::()?; + let store = ctx.data::()?; - let mut connection = store.connection()?; + let mut connection = store.connection()?; - let res = generation::table - .filter(dsl::generated_entity_id.eq(id)) - .inner_join(chronicle_persistence::schema::activity::table) - .select(Activity::as_select()) - .load::(&mut connection)?; + let res = generation::table + .filter(dsl::generated_entity_id.eq(id)) + .inner_join(chronicle_persistence::schema::activity::table) + .select(Activity::as_select()) + .load::(&mut connection)?; - Ok(res) + Ok(res) } pub async fn was_derived_from<'a>( - id: i32, - ctx: &Context<'a>, + id: i32, + ctx: &Context<'a>, ) -> async_graphql::Result> { - use chronicle_persistence::schema::{ - derivation::{self, dsl}, - entity as entitydsl, - }; + use chronicle_persistence::schema::{ + derivation::{self, dsl}, + entity as entitydsl, + }; - let store = ctx.data::()?; + let store = ctx.data::()?; - let mut connection = store.connection()?; + let mut connection = store.connection()?; - let res = derivation::table - .filter(dsl::generated_entity_id.eq(id)) - .inner_join(entitydsl::table.on(dsl::used_entity_id.eq(entitydsl::id))) - .select(Entity::as_select()) - .load::(&mut connection)?; + let res = derivation::table + .filter(dsl::generated_entity_id.eq(id)) + .inner_join(entitydsl::table.on(dsl::used_entity_id.eq(entitydsl::id))) + .select(Entity::as_select()) + .load::(&mut connection)?; - Ok(res) + Ok(res) } pub async fn had_primary_source<'a>( - id: i32, - ctx: &Context<'a>, + id: i32, + ctx: &Context<'a>, ) -> async_graphql::Result> { - typed_derivation(id, ctx, DerivationType::PrimarySource).await + typed_derivation(id, ctx, DerivationType::PrimarySource).await } pub async fn was_revision_of<'a>(id: i32, ctx: &Context<'a>) -> async_graphql::Result> { - typed_derivation(id, ctx, DerivationType::Revision).await + typed_derivation(id, ctx, DerivationType::Revision).await } + pub async fn was_quoted_from<'a>(id: i32, ctx: &Context<'a>) -> async_graphql::Result> { - typed_derivation(id, ctx, DerivationType::Quotation).await + typed_derivation(id, ctx, DerivationType::Quotation).await } pub async fn load_attribute<'a>( - id: i32, - external_id: &str, - ctx: &Context<'a>, + id: i32, + external_id: &str, + ctx: &Context<'a>, ) -> async_graphql::Result> { - use chronicle_persistence::schema::entity_attribute; - - let store = ctx.data::()?; - - let mut connection = store.connection()?; - - Ok(entity_attribute::table - .filter( - entity_attribute::entity_id - .eq(id) - .and(entity_attribute::typename.eq(external_id)), - ) - .select(entity_attribute::value) - .first::(&mut connection) - .optional()? - .as_deref() - .map(serde_json::from_str) - .transpose()?) + use chronicle_persistence::schema::entity_attribute; + + let store = ctx.data::()?; + + let mut connection = store.connection()?; + + Ok(entity_attribute::table + .filter( + entity_attribute::entity_id + .eq(id) + .and(entity_attribute::typename.eq(external_id)), + ) + .select(entity_attribute::value) + .first::(&mut connection) + .optional()? + .as_deref() + .map(serde_json::from_str) + .transpose()?) } diff --git a/crates/api/src/chronicle_graphql/mod.rs b/crates/api/src/chronicle_graphql/mod.rs index 1b1ba2a9e..c513e438e 100644 --- a/crates/api/src/chronicle_graphql/mod.rs +++ b/crates/api/src/chronicle_graphql/mod.rs @@ -1,6 +1,14 @@ +use std::{ + collections::{BTreeSet, HashMap}, + fmt::Display, + net::SocketAddr, + str::FromStr, + sync::Arc, +}; + use async_graphql::{ - http::{playground_source, GraphQLPlaygroundConfig, ALL_WEBSOCKET_PROTOCOLS}, - scalar, Context, Enum, Error, ErrorExtensions, ObjectType, Schema, ServerError, SimpleObject, + Context, + Enum, Error, ErrorExtensions, http::{ALL_WEBSOCKET_PROTOCOLS, GraphQLPlaygroundConfig, playground_source}, ObjectType, scalar, Schema, ServerError, SimpleObject, Subscription, SubscriptionType, }; use async_graphql_poem::{ @@ -8,51 +16,47 @@ use async_graphql_poem::{ GraphQLWebSocket, }; -use crate::Store; -use common::{ - identity::{AuthId, IdentityError, JwtClaims, OpaData, SignedIdentity}, - ledger::{SubmissionError, SubmissionStage}, - opa::std::{ExecutorContext, OpaExecutorError}, - prov::{ - json_ld::ToJson, ChronicleIri, ChronicleTransactionId, ExternalId, ExternalIdPart, - ProvModel, - }, -}; -use derivative::*; use diesel::{ + PgConnection, prelude::*, - r2d2::{ConnectionManager, Pool, PooledConnection}, - PgConnection, Queryable, + Queryable, r2d2::{ConnectionManager, Pool, PooledConnection}, }; use futures::Stream; use lazy_static::lazy_static; use poem::{ - get, handler, + Endpoint, get, + handler, http::{HeaderValue, StatusCode}, + IntoResponse, listener::{Listener, TcpListener}, - post, - web::{ + post, Route, Server, web::{ headers::authorization::{Bearer, Credentials}, Html, }, - Endpoint, IntoResponse, Route, Server, }; use serde::{Deserialize, Serialize}; use serde_json::json; -use std::{ - collections::{BTreeSet, HashMap}, - fmt::Display, - net::SocketAddr, - str::FromStr, - sync::Arc, -}; use thiserror::Error; use tokio::sync::{broadcast::error::RecvError, Semaphore}; use tracing::{debug, error, instrument, warn}; use url::Url; +use common::{ + identity::{AuthId, IdentityError, JwtClaims, OpaData, SignedIdentity}, + ledger::{SubmissionError, SubmissionStage}, + opa::std::{ExecutorContext, OpaExecutorError}, + prov::{ + ChronicleIri, ChronicleTransactionId, ExternalId, ExternalIdPart, json_ld::ToJson, + ProvModel, + }, +}; + +use crate::dispatch::ApiDispatch; +use crate::error::ApiError; +use crate::Store; +use crate::StoreError; + use self::authorization::TokenChecker; -use crate::{ApiDispatch, ApiError, StoreError}; #[macro_use] pub mod activity; @@ -77,9 +81,9 @@ pub type AuthorizationError = authorization::Error; /// * `tx_id` - transaction id for a submitted operation; returns `null` if `submission_result` /// is `SubmissionResult::AlreadyRecorded` pub struct Submission { - context: String, - submission_result: SubmissionResult, - tx_id: Option, + context: String, + submission_result: SubmissionResult, + tx_id: Option, } #[derive(Enum, PartialEq, Eq, Clone, Copy)] @@ -90,26 +94,26 @@ pub struct Submission { /// * `Submission` - operation has been submitted /// * `AlreadyRecorded` - operation will not result in data changes and has not been submitted pub enum SubmissionResult { - Submission, - AlreadyRecorded, + Submission, + AlreadyRecorded, } impl Submission { - pub fn from_submission(subject: &ChronicleIri, tx_id: &ChronicleTransactionId) -> Self { - Submission { - context: subject.to_string(), - submission_result: SubmissionResult::Submission, - tx_id: Some(tx_id.to_string()), - } - } + pub fn from_submission(subject: &ChronicleIri, tx_id: &ChronicleTransactionId) -> Self { + Submission { + context: subject.to_string(), + submission_result: SubmissionResult::Submission, + tx_id: Some(tx_id.to_string()), + } + } - pub fn from_already_recorded(subject: &ChronicleIri) -> Self { - Submission { - context: subject.to_string(), - submission_result: SubmissionResult::AlreadyRecorded, - tx_id: None, - } - } + pub fn from_already_recorded(subject: &ChronicleIri) -> Self { + Submission { + context: subject.to_string(), + submission_result: SubmissionResult::AlreadyRecorded, + tx_id: None, + } + } } /// # `TimelineOrder` @@ -117,95 +121,95 @@ impl Submission { /// Specify the order in which multiple results of query data are returned #[derive(Enum, Copy, Clone, Eq, PartialEq, Debug)] pub enum TimelineOrder { - NewestFirst, - OldestFirst, + NewestFirst, + OldestFirst, } #[derive(Error, Debug)] pub enum GraphQlError { - #[error("Database operation failed: {0}")] - Db( - #[from] - #[source] - diesel::result::Error, - ), - - #[error("Connection pool error: {0}")] - R2d2( - #[from] - #[source] - diesel::r2d2::Error, - ), - - #[error("Database connection failed: {0}")] - DbConnection( - #[from] - #[source] - diesel::ConnectionError, - ), - - #[error("API: {0}")] - Api( - #[from] - #[source] - crate::ApiError, - ), - - #[error("I/O: {0}")] - Io( - #[from] - #[source] - std::io::Error, - ), + #[error("Database operation failed: {0}")] + Db( + #[from] + #[source] + diesel::result::Error, + ), + + #[error("Connection pool error: {0}")] + R2d2( + #[from] + #[source] + diesel::r2d2::Error, + ), + + #[error("Database connection failed: {0}")] + DbConnection( + #[from] + #[source] + diesel::ConnectionError, + ), + + #[error("API: {0}")] + Api( + #[from] + #[source] + crate::ApiError, + ), + + #[error("I/O: {0}")] + Io( + #[from] + #[source] + std::io::Error, + ), } impl GraphQlError { - fn error_sources( - mut source: Option<&(dyn std::error::Error + 'static)>, - ) -> Option> { - /* Check if we have any sources to derive reasons from */ - if source.is_some() { - /* Add all the error sources to a list of reasons for the error */ - let mut reasons = Vec::new(); - while let Some(error) = source { - reasons.push(error.to_string()); - source = error.source(); - } - Some(reasons) - } else { - None - } - } + fn error_sources( + mut source: Option<&(dyn std::error::Error + 'static)>, + ) -> Option> { + /* Check if we have any sources to derive reasons from */ + if source.is_some() { + /* Add all the error sources to a list of reasons for the error */ + let mut reasons = Vec::new(); + while let Some(error) = source { + reasons.push(error.to_string()); + source = error.source(); + } + Some(reasons) + } else { + None + } + } } impl ErrorExtensions for GraphQlError { - // lets define our base extensions - fn extend(&self) -> Error { - Error::new(self.to_string()).extend_with(|_err, e| { - if let Some(reasons) = Self::error_sources(custom_error::Error::source(&self)) { - let mut i = 1; - for reason in reasons { - e.set(format!("reason {i}"), reason); - i += 1; - } - } - }) - } + // lets define our base extensions + fn extend(&self) -> Error { + Error::new(self.to_string()).extend_with(|_err, e| { + if let Some(reasons) = Self::error_sources(custom_error::Error::source(&self)) { + let mut i = 1; + for reason in reasons { + e.set(format!("reason {i}"), reason); + i += 1; + } + } + }) + } } pub struct Commit { - pub tx_id: String, + pub tx_id: String, } pub struct Rejection { - pub commit: Commit, - pub reason: String, + pub commit: Commit, + pub reason: String, } #[derive(Enum, PartialEq, Eq, Clone, Copy)] pub enum Stage { - Submit, - Commit, + Submit, + Commit, } #[derive(Serialize, Deserialize)] @@ -214,85 +218,85 @@ scalar!(Delta); #[derive(SimpleObject)] pub struct CommitIdentity { - identity: String, - signature: String, - verifying_key: String, + identity: String, + signature: String, + verifying_key: String, } impl From for CommitIdentity { - fn from(identity: SignedIdentity) -> Self { - CommitIdentity { - identity: identity.identity, - signature: identity.signature.map(|x| hex::encode(&*x)).unwrap_or_default(), - verifying_key: identity.verifying_key.map(hex::encode).unwrap_or_default(), - } - } + fn from(identity: SignedIdentity) -> Self { + CommitIdentity { + identity: identity.identity, + signature: identity.signature.map(|x| hex::encode(&*x)).unwrap_or_default(), + verifying_key: identity.verifying_key.map(hex::encode).unwrap_or_default(), + } + } } #[derive(SimpleObject)] pub struct CommitNotification { - pub stage: Stage, - pub tx_id: String, - pub error: Option, - pub delta: Option, - pub id: Option, + pub stage: Stage, + pub tx_id: String, + pub error: Option, + pub delta: Option, + pub id: Option, } impl CommitNotification { - pub fn from_submission(tx_id: &ChronicleTransactionId) -> Self { - CommitNotification { - stage: Stage::Submit, - tx_id: tx_id.to_string(), - error: None, - delta: None, - id: None, - } - } - - pub fn from_submission_failed(e: &SubmissionError) -> Self { - CommitNotification { - stage: Stage::Submit, - tx_id: e.tx_id().to_string(), - error: Some(e.to_string()), - delta: None, - id: None, - } - } - - pub fn from_contradiction( - tx_id: &ChronicleTransactionId, - contradiction: &str, - id: SignedIdentity, - ) -> Self { - CommitNotification { - stage: Stage::Commit, - tx_id: tx_id.to_string(), - error: Some(contradiction.to_string()), - delta: None, - id: Some(id.into()), - } - } - - pub async fn from_committed( - tx_id: &ChronicleTransactionId, - delta: Box, - id: SignedIdentity, - ) -> Result { - Ok(CommitNotification { - stage: Stage::Commit, - tx_id: tx_id.to_string(), - error: None, - delta: delta - .to_json() - .compact_stable_order() - .await - .ok() - .map(async_graphql::Value::from_json) - .transpose()? - .map(Delta), - id: Some(id.into()), - }) - } + pub fn from_submission(tx_id: &ChronicleTransactionId) -> Self { + CommitNotification { + stage: Stage::Submit, + tx_id: tx_id.to_string(), + error: None, + delta: None, + id: None, + } + } + + pub fn from_submission_failed(e: &SubmissionError) -> Self { + CommitNotification { + stage: Stage::Submit, + tx_id: e.tx_id().to_string(), + error: Some(e.to_string()), + delta: None, + id: None, + } + } + + pub fn from_contradiction( + tx_id: &ChronicleTransactionId, + contradiction: &str, + id: SignedIdentity, + ) -> Self { + CommitNotification { + stage: Stage::Commit, + tx_id: tx_id.to_string(), + error: Some(contradiction.to_string()), + delta: None, + id: Some(id.into()), + } + } + + pub async fn from_committed( + tx_id: &ChronicleTransactionId, + delta: Box, + id: SignedIdentity, + ) -> Result { + Ok(CommitNotification { + stage: Stage::Commit, + tx_id: tx_id.to_string(), + error: None, + delta: delta + .to_json() + .compact_stable_order() + .await + .ok() + .map(async_graphql::Value::from_json) + .transpose()? + .map(Delta), + id: Some(id.into()), + }) + } } pub struct Subscription; @@ -303,13 +307,13 @@ pub struct Subscription; /// /// [^note](https://graphql.org/blog/subscriptions-in-graphql-and-relay/) impl Subscription { - async fn commit_notifications<'a>( - &self, - ctx: &Context<'a>, - ) -> impl Stream { - let api = ctx.data_unchecked::().clone(); - let mut rx = api.notify_commit.subscribe(); - async_stream::stream! { + async fn commit_notifications<'a>( + &self, + ctx: &Context<'a>, + ) -> impl Stream { + let api = ctx.data_unchecked::().clone(); + let mut rx = api.notify_commit.subscribe(); + async_stream::stream! { loop { match rx.recv().await { Ok(SubmissionStage::Submitted(Ok(submission))) => @@ -334,643 +338,643 @@ impl Subscription { } } } - } + } } #[handler] async fn gql_playground() -> impl IntoResponse { - Html(playground_source(GraphQLPlaygroundConfig::new("/").subscription_endpoint("/ws"))) + Html(playground_source(GraphQLPlaygroundConfig::new("/").subscription_endpoint("/ws"))) } #[derive(Debug, Clone)] pub struct ChronicleGraphQl -where - Query: ObjectType + 'static, - Mutation: ObjectType + 'static, + where + Query: ObjectType + 'static, + Mutation: ObjectType + 'static, { - query: Query, - mutation: Mutation, + query: Query, + mutation: Mutation, } #[derive(Clone)] pub struct JwksUri { - uri: Url, + uri: Url, } impl JwksUri { - pub fn new(uri: Url) -> Self { - Self { uri } - } - - // not ToString to prevent accidental disclosure of credentials - pub fn full_uri(&self) -> String { - self.uri.to_string() - } + pub fn new(uri: Url) -> Self { + Self { uri } + } + + // not ToString to prevent accidental disclosure of credentials + pub fn full_uri(&self) -> String { + self.uri.to_string() + } } impl core::fmt::Debug for JwksUri { - fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!( - fmt, - r#"JwksUri {{ uri: Url {{ scheme: {:?}, cannot_be_a_base: {:?}, username: {:?}, password: ***SECRET***, host: {:?}, port: {:?}, path: {:?}, query: {:?}, fragment: {:?} }} }}"#, - self.uri.scheme(), - self.uri.cannot_be_a_base(), - self.uri.username(), - self.uri.host(), - self.uri.port(), - self.uri.path(), - self.uri.query(), - self.uri.fragment(), - )?; - Ok(()) - } + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!( + fmt, + r#"JwksUri {{ uri: Url {{ scheme: {:?}, cannot_be_a_base: {:?}, username: {:?}, password: ***SECRET***, host: {:?}, port: {:?}, path: {:?}, query: {:?}, fragment: {:?} }} }}"#, + self.uri.scheme(), + self.uri.cannot_be_a_base(), + self.uri.username(), + self.uri.host(), + self.uri.port(), + self.uri.path(), + self.uri.query(), + self.uri.fragment(), + )?; + Ok(()) + } } #[derive(Clone)] pub struct UserInfoUri { - uri: Url, + uri: Url, } impl UserInfoUri { - pub fn new(uri: Url) -> Self { - Self { uri } - } - - // not ToString to prevent accidental disclosure of credentials - pub fn full_uri(&self) -> String { - self.uri.to_string() - } + pub fn new(uri: Url) -> Self { + Self { uri } + } + + // not ToString to prevent accidental disclosure of credentials + pub fn full_uri(&self) -> String { + self.uri.to_string() + } } impl core::fmt::Debug for UserInfoUri { - fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - write!( - fmt, - r#"UserInfoUri {{ uri: Url {{ scheme: {:?}, cannot_be_a_base: {:?}, username: {:?}, password: ***SECRET***, host: {:?}, port: {:?}, path: {:?}, query: {:?}, fragment: {:?} }} }}"#, - self.uri.scheme(), - self.uri.cannot_be_a_base(), - self.uri.username(), - self.uri.host(), - self.uri.port(), - self.uri.path(), - self.uri.query(), - self.uri.fragment(), - )?; - Ok(()) - } + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + write!( + fmt, + r#"UserInfoUri {{ uri: Url {{ scheme: {:?}, cannot_be_a_base: {:?}, username: {:?}, password: ***SECRET***, host: {:?}, port: {:?}, path: {:?}, query: {:?}, fragment: {:?} }} }}"#, + self.uri.scheme(), + self.uri.cannot_be_a_base(), + self.uri.username(), + self.uri.host(), + self.uri.port(), + self.uri.path(), + self.uri.query(), + self.uri.fragment(), + )?; + Ok(()) + } } #[derive(Clone, Debug)] pub struct SecurityConf { - jwks_uri: Option, - userinfo_uri: Option, - id_claims: Option>, - jwt_must_claim: HashMap, - allow_anonymous: bool, - opa: ExecutorContext, + jwks_uri: Option, + userinfo_uri: Option, + id_claims: Option>, + jwt_must_claim: HashMap, + allow_anonymous: bool, + opa: ExecutorContext, } impl SecurityConf { - pub fn new( - jwks_uri: Option, - userinfo_uri: Option, - id_claims: Option>, - jwt_must_claim: HashMap, - allow_anonymous: bool, - opa: ExecutorContext, - ) -> Self { - Self { jwks_uri, userinfo_uri, id_claims, jwt_must_claim, allow_anonymous, opa } - } - - pub fn as_endpoint_conf(&self, cache_expiry_seconds: u32) -> EndpointSecurityConfiguration { - EndpointSecurityConfiguration::new( - TokenChecker::new( - self.jwks_uri.as_ref(), - self.userinfo_uri.as_ref(), - cache_expiry_seconds, - ), - self.jwt_must_claim.clone(), - self.allow_anonymous, - ) - } + pub fn new( + jwks_uri: Option, + userinfo_uri: Option, + id_claims: Option>, + jwt_must_claim: HashMap, + allow_anonymous: bool, + opa: ExecutorContext, + ) -> Self { + Self { jwks_uri, userinfo_uri, id_claims, jwt_must_claim, allow_anonymous, opa } + } + + pub fn as_endpoint_conf(&self, cache_expiry_seconds: u32) -> EndpointSecurityConfiguration { + EndpointSecurityConfiguration::new( + TokenChecker::new( + self.jwks_uri.as_ref(), + self.userinfo_uri.as_ref(), + cache_expiry_seconds, + ), + self.jwt_must_claim.clone(), + self.allow_anonymous, + ) + } } #[async_trait::async_trait] pub trait ChronicleApiServer { - async fn serve_api( - &self, - pool: Pool>, - api: ApiDispatch, - addresses: Vec, - security_conf: &SecurityConf, - serve_graphql: bool, - serve_data: bool, - ) -> Result<(), ApiError>; + async fn serve_api( + &self, + pool: Pool>, + api: ApiDispatch, + addresses: Vec, + security_conf: &SecurityConf, + serve_graphql: bool, + serve_data: bool, + ) -> Result<(), ApiError>; } impl ChronicleGraphQl -where - Query: ObjectType + Copy, - Mutation: ObjectType + Copy, + where + Query: ObjectType + Copy, + Mutation: ObjectType + Copy, { - pub fn new(query: Query, mutation: Mutation) -> Self { - Self { query, mutation } - } - - pub fn exportable_schema(&self) -> String - where - Query: ObjectType + Copy, - Mutation: ObjectType + Copy, - { - let schema = Schema::build(self.query, self.mutation, Subscription).finish(); - - schema.sdl() - } + pub fn new(query: Query, mutation: Mutation) -> Self { + Self { query, mutation } + } + + pub fn exportable_schema(&self) -> String + where + Query: ObjectType + Copy, + Mutation: ObjectType + Copy, + { + let schema = Schema::build(self.query, self.mutation, Subscription).finish(); + + schema.sdl() + } } fn check_required_claim(must_value: &str, actual_value: &serde_json::Value) -> bool { - match actual_value { - serde_json::Value::String(actual_value) => must_value == actual_value, - serde_json::Value::Array(actual_values) => actual_values - .iter() - .any(|actual_value| check_required_claim(must_value, actual_value)), - _ => false, - } + match actual_value { + serde_json::Value::String(actual_value) => must_value == actual_value, + serde_json::Value::Array(actual_values) => actual_values + .iter() + .any(|actual_value| check_required_claim(must_value, actual_value)), + _ => false, + } } #[instrument(level = "trace", ret(Debug))] fn check_required_claims( - must_claim: &HashMap, - actual_claims: &serde_json::Map, + must_claim: &HashMap, + actual_claims: &serde_json::Map, ) -> bool { - for (name, value) in must_claim { - if let Some(json) = actual_claims.get(name) { - if !check_required_claim(value, json) { - return false; - } - } else { - return false; - } - } - true + for (name, value) in must_claim { + if let Some(json) = actual_claims.get(name) { + if !check_required_claim(value, json) { + return false; + } + } else { + return false; + } + } + true } async fn check_claims( - secconf: &EndpointSecurityConfiguration, - req: &poem::Request, + secconf: &EndpointSecurityConfiguration, + req: &poem::Request, ) -> Result, poem::Error> { - if let Some(authorization) = req.header("Authorization") { - if let Ok(authorization) = HeaderValue::from_str(authorization) { - let bearer_token_maybe: Option = Credentials::decode(&authorization); - if let Some(bearer_token) = bearer_token_maybe { - if let Ok(claims) = secconf.checker.verify_token(bearer_token.token()).await { - if check_required_claims(&secconf.must_claim, &claims) { - return Ok(Some(JwtClaims(claims))); - } - } - } - } - tracing::trace!("rejected authorization from {}: {:?}", req.remote_addr(), authorization); - Err(poem::error::Error::from_string( - "Authorization header present but without a satisfactory bearer token", - StatusCode::UNAUTHORIZED, - )) - } else if secconf.allow_anonymous { - tracing::trace!("anonymous access from {}", req.remote_addr()); - Ok(None) - } else { - tracing::trace!("rejected anonymous access from {}", req.remote_addr()); - Err(poem::error::Error::from_string( - "required Authorization header not present", - StatusCode::UNAUTHORIZED, - )) - } + if let Some(authorization) = req.header("Authorization") { + if let Ok(authorization) = HeaderValue::from_str(authorization) { + let bearer_token_maybe: Option = Credentials::decode(&authorization); + if let Some(bearer_token) = bearer_token_maybe { + if let Ok(claims) = secconf.checker.verify_token(bearer_token.token()).await { + if check_required_claims(&secconf.must_claim, &claims) { + return Ok(Some(JwtClaims(claims))); + } + } + } + } + tracing::trace!("rejected authorization from {}: {:?}", req.remote_addr(), authorization); + Err(poem::error::Error::from_string( + "Authorization header present but without a satisfactory bearer token", + StatusCode::UNAUTHORIZED, + )) + } else if secconf.allow_anonymous { + tracing::trace!("anonymous access from {}", req.remote_addr()); + Ok(None) + } else { + tracing::trace!("rejected anonymous access from {}", req.remote_addr()); + Err(poem::error::Error::from_string( + "required Authorization header not present", + StatusCode::UNAUTHORIZED, + )) + } } async fn execute_opa_check( - opa_executor: &ExecutorContext, - claim_parser: &Option, - claims: Option<&JwtClaims>, - construct_data: impl FnOnce(&AuthId) -> OpaData, + opa_executor: &ExecutorContext, + claim_parser: &Option, + claims: Option<&JwtClaims>, + construct_data: impl FnOnce(&AuthId) -> OpaData, ) -> Result<(), OpaExecutorError> { - // If unable to get an external_id from the JwtClaims or no claims found, - // identity will be `Anonymous` - let identity = match (claims, claim_parser) { - (Some(claims), Some(parser)) => parser.identity(claims).unwrap_or(AuthId::anonymous()), - _ => AuthId::anonymous(), - }; - - // Create OPA context data for the user identity - let opa_data = construct_data(&identity); - - // Execute OPA check - match opa_executor.evaluate(&identity, &opa_data).await { - Err(error) => { - tracing::warn!( + // If unable to get an external_id from the JwtClaims or no claims found, + // identity will be `Anonymous` + let identity = match (claims, claim_parser) { + (Some(claims), Some(parser)) => parser.identity(claims).unwrap_or(AuthId::anonymous()), + _ => AuthId::anonymous(), + }; + + // Create OPA context data for the user identity + let opa_data = construct_data(&identity); + + // Execute OPA check + match opa_executor.evaluate(&identity, &opa_data).await { + Err(error) => { + tracing::warn!( "{error}: attempt to violate policy rules by identity: {identity}, in context: {:#?}", opa_data ); - Err(error) - }, - ok => ok, - } + Err(error) + } + ok => ok, + } } #[derive(Clone)] pub struct EndpointSecurityConfiguration { - checker: TokenChecker, - pub must_claim: HashMap, - pub allow_anonymous: bool, + checker: TokenChecker, + pub must_claim: HashMap, + pub allow_anonymous: bool, } impl EndpointSecurityConfiguration { - pub fn new( - checker: TokenChecker, - must_claim: HashMap, - allow_anonymous: bool, - ) -> Self { - Self { checker, must_claim, allow_anonymous } - } - - async fn check_status(&self) -> Result<(), AuthorizationError> { - self.checker.check_status().await - } + pub fn new( + checker: TokenChecker, + must_claim: HashMap, + allow_anonymous: bool, + ) -> Self { + Self { checker, must_claim, allow_anonymous } + } + + async fn check_status(&self) -> Result<(), AuthorizationError> { + self.checker.check_status().await + } } struct QueryEndpoint { - secconf: EndpointSecurityConfiguration, - schema: Schema, + secconf: EndpointSecurityConfiguration, + schema: Schema, } impl QueryEndpoint -where - Q: ObjectType + 'static, - M: ObjectType + 'static, - S: SubscriptionType + 'static, + where + Q: ObjectType + 'static, + M: ObjectType + 'static, + S: SubscriptionType + 'static, { - #[instrument(level = "debug", skip_all, ret(Debug))] - async fn respond( - &self, - req: poem::Request, - prepare_req: impl FnOnce(GraphQLBatchRequest) -> async_graphql::BatchRequest, - ) -> poem::Result { - use poem::{FromRequest, IntoResponse}; - let (req, mut body) = req.split(); - let req = prepare_req(GraphQLBatchRequest::from_request(&req, &mut body).await?); - Ok(GraphQLBatchResponse(self.schema.execute_batch(req).await).into_response()) - } + #[instrument(level = "debug", skip_all, ret(Debug))] + async fn respond( + &self, + req: poem::Request, + prepare_req: impl FnOnce(GraphQLBatchRequest) -> async_graphql::BatchRequest, + ) -> poem::Result { + use poem::{FromRequest, IntoResponse}; + let (req, mut body) = req.split(); + let req = prepare_req(GraphQLBatchRequest::from_request(&req, &mut body).await?); + Ok(GraphQLBatchResponse(self.schema.execute_batch(req).await).into_response()) + } } impl Endpoint for QueryEndpoint -where - Q: ObjectType + 'static, - M: ObjectType + 'static, - S: SubscriptionType + 'static, + where + Q: ObjectType + 'static, + M: ObjectType + 'static, + S: SubscriptionType + 'static, { - type Output = poem::Response; - - async fn call(&self, req: poem::Request) -> poem::Result { - let checked_claims = check_claims(&self.secconf, &req).await?; - self.respond(req, |api_req| { - if let Some(claims) = checked_claims { - api_req.0.data(claims) - } else { - api_req.0 - } - }) - .await - } + type Output = poem::Response; + + async fn call(&self, req: poem::Request) -> poem::Result { + let checked_claims = check_claims(&self.secconf, &req).await?; + self.respond(req, |api_req| { + if let Some(claims) = checked_claims { + api_req.0.data(claims) + } else { + api_req.0 + } + }) + .await + } } struct SubscriptionEndpoint { - secconf: EndpointSecurityConfiguration, - schema: Schema, + secconf: EndpointSecurityConfiguration, + schema: Schema, } impl SubscriptionEndpoint -where - Q: ObjectType + 'static, - M: ObjectType + 'static, - S: SubscriptionType + 'static, + where + Q: ObjectType + 'static, + M: ObjectType + 'static, + S: SubscriptionType + 'static, { - #[instrument(level = "trace", skip(self, req), ret(Debug))] - async fn respond( - &self, - req: poem::Request, - data: async_graphql::Data, - ) -> poem::Result { - use poem::{FromRequest, IntoResponse}; - let (req, mut body) = req.split(); - let websocket = poem::web::websocket::WebSocket::from_request(&req, &mut body).await?; - let protocol = GraphQLProtocol::from_request(&req, &mut body).await?; - let schema = self.schema.clone(); - Ok(websocket - .protocols(ALL_WEBSOCKET_PROTOCOLS) - .on_upgrade(move |stream| { - GraphQLWebSocket::new(stream, schema, protocol).with_data(data).serve() - }) - .into_response()) - } + #[instrument(level = "trace", skip(self, req), ret(Debug))] + async fn respond( + &self, + req: poem::Request, + data: async_graphql::Data, + ) -> poem::Result { + use poem::{FromRequest, IntoResponse}; + let (req, mut body) = req.split(); + let websocket = poem::web::websocket::WebSocket::from_request(&req, &mut body).await?; + let protocol = GraphQLProtocol::from_request(&req, &mut body).await?; + let schema = self.schema.clone(); + Ok(websocket + .protocols(ALL_WEBSOCKET_PROTOCOLS) + .on_upgrade(move |stream| { + GraphQLWebSocket::new(stream, schema, protocol).with_data(data).serve() + }) + .into_response()) + } } impl Endpoint for SubscriptionEndpoint -where - Q: ObjectType + 'static, - M: ObjectType + 'static, - S: SubscriptionType + 'static, + where + Q: ObjectType + 'static, + M: ObjectType + 'static, + S: SubscriptionType + 'static, { - type Output = poem::Response; - - async fn call(&self, req: poem::Request) -> poem::Result { - let checked_claims = check_claims(&self.secconf, &req).await?; - self.respond( - req, - if let Some(claims) = checked_claims { - let mut data = async_graphql::Data::default(); - data.insert(claims); - data - } else { - async_graphql::Data::default() - }, - ) - .await - } + type Output = poem::Response; + + async fn call(&self, req: poem::Request) -> poem::Result { + let checked_claims = check_claims(&self.secconf, &req).await?; + self.respond( + req, + if let Some(claims) = checked_claims { + let mut data = async_graphql::Data::default(); + data.insert(claims); + data + } else { + async_graphql::Data::default() + }, + ) + .await + } } struct IriEndpoint { - secconf: Option, - store: chronicle_persistence::Store, - opa_executor: ExecutorContext, - claim_parser: Option, + secconf: Option, + store: chronicle_persistence::Store, + opa_executor: ExecutorContext, + claim_parser: Option, } impl IriEndpoint { - async fn response_for_query( - &self, - claims: Option<&JwtClaims>, - prov_type: &str, - id: &ID, - ns: &ExternalId, - retrieve: impl FnOnce( - PooledConnection>, - &ID, - &ExternalId, - ) -> Result, - ) -> poem::Result { - match execute_opa_check(&self.opa_executor, &self.claim_parser, claims, |identity| { - OpaData::operation( - identity, - &json!("ReadData"), - &json!({ + async fn response_for_query( + &self, + claims: Option<&JwtClaims>, + prov_type: &str, + id: &ID, + ns: &ExternalId, + retrieve: impl FnOnce( + PooledConnection>, + &ID, + &ExternalId, + ) -> Result, + ) -> poem::Result { + match execute_opa_check(&self.opa_executor, &self.claim_parser, claims, |identity| { + OpaData::operation( + identity, + &json!("ReadData"), + &json!({ "type": prov_type, "id": id.external_id_part(), "namespace": ns }), - ) - }) - .await - { - Ok(()) => match self.store.connection() { - Ok(connection) => match retrieve(connection, id, ns) { - Ok(data) => match data.to_json().compact().await { - Ok(mut json) => { - use serde_json::Value; - if let Value::Object(mut map) = json { - map.insert( - "@context".to_string(), - Value::String("/context".to_string()), - ); - json = Value::Object(map); - } - Ok(IntoResponse::into_response(poem::web::Json(json))) - }, - Err(error) => { - tracing::error!("JSON failed compaction: {error}"); - Ok(poem::Response::builder() - .status(StatusCode::INTERNAL_SERVER_ERROR) - .body("failed to compact JSON response")) - }, - }, - Err(StoreError::Db(diesel::result::Error::NotFound)) | - Err(StoreError::RecordNotFound) => { - tracing::debug!("not found: {prov_type} {} in {ns}", id.external_id_part()); - Ok(poem::Response::builder() - .status(StatusCode::NOT_FOUND) - .body(format!("the specified {prov_type} does not exist"))) - }, - Err(error) => { - tracing::error!("failed to retrieve from database: {error}"); - Ok(poem::Response::builder() - .status(StatusCode::INTERNAL_SERVER_ERROR) - .body("failed to fetch from backend storage")) - }, - }, - Err(error) => { - tracing::error!("failed to connect to database: {error}"); - Ok(poem::Response::builder() - .status(StatusCode::INTERNAL_SERVER_ERROR) - .body("failed to access backend storage")) - }, - }, - Err(_) => Ok(poem::Response::builder() - .status(StatusCode::FORBIDDEN) - .body("violation of policy rules")), - } - } - - async fn parse_ns_iri_from_uri_path( - &self, - req: poem::Request, - ) -> poem::Result> { - use poem::{web::Path, FromRequest, Response}; - - #[derive(Clone, Debug, Serialize, Deserialize)] - struct NamespacedIri { - ns: String, - iri: String, - } - - #[derive(Clone, Debug, Serialize, Deserialize)] - struct Iri { - iri: String, - } - - impl From for NamespacedIri { - fn from(value: Iri) -> Self { - NamespacedIri { ns: "default".to_string(), iri: value.iri } - } - } - - let (req, mut body) = req.split(); - - let ns_iri: poem::Result> = - poem::web::Path::from_request(&req, &mut body).await; + ) + }) + .await + { + Ok(()) => match self.store.connection() { + Ok(connection) => match retrieve(connection, id, ns) { + Ok(data) => match data.to_json().compact().await { + Ok(mut json) => { + use serde_json::Value; + if let Value::Object(mut map) = json { + map.insert( + "@context".to_string(), + Value::String("/context".to_string()), + ); + json = Value::Object(map); + } + Ok(IntoResponse::into_response(poem::web::Json(json))) + } + Err(error) => { + tracing::error!("JSON failed compaction: {error}"); + Ok(poem::Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body("failed to compact JSON response")) + } + }, + Err(StoreError::Db(diesel::result::Error::NotFound)) | + Err(StoreError::RecordNotFound) => { + tracing::debug!("not found: {prov_type} {} in {ns}", id.external_id_part()); + Ok(poem::Response::builder() + .status(StatusCode::NOT_FOUND) + .body(format!("the specified {prov_type} does not exist"))) + } + Err(error) => { + tracing::error!("failed to retrieve from database: {error}"); + Ok(poem::Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body("failed to fetch from backend storage")) + } + }, + Err(error) => { + tracing::error!("failed to connect to database: {error}"); + Ok(poem::Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body("failed to access backend storage")) + } + }, + Err(_) => Ok(poem::Response::builder() + .status(StatusCode::FORBIDDEN) + .body("violation of policy rules")), + } + } - let ns_iri: NamespacedIri = match ns_iri { - Ok(Path(nsi)) => nsi, - Err(_) => { - let path: Path = poem::web::Path::from_request(&req, &mut body).await?; - path.0.into() - }, - }; + async fn parse_ns_iri_from_uri_path( + &self, + req: poem::Request, + ) -> poem::Result> { + use poem::{FromRequest, Response, web::Path}; + + #[derive(Clone, Debug, Serialize, Deserialize)] + struct NamespacedIri { + ns: String, + iri: String, + } + + #[derive(Clone, Debug, Serialize, Deserialize)] + struct Iri { + iri: String, + } + + impl From for NamespacedIri { + fn from(value: Iri) -> Self { + NamespacedIri { ns: "default".to_string(), iri: value.iri } + } + } + + let (req, mut body) = req.split(); + + let ns_iri: poem::Result> = + poem::web::Path::from_request(&req, &mut body).await; + + let ns_iri: NamespacedIri = match ns_iri { + Ok(Path(nsi)) => nsi, + Err(_) => { + let path: Path = poem::web::Path::from_request(&req, &mut body).await?; + path.0.into() + } + }; + + match ChronicleIri::from_str(&ns_iri.iri) { + Ok(iri) => Ok(Ok((ns_iri.ns.into(), iri))), + Err(error) => + Ok(Err(Response::builder().status(StatusCode::NOT_FOUND).body(error.to_string()))), + } + } - match ChronicleIri::from_str(&ns_iri.iri) { - Ok(iri) => Ok(Ok((ns_iri.ns.into(), iri))), - Err(error) => - Ok(Err(Response::builder().status(StatusCode::NOT_FOUND).body(error.to_string()))), - } - } - - #[instrument(level = "trace", skip(self, req), ret(Debug))] - async fn respond( - &self, - req: poem::Request, - claims: Option<&JwtClaims>, - ) -> poem::Result { - match self.parse_ns_iri_from_uri_path(req).await? { - Ok((ns, ChronicleIri::Activity(id))) => - self.response_for_query(claims, "activity", &id, &ns, |mut conn, id, ns| { - self.store.prov_model_for_activity_id(&mut conn, id, ns) - }) - .await, - Ok((ns, ChronicleIri::Agent(id))) => - self.response_for_query(claims, "agent", &id, &ns, |mut conn, id, ns| { - self.store.prov_model_for_agent_id(&mut conn, id, ns) - }) - .await, - Ok((ns, ChronicleIri::Entity(id))) => - self.response_for_query(claims, "entity", &id, &ns, |mut conn, id, ns| { - self.store.prov_model_for_entity_id(&mut conn, id, ns) - }) - .await, - Ok(_) => Ok(poem::Response::builder() - .status(StatusCode::NOT_FOUND) - .body("may query only: activity, agent, entity")), - Err(rsp) => Ok(rsp), - } - } + #[instrument(level = "trace", skip(self, req), ret(Debug))] + async fn respond( + &self, + req: poem::Request, + claims: Option<&JwtClaims>, + ) -> poem::Result { + match self.parse_ns_iri_from_uri_path(req).await? { + Ok((ns, ChronicleIri::Activity(id))) => + self.response_for_query(claims, "activity", &id, &ns, |mut conn, id, ns| { + self.store.prov_model_for_activity_id(&mut conn, id, ns) + }) + .await, + Ok((ns, ChronicleIri::Agent(id))) => + self.response_for_query(claims, "agent", &id, &ns, |mut conn, id, ns| { + self.store.prov_model_for_agent_id(&mut conn, id, ns) + }) + .await, + Ok((ns, ChronicleIri::Entity(id))) => + self.response_for_query(claims, "entity", &id, &ns, |mut conn, id, ns| { + self.store.prov_model_for_entity_id(&mut conn, id, ns) + }) + .await, + Ok(_) => Ok(poem::Response::builder() + .status(StatusCode::NOT_FOUND) + .body("may query only: activity, agent, entity")), + Err(rsp) => Ok(rsp), + } + } } impl Endpoint for IriEndpoint { - type Output = poem::Response; - - async fn call(&self, req: poem::Request) -> poem::Result { - let checked_claims = if let Some(secconf) = &self.secconf { - check_claims(secconf, &req).await? - } else { - None - }; - self.respond(req, checked_claims.as_ref()).await - } + type Output = poem::Response; + + async fn call(&self, req: poem::Request) -> poem::Result { + let checked_claims = if let Some(secconf) = &self.secconf { + check_claims(secconf, &req).await? + } else { + None + }; + self.respond(req, checked_claims.as_ref()).await + } } struct LdContextEndpoint; impl Endpoint for LdContextEndpoint { - type Output = poem::Response; + type Output = poem::Response; - async fn call(&self, _req: poem::Request) -> poem::Result { - let context: &serde_json::Value = &common::context::PROV; - Ok(IntoResponse::into_response(poem::web::Json(context))) - } + async fn call(&self, _req: poem::Request) -> poem::Result { + let context: &serde_json::Value = &common::context::PROV; + Ok(IntoResponse::into_response(poem::web::Json(context))) + } } #[derive(Clone, Debug)] pub struct AuthFromJwt { - id_claims: BTreeSet, - allow_anonymous: bool, + id_claims: BTreeSet, + allow_anonymous: bool, } impl AuthFromJwt { - #[instrument(level = "debug", ret(Debug))] - fn identity(&self, claims: &JwtClaims) -> Result { - AuthId::from_jwt_claims(claims, &self.id_claims) - } + #[instrument(level = "debug", ret(Debug))] + fn identity(&self, claims: &JwtClaims) -> Result { + AuthId::from_jwt_claims(claims, &self.id_claims) + } } #[async_trait::async_trait] impl async_graphql::extensions::Extension for AuthFromJwt { - async fn prepare_request( - &self, - ctx: &async_graphql::extensions::ExtensionContext<'_>, - mut request: async_graphql::Request, - next: async_graphql::extensions::NextPrepareRequest<'_>, - ) -> async_graphql::ServerResult { - if let Some(claims) = ctx.data_opt::() { - match self.identity(claims) { - Ok(chronicle_id) => request = request.data(chronicle_id), - Err(error) if self.allow_anonymous => { - debug!("Identity could not be determined: {:?}", error) - }, - Err(error) => { - warn!( + async fn prepare_request( + &self, + ctx: &async_graphql::extensions::ExtensionContext<'_>, + mut request: async_graphql::Request, + next: async_graphql::extensions::NextPrepareRequest<'_>, + ) -> async_graphql::ServerResult { + if let Some(claims) = ctx.data_opt::() { + match self.identity(claims) { + Ok(chronicle_id) => request = request.data(chronicle_id), + Err(error) if self.allow_anonymous => { + debug!("Identity could not be determined: {:?}", error) + } + Err(error) => { + warn!( "Rejecting request because required identity could not be determined: {:?}", error ); - return Err(ServerError::new("Authorization header present but identity could not be determined from bearer token", None)); - }, - } - } - next.run(ctx, request).await - } + return Err(ServerError::new("Authorization header present but identity could not be determined from bearer token", None)); + } + } + } + next.run(ctx, request).await + } } impl async_graphql::extensions::ExtensionFactory for AuthFromJwt { - fn create(&self) -> Arc { - Arc::new(AuthFromJwt { - id_claims: self.id_claims.clone(), - allow_anonymous: self.allow_anonymous, - }) - } + fn create(&self) -> Arc { + Arc::new(AuthFromJwt { + id_claims: self.id_claims.clone(), + allow_anonymous: self.allow_anonymous, + }) + } } #[derive(Clone, Debug)] pub struct OpaCheck { - pub claim_parser: Option, + pub claim_parser: Option, } #[async_trait::async_trait] impl async_graphql::extensions::Extension for OpaCheck { - #[instrument(level = "trace", skip_all, ret(Debug))] - async fn resolve( - &self, - ctx: &async_graphql::extensions::ExtensionContext<'_>, - info: async_graphql::extensions::ResolveInfo<'_>, - next: async_graphql::extensions::NextResolve<'_>, - ) -> async_graphql::ServerResult> { - use async_graphql::ServerError; - use serde_json::Value; - if let Some(opa_executor) = ctx.data_opt::() { - match execute_opa_check( - opa_executor, - &self.claim_parser, - ctx.data_opt::(), - |identity| { - OpaData::graphql( - identity, - &Value::String(info.parent_type.to_string()), - &Value::Array( - info.path_node.to_string_vec().into_iter().map(Value::String).collect(), - ), - ) - }, - ) - .await - { - Ok(()) => next.run(ctx, info).await, - Err(_) => Err(ServerError::new("violation of policy rules", None)), - } - } else { - Err(ServerError::new("cannot check policy rules", None)) - } - } + #[instrument(level = "trace", skip_all, ret(Debug))] + async fn resolve( + &self, + ctx: &async_graphql::extensions::ExtensionContext<'_>, + info: async_graphql::extensions::ResolveInfo<'_>, + next: async_graphql::extensions::NextResolve<'_>, + ) -> async_graphql::ServerResult> { + use async_graphql::ServerError; + use serde_json::Value; + if let Some(opa_executor) = ctx.data_opt::() { + match execute_opa_check( + opa_executor, + &self.claim_parser, + ctx.data_opt::(), + |identity| { + OpaData::graphql( + identity, + &Value::String(info.parent_type.to_string()), + &Value::Array( + info.path_node.to_string_vec().into_iter().map(Value::String).collect(), + ), + ) + }, + ) + .await + { + Ok(()) => next.run(ctx, info).await, + Err(_) => Err(ServerError::new("violation of policy rules", None)), + } + } else { + Err(ServerError::new("cannot check policy rules", None)) + } + } } #[async_trait::async_trait] impl async_graphql::extensions::ExtensionFactory for OpaCheck { - fn create(&self) -> Arc { - Arc::new(OpaCheck { claim_parser: self.claim_parser.clone() }) - } + fn create(&self) -> Arc { + Arc::new(OpaCheck { claim_parser: self.claim_parser.clone() }) + } } lazy_static! { @@ -978,11 +982,11 @@ lazy_static! { } pub fn trigger_shutdown() { - SHUTDOWN_SIGNAL.add_permits(1); + SHUTDOWN_SIGNAL.add_permits(1); } async fn await_shutdown() { - let _permit = SHUTDOWN_SIGNAL.acquire().await.unwrap(); + let _permit = SHUTDOWN_SIGNAL.acquire().await.unwrap(); } @@ -1002,137 +1006,137 @@ impl DatabaseContext { } pub fn construct_schema( - query: Query, - mutation: Mutation, - subscription: Subscription, - claim_parser: Option, - pool: &Pool>, - api: &ApiDispatch, - opa: ExecutorContext, + query: Query, + mutation: Mutation, + subscription: Subscription, + claim_parser: Option, + pool: &Pool>, + api: &ApiDispatch, + opa: ExecutorContext, ) -> Result, StoreError> -where - Query: ObjectType + Copy + 'static, - Mutation: ObjectType + Copy + 'static, - Subscription: SubscriptionType + 'static, + where + Query: ObjectType + Copy + 'static, + Mutation: ObjectType + Copy + 'static, + Subscription: SubscriptionType + 'static, { - let mut schema = Schema::build(query, mutation, subscription) - .extension(OpaCheck { claim_parser: claim_parser.clone() }); - - if let Some(claim_parser) = &claim_parser { - schema = schema.extension(claim_parser.clone()); - } - - Ok(schema - .data(api.clone()) - .data(opa.clone()) - .data(AuthId::anonymous()) - .data(DatabaseContext::new(pool)?) - .finish()) + let mut schema = Schema::build(query, mutation, subscription) + .extension(OpaCheck { claim_parser: claim_parser.clone() }); + + if let Some(claim_parser) = &claim_parser { + schema = schema.extension(claim_parser.clone()); + } + + Ok(schema + .data(api.clone()) + .data(opa.clone()) + .data(AuthId::anonymous()) + .data(DatabaseContext::new(pool)?) + .finish()) } #[async_trait::async_trait] impl ChronicleApiServer for ChronicleGraphQl -where - Query: ObjectType + Copy, - Mutation: ObjectType + Copy, + where + Query: ObjectType + Copy, + Mutation: ObjectType + Copy, { - async fn serve_api( - &self, - pool: Pool>, - api: ApiDispatch, - addresses: Vec, - sec: &SecurityConf, - serve_graphql: bool, - serve_data: bool, - ) -> Result<(), ApiError> { - tracing::info!("Serve graphql on {:?}", addresses); - let sec = sec.clone(); - let claim_parser = sec - .id_claims - .map(|id_claims| AuthFromJwt { id_claims, allow_anonymous: sec.allow_anonymous }); - - let schema = construct_schema( - self.query, - self.mutation, - Subscription, - claim_parser.clone(), - &pool, - &api, - sec.opa.clone(), - )?; - - let iri_endpoint = |secconf| IriEndpoint { - secconf, - store: chronicle_persistence::Store::new(pool.clone()).unwrap(), - opa_executor: sec.opa.clone(), - claim_parser: claim_parser.clone(), - }; - - let mut app = Route::new(); - - match (&sec.jwks_uri, &sec.userinfo_uri) { - (None, None) => { - tracing::warn!("API endpoint uses no authentication"); - - if serve_graphql { - app = app - .at("/", get(gql_playground).post(GraphQL::new(schema.clone()))) - .at("/ws", get(GraphQLSubscription::new(schema))) - }; - if serve_data { - app = app - .at("/context", get(LdContextEndpoint)) - .at("/data/:iri", get(iri_endpoint(None))) - .at("/data/:ns/:iri", get(iri_endpoint(None))) - }; - }, - (jwks_uri, userinfo_uri) => { - const CACHE_EXPIRY_SECONDS: u32 = 100; - if let Some(uri) = jwks_uri { - tracing::debug!(oidc_jwks_endpoint = ?uri); - } - if let Some(uri) = userinfo_uri { - tracing::debug!(oidc_userinfo_endpoint = ?uri); - } - - let secconf = || { - EndpointSecurityConfiguration::new( - TokenChecker::new( - jwks_uri.as_ref(), - userinfo_uri.as_ref(), - CACHE_EXPIRY_SECONDS, - ), - sec.jwt_must_claim.clone(), - sec.allow_anonymous, - ) - }; - - secconf().check_status().await?; - - if serve_graphql { - app = app - .at("/", post(QueryEndpoint { secconf: secconf(), schema: schema.clone() })) - .at("/ws", get(SubscriptionEndpoint { secconf: secconf(), schema })) - }; - if serve_data { - app = app - .at("/context", get(LdContextEndpoint)) - .at("/data/:iri", get(iri_endpoint(Some(secconf())))) - .at("/data/:ns/:iri", get(iri_endpoint(Some(secconf())))) - }; - }, - } - - let listener = addresses - .into_iter() - .map(|address| TcpListener::bind(address).boxed()) - .reduce(|listener_1, listener_2| listener_1.combine(listener_2).boxed()) - .unwrap(); - - Server::new(listener) - .run_with_graceful_shutdown(app, await_shutdown(), None) - .await?; - - Ok(()) - } + async fn serve_api( + &self, + pool: Pool>, + api: ApiDispatch, + addresses: Vec, + sec: &SecurityConf, + serve_graphql: bool, + serve_data: bool, + ) -> Result<(), ApiError> { + tracing::info!("Serve graphql on {:?}", addresses); + let sec = sec.clone(); + let claim_parser = sec + .id_claims + .map(|id_claims| AuthFromJwt { id_claims, allow_anonymous: sec.allow_anonymous }); + + let schema = construct_schema( + self.query, + self.mutation, + Subscription, + claim_parser.clone(), + &pool, + &api, + sec.opa.clone(), + )?; + + let iri_endpoint = |secconf| IriEndpoint { + secconf, + store: chronicle_persistence::Store::new(pool.clone()).unwrap(), + opa_executor: sec.opa.clone(), + claim_parser: claim_parser.clone(), + }; + + let mut app = Route::new(); + + match (&sec.jwks_uri, &sec.userinfo_uri) { + (None, None) => { + tracing::warn!("API endpoint uses no authentication"); + + if serve_graphql { + app = app + .at("/", get(gql_playground).post(GraphQL::new(schema.clone()))) + .at("/ws", get(GraphQLSubscription::new(schema))) + }; + if serve_data { + app = app + .at("/context", get(LdContextEndpoint)) + .at("/data/:iri", get(iri_endpoint(None))) + .at("/data/:ns/:iri", get(iri_endpoint(None))) + }; + } + (jwks_uri, userinfo_uri) => { + const CACHE_EXPIRY_SECONDS: u32 = 100; + if let Some(uri) = jwks_uri { + tracing::debug!(oidc_jwks_endpoint = ?uri); + } + if let Some(uri) = userinfo_uri { + tracing::debug!(oidc_userinfo_endpoint = ?uri); + } + + let secconf = || { + EndpointSecurityConfiguration::new( + TokenChecker::new( + jwks_uri.as_ref(), + userinfo_uri.as_ref(), + CACHE_EXPIRY_SECONDS, + ), + sec.jwt_must_claim.clone(), + sec.allow_anonymous, + ) + }; + + secconf().check_status().await?; + + if serve_graphql { + app = app + .at("/", post(QueryEndpoint { secconf: secconf(), schema: schema.clone() })) + .at("/ws", get(SubscriptionEndpoint { secconf: secconf(), schema })) + }; + if serve_data { + app = app + .at("/context", get(LdContextEndpoint)) + .at("/data/:iri", get(iri_endpoint(Some(secconf())))) + .at("/data/:ns/:iri", get(iri_endpoint(Some(secconf())))) + }; + } + } + + let listener = addresses + .into_iter() + .map(|address| TcpListener::bind(address).boxed()) + .reduce(|listener_1, listener_2| listener_1.combine(listener_2).boxed()) + .unwrap(); + + Server::new(listener) + .run_with_graceful_shutdown(app, await_shutdown(), None) + .await?; + + Ok(()) + } } diff --git a/crates/api/src/chronicle_graphql/mutation.rs b/crates/api/src/chronicle_graphql/mutation.rs index bf63e42e8..ab55d1f17 100644 --- a/crates/api/src/chronicle_graphql/mutation.rs +++ b/crates/api/src/chronicle_graphql/mutation.rs @@ -1,386 +1,390 @@ //! Primitive mutation operations that are not in terms of particular domain types -use crate::commands::{ActivityCommand, AgentCommand, ApiCommand, ApiResponse, EntityCommand}; use async_graphql::Context; use chrono::{DateTime, Utc}; + use common::{ attributes::Attributes, identity::AuthId, - prov::{operations::DerivationType, ActivityId, AgentId, EntityId, Role}, + prov::{ActivityId, AgentId, EntityId, operations::DerivationType, Role}, }; -use crate::ApiDispatch; +use crate::commands::{ActivityCommand, AgentCommand, ApiCommand, ApiResponse, EntityCommand}; +use crate::dispatch::ApiDispatch; use super::Submission; + async fn transaction_context<'a>( - res: ApiResponse, - _ctx: &Context<'a>, + res: ApiResponse, + _ctx: &Context<'a>, ) -> async_graphql::Result { - match res { - ApiResponse::Submission { subject, tx_id, .. } => - Ok(Submission::from_submission(&subject, &tx_id)), - ApiResponse::AlreadyRecorded { subject, .. } => - Ok(Submission::from_already_recorded(&subject)), - _ => unreachable!(), - } + match res { + ApiResponse::Submission { subject, tx_id, .. } => + Ok(Submission::from_submission(&subject, &tx_id)), + ApiResponse::AlreadyRecorded { subject, .. } => + Ok(Submission::from_already_recorded(&subject)), + _ => unreachable!(), + } } async fn derivation<'a>( - ctx: &Context<'a>, - namespace: Option, - generated_entity: EntityId, - used_entity: EntityId, - derivation: DerivationType, + ctx: &Context<'a>, + namespace: Option, + generated_entity: EntityId, + used_entity: EntityId, + derivation: DerivationType, ) -> async_graphql::Result { - let api = ctx.data::()?; - - let identity = ctx.data::()?.to_owned(); - - let namespace = namespace.unwrap_or_else(|| "default".into()).into(); - - let res = api - .dispatch( - ApiCommand::Entity(EntityCommand::Derive { - id: generated_entity, - namespace, - activity: None, - used_entity, - derivation, - }), - identity, - ) - .await?; - - transaction_context(res, ctx).await + let api = ctx.data::()?; + + let identity = ctx.data::()?.to_owned(); + + let namespace = namespace.unwrap_or_else(|| "default".into()).into(); + + let res = api + .dispatch( + ApiCommand::Entity(EntityCommand::Derive { + id: generated_entity, + namespace, + activity: None, + used_entity, + derivation, + }), + identity, + ) + .await?; + + transaction_context(res, ctx).await } pub async fn agent<'a>( - ctx: &Context<'a>, - external_id: String, - namespace: Option, - attributes: Attributes, + ctx: &Context<'a>, + external_id: String, + namespace: Option, + attributes: Attributes, ) -> async_graphql::Result { - let api = ctx.data::()?; + let api = ctx.data::()?; - let identity = ctx.data::()?.to_owned(); + let identity = ctx.data::()?.to_owned(); - let namespace = namespace.unwrap_or_else(|| "default".to_owned()); + let namespace = namespace.unwrap_or_else(|| "default".to_owned()); - let res = api - .dispatch( - ApiCommand::Agent(AgentCommand::Create { - id: external_id.into(), - namespace: namespace.into(), - attributes, - }), - identity, - ) - .await?; + let res = api + .dispatch( + ApiCommand::Agent(AgentCommand::Create { + id: external_id.into(), + namespace: namespace.into(), + attributes, + }), + identity, + ) + .await?; - transaction_context(res, ctx).await + transaction_context(res, ctx).await } pub async fn activity<'a>( - ctx: &Context<'a>, - external_id: String, - namespace: Option, - attributes: Attributes, + ctx: &Context<'a>, + external_id: String, + namespace: Option, + attributes: Attributes, ) -> async_graphql::Result { - let api = ctx.data::()?; + let api = ctx.data::()?; - let identity = ctx.data::()?.to_owned(); + let identity = ctx.data::()?.to_owned(); - let namespace = namespace.unwrap_or_else(|| "default".to_owned()); + let namespace = namespace.unwrap_or_else(|| "default".to_owned()); - let res = api - .dispatch( - ApiCommand::Activity(ActivityCommand::Create { - id: external_id.into(), - namespace: namespace.into(), - attributes, - }), - identity, - ) - .await?; + let res = api + .dispatch( + ApiCommand::Activity(ActivityCommand::Create { + id: external_id.into(), + namespace: namespace.into(), + attributes, + }), + identity, + ) + .await?; - transaction_context(res, ctx).await + transaction_context(res, ctx).await } pub async fn entity<'a>( - ctx: &Context<'a>, - external_id: String, - namespace: Option, - attributes: Attributes, + ctx: &Context<'a>, + external_id: String, + namespace: Option, + attributes: Attributes, ) -> async_graphql::Result { - let api = ctx.data::()?; + let api = ctx.data::()?; - let identity = ctx.data::()?.to_owned(); + let identity = ctx.data::()?.to_owned(); - let namespace = namespace.unwrap_or_else(|| "default".to_owned()); + let namespace = namespace.unwrap_or_else(|| "default".to_owned()); - let res = api - .dispatch( - ApiCommand::Entity(EntityCommand::Create { - id: external_id.into(), - namespace: namespace.into(), - attributes, - }), - identity, - ) - .await?; + let res = api + .dispatch( + ApiCommand::Entity(EntityCommand::Create { + id: external_id.into(), + namespace: namespace.into(), + attributes, + }), + identity, + ) + .await?; - transaction_context(res, ctx).await + transaction_context(res, ctx).await } pub async fn acted_on_behalf_of<'a>( - ctx: &Context<'a>, - namespace: Option, - responsible_id: AgentId, - delegate_id: AgentId, - activity_id: Option, - role: Option, + ctx: &Context<'a>, + namespace: Option, + responsible_id: AgentId, + delegate_id: AgentId, + activity_id: Option, + role: Option, ) -> async_graphql::Result { - let api = ctx.data::()?; - - let identity = ctx.data::()?.to_owned(); - - let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); - - let res = api - .dispatch( - ApiCommand::Agent(AgentCommand::Delegate { - id: responsible_id, - delegate: delegate_id, - activity: activity_id, - namespace, - role, - }), - identity, - ) - .await?; - - transaction_context(res, ctx).await + let api = ctx.data::()?; + + let identity = ctx.data::()?.to_owned(); + + let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); + + let res = api + .dispatch( + ApiCommand::Agent(AgentCommand::Delegate { + id: responsible_id, + delegate: delegate_id, + activity: activity_id, + namespace, + role, + }), + identity, + ) + .await?; + + transaction_context(res, ctx).await } pub async fn was_derived_from<'a>( - ctx: &Context<'a>, - namespace: Option, - generated_entity: EntityId, - used_entity: EntityId, + ctx: &Context<'a>, + namespace: Option, + generated_entity: EntityId, + used_entity: EntityId, ) -> async_graphql::Result { - derivation(ctx, namespace, generated_entity, used_entity, DerivationType::None).await + derivation(ctx, namespace, generated_entity, used_entity, DerivationType::None).await } pub async fn was_revision_of<'a>( - ctx: &Context<'a>, - namespace: Option, - generated_entity: EntityId, - used_entity: EntityId, + ctx: &Context<'a>, + namespace: Option, + generated_entity: EntityId, + used_entity: EntityId, ) -> async_graphql::Result { - derivation(ctx, namespace, generated_entity, used_entity, DerivationType::Revision).await + derivation(ctx, namespace, generated_entity, used_entity, DerivationType::Revision).await } + pub async fn had_primary_source<'a>( - ctx: &Context<'a>, - namespace: Option, - generated_entity: EntityId, - used_entity: EntityId, + ctx: &Context<'a>, + namespace: Option, + generated_entity: EntityId, + used_entity: EntityId, ) -> async_graphql::Result { - derivation(ctx, namespace, generated_entity, used_entity, DerivationType::PrimarySource).await + derivation(ctx, namespace, generated_entity, used_entity, DerivationType::PrimarySource).await } + pub async fn was_quoted_from<'a>( - ctx: &Context<'a>, - namespace: Option, - generated_entity: EntityId, - used_entity: EntityId, + ctx: &Context<'a>, + namespace: Option, + generated_entity: EntityId, + used_entity: EntityId, ) -> async_graphql::Result { - derivation(ctx, namespace, generated_entity, used_entity, DerivationType::Quotation).await + derivation(ctx, namespace, generated_entity, used_entity, DerivationType::Quotation).await } pub async fn start_activity<'a>( - ctx: &Context<'a>, - id: ActivityId, - namespace: Option, - agent: Option, // deprecated, slated for removal in CHRON-185 - time: Option>, + ctx: &Context<'a>, + id: ActivityId, + namespace: Option, + agent: Option, // deprecated, slated for removal in CHRON-185 + time: Option>, ) -> async_graphql::Result { - let api = ctx.data::()?; + let api = ctx.data::()?; - let identity = ctx.data::()?.to_owned(); + let identity = ctx.data::()?.to_owned(); - let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); + let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); - let res = api - .dispatch( - ApiCommand::Activity(ActivityCommand::Start { id, namespace, time, agent }), - identity, - ) - .await?; + let res = api + .dispatch( + ApiCommand::Activity(ActivityCommand::Start { id, namespace, time, agent }), + identity, + ) + .await?; - transaction_context(res, ctx).await + transaction_context(res, ctx).await } pub async fn end_activity<'a>( - ctx: &Context<'a>, - id: ActivityId, - namespace: Option, - agent: Option, // deprecated, slated for removal in CHRON-185 - time: Option>, + ctx: &Context<'a>, + id: ActivityId, + namespace: Option, + agent: Option, // deprecated, slated for removal in CHRON-185 + time: Option>, ) -> async_graphql::Result { - let api = ctx.data::()?; + let api = ctx.data::()?; - let identity = ctx.data::()?.to_owned(); + let identity = ctx.data::()?.to_owned(); - let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); + let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); - let res = api - .dispatch( - ApiCommand::Activity(ActivityCommand::End { id, namespace, time, agent }), - identity, - ) - .await?; + let res = api + .dispatch( + ApiCommand::Activity(ActivityCommand::End { id, namespace, time, agent }), + identity, + ) + .await?; - transaction_context(res, ctx).await + transaction_context(res, ctx).await } pub async fn instant_activity<'a>( - ctx: &Context<'a>, - id: ActivityId, - namespace: Option, - agent: Option, // deprecated, slated for removal in CHRON-185 - time: Option>, + ctx: &Context<'a>, + id: ActivityId, + namespace: Option, + agent: Option, // deprecated, slated for removal in CHRON-185 + time: Option>, ) -> async_graphql::Result { - let api = ctx.data::()?; + let api = ctx.data::()?; - let identity = ctx.data::()?.to_owned(); + let identity = ctx.data::()?.to_owned(); - let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); + let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); - let res = api - .dispatch( - ApiCommand::Activity(ActivityCommand::Instant { id, namespace, time, agent }), - identity, - ) - .await?; + let res = api + .dispatch( + ApiCommand::Activity(ActivityCommand::Instant { id, namespace, time, agent }), + identity, + ) + .await?; - transaction_context(res, ctx).await + transaction_context(res, ctx).await } pub async fn was_associated_with<'a>( - ctx: &Context<'a>, - namespace: Option, - responsible: AgentId, - activity: ActivityId, - role: Option, + ctx: &Context<'a>, + namespace: Option, + responsible: AgentId, + activity: ActivityId, + role: Option, ) -> async_graphql::Result { - let api = ctx.data::()?; + let api = ctx.data::()?; - let identity = ctx.data::()?.to_owned(); + let identity = ctx.data::()?.to_owned(); - let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); + let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); - let res = api - .dispatch( - ApiCommand::Activity(ActivityCommand::Associate { - id: activity, - responsible, - role, - namespace, - }), - identity, - ) - .await?; + let res = api + .dispatch( + ApiCommand::Activity(ActivityCommand::Associate { + id: activity, + responsible, + role, + namespace, + }), + identity, + ) + .await?; - transaction_context(res, ctx).await + transaction_context(res, ctx).await } pub async fn was_attributed_to<'a>( - ctx: &Context<'a>, - namespace: Option, - responsible: AgentId, - id: EntityId, - role: Option, + ctx: &Context<'a>, + namespace: Option, + responsible: AgentId, + id: EntityId, + role: Option, ) -> async_graphql::Result { - let api = ctx.data::()?; + let api = ctx.data::()?; - let identity = ctx.data::()?.to_owned(); + let identity = ctx.data::()?.to_owned(); - let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); + let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); - let res = api - .dispatch( - ApiCommand::Entity(EntityCommand::Attribute { id, namespace, responsible, role }), - identity, - ) - .await?; + let res = api + .dispatch( + ApiCommand::Entity(EntityCommand::Attribute { id, namespace, responsible, role }), + identity, + ) + .await?; - transaction_context(res, ctx).await + transaction_context(res, ctx).await } pub async fn used<'a>( - ctx: &Context<'a>, - activity: ActivityId, - entity: EntityId, - namespace: Option, + ctx: &Context<'a>, + activity: ActivityId, + entity: EntityId, + namespace: Option, ) -> async_graphql::Result { - let api = ctx.data::()?; + let api = ctx.data::()?; - let identity = ctx.data::()?.to_owned(); + let identity = ctx.data::()?.to_owned(); - let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); + let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); - let res = api - .dispatch( - ApiCommand::Activity(ActivityCommand::Use { id: entity, namespace, activity }), - identity, - ) - .await?; + let res = api + .dispatch( + ApiCommand::Activity(ActivityCommand::Use { id: entity, namespace, activity }), + identity, + ) + .await?; - transaction_context(res, ctx).await + transaction_context(res, ctx).await } pub async fn was_informed_by<'a>( - ctx: &Context<'a>, - activity: ActivityId, - informing_activity: ActivityId, - namespace: Option, + ctx: &Context<'a>, + activity: ActivityId, + informing_activity: ActivityId, + namespace: Option, ) -> async_graphql::Result { - let api = ctx.data::()?; + let api = ctx.data::()?; - let identity = ctx.data::()?.to_owned(); + let identity = ctx.data::()?.to_owned(); - let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); + let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); - let res = api - .dispatch( - ApiCommand::Activity(ActivityCommand::WasInformedBy { - id: activity, - namespace, - informing_activity, - }), - identity, - ) - .await?; + let res = api + .dispatch( + ApiCommand::Activity(ActivityCommand::WasInformedBy { + id: activity, + namespace, + informing_activity, + }), + identity, + ) + .await?; - transaction_context(res, ctx).await + transaction_context(res, ctx).await } pub async fn was_generated_by<'a>( - ctx: &Context<'a>, - activity: ActivityId, - entity: EntityId, - namespace: Option, + ctx: &Context<'a>, + activity: ActivityId, + entity: EntityId, + namespace: Option, ) -> async_graphql::Result { - let api = ctx.data::()?; + let api = ctx.data::()?; - let identity = ctx.data::()?.to_owned(); + let identity = ctx.data::()?.to_owned(); - let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); + let namespace = namespace.unwrap_or_else(|| "default".to_owned()).into(); - let res = api - .dispatch( - ApiCommand::Activity(ActivityCommand::Generate { id: entity, namespace, activity }), - identity, - ) - .await?; + let res = api + .dispatch( + ApiCommand::Activity(ActivityCommand::Generate { id: entity, namespace, activity }), + identity, + ) + .await?; - transaction_context(res, ctx).await + transaction_context(res, ctx).await } diff --git a/crates/api/src/chronicle_graphql/query.rs b/crates/api/src/chronicle_graphql/query.rs index e141c8dbd..342f739bf 100644 --- a/crates/api/src/chronicle_graphql/query.rs +++ b/crates/api/src/chronicle_graphql/query.rs @@ -1,320 +1,320 @@ use async_graphql::{ - connection::{query, Connection, EmptyFields}, - Context, ID, + connection::{Connection, EmptyFields, query}, + Context, ID, }; use chrono::{DateTime, NaiveDate, TimeZone, Utc}; use diesel::{debug_query, pg::Pg, prelude::*}; use tracing::{debug, instrument}; -use crate::chronicle_graphql::DatabaseContext; - -use super::{cursor_project::project_to_nodes, GraphQlError, Store, TimelineOrder}; use chronicle_persistence::{ - cursor::Cursorize, - queryable::{Activity, Agent, Entity}, - schema::generation, + cursor::Cursorize, + queryable::{Activity, Agent, Entity}, + schema::generation, }; -use common::{identity::AuthId, prov::{ActivityId, AgentId, DomaintypeId, EntityId, ExternalIdPart}}; +use common::{prov::{ActivityId, AgentId, DomaintypeId, EntityId, ExternalIdPart}}; + +use crate::chronicle_graphql::DatabaseContext; + +use super::{cursor_project::project_to_nodes, GraphQlError, TimelineOrder}; #[allow(clippy::too_many_arguments)] #[instrument(skip(ctx))] pub async fn activity_timeline<'a>( - ctx: &Context<'a>, - activity_types: Option>, - for_agent: Option>, - for_entity: Option>, - from: Option>, - to: Option>, - order: Option, - namespace: Option, - after: Option, - before: Option, - first: Option, - last: Option, + ctx: &Context<'a>, + activity_types: Option>, + for_agent: Option>, + for_entity: Option>, + from: Option>, + to: Option>, + order: Option, + namespace: Option, + after: Option, + before: Option, + first: Option, + last: Option, ) -> async_graphql::Result> { - use chronicle_persistence::schema::{ - activity, agent, association, delegation, entity, namespace::dsl as nsdsl, usage, - wasinformedby, - }; - - let store = ctx.data::()?; - - let mut connection = store.connection()?; - let ns = namespace.unwrap_or_else(|| "default".into()); - - // Default from and to to the maximum possible time range - let from = from.or_else(|| { - Some( - Utc.from_utc_datetime( - &NaiveDate::from_ymd_opt(1582, 10, 16) - .expect("Invalid date") - .and_hms_opt(0, 0, 0) - .expect("Invalid time"), - ), - ) - }); - - let to = to.or_else(|| Some(Utc::now())); - - let mut sql_query = activity::table - .left_join(wasinformedby::table.on(wasinformedby::activity_id.eq(activity::id))) - .left_join(usage::table.on(usage::activity_id.eq(activity::id))) - .left_join(generation::table.on(generation::activity_id.eq(activity::id))) - .left_join(association::table.on(association::activity_id.eq(activity::id))) - .left_join( - delegation::table.on(delegation::activity_id.nullable().eq(activity::id.nullable())), - ) - .left_join( - entity::table.on(entity::id - .eq(usage::entity_id) - .or(entity::id.eq(generation::generated_entity_id))), - ) - .left_join( - agent::table.on(agent::id - .eq(association::agent_id) - .or(agent::id.eq(delegation::delegate_id)) - .or(agent::id.eq(delegation::responsible_id))), - ) - .inner_join(nsdsl::namespace.on(activity::namespace_id.eq(nsdsl::id))) - .filter(nsdsl::external_id.eq(&**ns)) - .filter(activity::started.ge(from.map(|x| x.naive_utc()))) - .filter(activity::ended.le(to.map(|x| x.naive_utc()))) - .distinct() - .select(Activity::as_select()) - .into_boxed(); - - if let Some(for_entity) = for_entity { - if !for_entity.is_empty() { - sql_query = sql_query.filter(entity::external_id.eq_any( - for_entity.iter().map(|x| x.external_id_part().clone()).collect::>(), - )) - } - } - - if let Some(for_agent) = for_agent { - if !for_agent.is_empty() { - sql_query = - sql_query.filter(agent::external_id.eq_any( - for_agent.iter().map(|x| x.external_id_part().clone()).collect::>(), - )) - } - } - - if let Some(activity_types) = activity_types { - if !activity_types.is_empty() { - sql_query = sql_query.filter(activity::domaintype.eq_any( - activity_types.iter().map(|x| x.external_id_part().clone()).collect::>(), - )); - } - } - - if order.unwrap_or(TimelineOrder::NewestFirst) == TimelineOrder::NewestFirst { - sql_query = sql_query.order_by(activity::started.desc()); - } else { - sql_query = sql_query.order_by(activity::started.asc()); - }; - - query(after, before, first, last, |after, before, first, last| async move { - debug!("Cursor query {}", debug_query::(&sql_query).to_string()); - let rx = sql_query.cursor(after, before, first, last); - - let start = rx.start; - let limit = rx.limit; - - let rx = rx.load::<(Activity, i64)>(&mut connection)?; - - Ok::<_, GraphQlError>(project_to_nodes(rx, start, limit)) - }) - .await + use chronicle_persistence::schema::{ + activity, agent, association, delegation, entity, namespace::dsl as nsdsl, usage, + wasinformedby, + }; + + let store = ctx.data::()?; + + let mut connection = store.connection()?; + let ns = namespace.unwrap_or_else(|| "default".into()); + + // Default from and to to the maximum possible time range + let from = from.or_else(|| { + Some( + Utc.from_utc_datetime( + &NaiveDate::from_ymd_opt(1582, 10, 16) + .expect("Invalid date") + .and_hms_opt(0, 0, 0) + .expect("Invalid time"), + ), + ) + }); + + let to = to.or_else(|| Some(Utc::now())); + + let mut sql_query = activity::table + .left_join(wasinformedby::table.on(wasinformedby::activity_id.eq(activity::id))) + .left_join(usage::table.on(usage::activity_id.eq(activity::id))) + .left_join(generation::table.on(generation::activity_id.eq(activity::id))) + .left_join(association::table.on(association::activity_id.eq(activity::id))) + .left_join( + delegation::table.on(delegation::activity_id.nullable().eq(activity::id.nullable())), + ) + .left_join( + entity::table.on(entity::id + .eq(usage::entity_id) + .or(entity::id.eq(generation::generated_entity_id))), + ) + .left_join( + agent::table.on(agent::id + .eq(association::agent_id) + .or(agent::id.eq(delegation::delegate_id)) + .or(agent::id.eq(delegation::responsible_id))), + ) + .inner_join(nsdsl::namespace.on(activity::namespace_id.eq(nsdsl::id))) + .filter(nsdsl::external_id.eq(&**ns)) + .filter(activity::started.ge(from.map(|x| x.naive_utc()))) + .filter(activity::ended.le(to.map(|x| x.naive_utc()))) + .distinct() + .select(Activity::as_select()) + .into_boxed(); + + if let Some(for_entity) = for_entity { + if !for_entity.is_empty() { + sql_query = sql_query.filter(entity::external_id.eq_any( + for_entity.iter().map(|x| x.external_id_part().clone()).collect::>(), + )) + } + } + + if let Some(for_agent) = for_agent { + if !for_agent.is_empty() { + sql_query = + sql_query.filter(agent::external_id.eq_any( + for_agent.iter().map(|x| x.external_id_part().clone()).collect::>(), + )) + } + } + + if let Some(activity_types) = activity_types { + if !activity_types.is_empty() { + sql_query = sql_query.filter(activity::domaintype.eq_any( + activity_types.iter().map(|x| x.external_id_part().clone()).collect::>(), + )); + } + } + + if order.unwrap_or(TimelineOrder::NewestFirst) == TimelineOrder::NewestFirst { + sql_query = sql_query.order_by(activity::started.desc()); + } else { + sql_query = sql_query.order_by(activity::started.asc()); + }; + + query(after, before, first, last, |after, before, first, last| async move { + debug!("Cursor query {}", debug_query::(&sql_query).to_string()); + let rx = sql_query.cursor(after, before, first, last); + + let start = rx.start; + let limit = rx.limit; + + let rx = rx.load::<(Activity, i64)>(&mut connection)?; + + Ok::<_, GraphQlError>(project_to_nodes(rx, start, limit)) + }) + .await } #[allow(clippy::too_many_arguments)] - pub async fn entities_by_type<'a>( - ctx: &Context<'a>, - typ: Option, - namespace: Option, - after: Option, - before: Option, - first: Option, - last: Option, + ctx: &Context<'a>, + typ: Option, + namespace: Option, + after: Option, + before: Option, + first: Option, + last: Option, ) -> async_graphql::Result> { - use chronicle_persistence::schema::{entity, namespace::dsl as nsdsl}; + use chronicle_persistence::schema::{entity, namespace::dsl as nsdsl}; - let store = ctx.data::()?; + let store = ctx.data::()?; - let mut connection = store.connection()?; - let ns = namespace.unwrap_or_else(|| "default".into()); + let mut connection = store.connection()?; + let ns = namespace.unwrap_or_else(|| "default".into()); - let sql_query = entity::table - .inner_join(nsdsl::namespace) - .filter( - nsdsl::external_id - .eq(&**ns) - .and(entity::domaintype.eq(typ.as_ref().map(|x| x.external_id_part().to_owned()))), - ) - .select(Entity::as_select()) - .order_by(entity::external_id.asc()); + let sql_query = entity::table + .inner_join(nsdsl::namespace) + .filter( + nsdsl::external_id + .eq(&**ns) + .and(entity::domaintype.eq(typ.as_ref().map(|x| x.external_id_part().to_owned()))), + ) + .select(Entity::as_select()) + .order_by(entity::external_id.asc()); - query(after, before, first, last, |after, before, first, last| async move { - debug!("Cursor query {}", debug_query::(&sql_query).to_string()); - let rx = sql_query.cursor(after, before, first, last); + query(after, before, first, last, |after, before, first, last| async move { + debug!("Cursor query {}", debug_query::(&sql_query).to_string()); + let rx = sql_query.cursor(after, before, first, last); - let start = rx.start; - let limit = rx.limit; + let start = rx.start; + let limit = rx.limit; - let rx = rx.load::<(Entity, i64)>(&mut connection)?; + let rx = rx.load::<(Entity, i64)>(&mut connection)?; - Ok::<_, GraphQlError>(project_to_nodes(rx, start, limit)) - }) - .await + Ok::<_, GraphQlError>(project_to_nodes(rx, start, limit)) + }) + .await } #[allow(clippy::too_many_arguments)] pub async fn activities_by_type<'a>( - ctx: &Context<'a>, - typ: Option, - namespace: Option, - after: Option, - before: Option, - first: Option, - last: Option, + ctx: &Context<'a>, + typ: Option, + namespace: Option, + after: Option, + before: Option, + first: Option, + last: Option, ) -> async_graphql::Result> { - use chronicle_persistence::schema::{activity, namespace::dsl as nsdsl}; + use chronicle_persistence::schema::{activity, namespace::dsl as nsdsl}; - let store = ctx.data::()?; + let store = ctx.data::()?; - let mut connection = store.connection()?; - let ns = namespace.unwrap_or_else(|| "default".into()); + let mut connection = store.connection()?; + let ns = namespace.unwrap_or_else(|| "default".into()); - let sql_query = - activity::table - .inner_join(nsdsl::namespace) - .filter(nsdsl::external_id.eq(&**ns).and( - activity::domaintype.eq(typ.as_ref().map(|x| x.external_id_part().to_owned())), - )) - .select(Activity::as_select()) - .order_by(activity::external_id.asc()); + let sql_query = + activity::table + .inner_join(nsdsl::namespace) + .filter(nsdsl::external_id.eq(&**ns).and( + activity::domaintype.eq(typ.as_ref().map(|x| x.external_id_part().to_owned())), + )) + .select(Activity::as_select()) + .order_by(activity::external_id.asc()); - query(after, before, first, last, |after, before, first, last| async move { - debug!("Cursor query {}", debug_query::(&sql_query).to_string()); - let rx = sql_query.cursor(after, before, first, last); + query(after, before, first, last, |after, before, first, last| async move { + debug!("Cursor query {}", debug_query::(&sql_query).to_string()); + let rx = sql_query.cursor(after, before, first, last); - let start = rx.start; - let limit = rx.limit; + let start = rx.start; + let limit = rx.limit; - let rx = rx.load::<(Activity, i64)>(&mut connection)?; + let rx = rx.load::<(Activity, i64)>(&mut connection)?; - Ok::<_, GraphQlError>(project_to_nodes(rx, start, limit)) - }) - .await + Ok::<_, GraphQlError>(project_to_nodes(rx, start, limit)) + }) + .await } #[allow(clippy::too_many_arguments)] pub async fn agents_by_type<'a>( - ctx: &Context<'a>, - typ: Option, - namespace: Option, - after: Option, - before: Option, - first: Option, - last: Option, + ctx: &Context<'a>, + typ: Option, + namespace: Option, + after: Option, + before: Option, + first: Option, + last: Option, ) -> async_graphql::Result> { - use chronicle_persistence::schema::{agent, namespace::dsl as nsdsl}; + use chronicle_persistence::schema::{agent, namespace::dsl as nsdsl}; - let store = ctx.data::()?; + let store = ctx.data::()?; - let mut connection = store.connection()?; - let ns = namespace.unwrap_or_else(|| "default".into()); + let mut connection = store.connection()?; + let ns = namespace.unwrap_or_else(|| "default".into()); - let sql_query = agent::table - .inner_join(nsdsl::namespace) - .filter( - nsdsl::external_id - .eq(&**ns) - .and(agent::domaintype.eq(typ.as_ref().map(|x| x.external_id_part().to_owned()))), - ) - .select(Agent::as_select()) - .order_by(agent::external_id.asc()); + let sql_query = agent::table + .inner_join(nsdsl::namespace) + .filter( + nsdsl::external_id + .eq(&**ns) + .and(agent::domaintype.eq(typ.as_ref().map(|x| x.external_id_part().to_owned()))), + ) + .select(Agent::as_select()) + .order_by(agent::external_id.asc()); - query(after, before, first, last, |after, before, first, last| async move { - debug!("Cursor query {}", debug_query::(&sql_query).to_string()); - let rx = sql_query.cursor(after, before, first, last); + query(after, before, first, last, |after, before, first, last| async move { + debug!("Cursor query {}", debug_query::(&sql_query).to_string()); + let rx = sql_query.cursor(after, before, first, last); - let start = rx.start; - let limit = rx.limit; + let start = rx.start; + let limit = rx.limit; - let rx = rx.load::<(Agent, i64)>(&mut connection)?; + let rx = rx.load::<(Agent, i64)>(&mut connection)?; - Ok::<_, GraphQlError>(project_to_nodes(rx, start, limit)) - }) - .await + Ok::<_, GraphQlError>(project_to_nodes(rx, start, limit)) + }) + .await } pub async fn agent_by_id<'a>( - ctx: &Context<'a>, - id: AgentId, - namespace: Option, + ctx: &Context<'a>, + id: AgentId, + namespace: Option, ) -> async_graphql::Result> { - use chronicle_persistence::schema::{ - agent::{self, dsl}, - namespace::dsl as nsdsl, - }; - - let store = ctx.data::()?; - - let ns = namespace.unwrap_or_else(|| "default".into()); - let mut connection = store.connection()?; - - Ok(agent::table - .inner_join(nsdsl::namespace) - .filter(dsl::external_id.eq(id.external_id_part()).and(nsdsl::external_id.eq(&ns))) - .select(Agent::as_select()) - .first::(&mut connection) - .optional()?) + use chronicle_persistence::schema::{ + agent::{self, dsl}, + namespace::dsl as nsdsl, + }; + + let store = ctx.data::()?; + + let ns = namespace.unwrap_or_else(|| "default".into()); + let mut connection = store.connection()?; + + Ok(agent::table + .inner_join(nsdsl::namespace) + .filter(dsl::external_id.eq(id.external_id_part()).and(nsdsl::external_id.eq(&ns))) + .select(Agent::as_select()) + .first::(&mut connection) + .optional()?) } pub async fn activity_by_id<'a>( - ctx: &Context<'a>, - id: ActivityId, - namespace: Option, + ctx: &Context<'a>, + id: ActivityId, + namespace: Option, ) -> async_graphql::Result> { - use chronicle_persistence::schema::{ - activity::{self, dsl}, - namespace::dsl as nsdsl, - }; - - let store = ctx.data::()?; - - let ns = namespace.unwrap_or_else(|| "default".into()); - let mut connection = store.connection()?; - - Ok(activity::table - .inner_join(nsdsl::namespace) - .filter(dsl::external_id.eq(id.external_id_part()).and(nsdsl::external_id.eq(&ns))) - .select(Activity::as_select()) - .first::(&mut connection) - .optional()?) + use chronicle_persistence::schema::{ + activity::{self, dsl}, + namespace::dsl as nsdsl, + }; + + let store = ctx.data::()?; + + let ns = namespace.unwrap_or_else(|| "default".into()); + let mut connection = store.connection()?; + + Ok(activity::table + .inner_join(nsdsl::namespace) + .filter(dsl::external_id.eq(id.external_id_part()).and(nsdsl::external_id.eq(&ns))) + .select(Activity::as_select()) + .first::(&mut connection) + .optional()?) } pub async fn entity_by_id<'a>( - ctx: &Context<'a>, - id: EntityId, - namespace: Option, + ctx: &Context<'a>, + id: EntityId, + namespace: Option, ) -> async_graphql::Result> { - use chronicle_persistence::schema::{ - entity::{self, dsl}, - namespace::dsl as nsdsl, - }; - - let store = ctx.data::()?; - let ns = namespace.unwrap_or_else(|| "default".into()); - let mut connection = store.connection()?; - - Ok(entity::table - .inner_join(nsdsl::namespace) - .filter(dsl::external_id.eq(id.external_id_part()).and(nsdsl::external_id.eq(&ns))) - .select(Entity::as_select()) - .first::(&mut connection) - .optional()?) + use chronicle_persistence::schema::{ + entity::{self, dsl}, + namespace::dsl as nsdsl, + }; + + let store = ctx.data::()?; + let ns = namespace.unwrap_or_else(|| "default".into()); + let mut connection = store.connection()?; + + Ok(entity::table + .inner_join(nsdsl::namespace) + .filter(dsl::external_id.eq(id.external_id_part()).and(nsdsl::external_id.eq(&ns))) + .select(Entity::as_select()) + .first::(&mut connection) + .optional()?) } diff --git a/crates/api/src/commands.rs b/crates/api/src/commands.rs index b3c25c04e..624aa1a7d 100644 --- a/crates/api/src/commands.rs +++ b/crates/api/src/commands.rs @@ -5,304 +5,304 @@ use std::{path::PathBuf, sync::Arc}; use chrono::{DateTime, Utc}; use futures::AsyncRead; - use serde::{Deserialize, Serialize}; use common::{ - attributes::Attributes, - prov::{ - operations::{ChronicleOperation, DerivationType}, - ActivityId, AgentId, ChronicleIri, ChronicleTransactionId, EntityId, ExternalId, - NamespaceId, ProvModel, Role, - }, + attributes::Attributes, + prov::{ + ActivityId, + AgentId, ChronicleIri, ChronicleTransactionId, EntityId, ExternalId, NamespaceId, + operations::{ChronicleOperation, DerivationType}, ProvModel, Role, + }, }; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum NamespaceCommand { - Create { id: ExternalId }, + Create { id: ExternalId }, } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum AgentCommand { - Create { - id: ExternalId, - namespace: ExternalId, - attributes: Attributes, - }, - UseInContext { - id: AgentId, - namespace: ExternalId, - }, - Delegate { - id: AgentId, - delegate: AgentId, - activity: Option, - namespace: ExternalId, - role: Option, - }, + Create { + id: ExternalId, + namespace: ExternalId, + attributes: Attributes, + }, + UseInContext { + id: AgentId, + namespace: ExternalId, + }, + Delegate { + id: AgentId, + delegate: AgentId, + activity: Option, + namespace: ExternalId, + role: Option, + }, } + #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ActivityCommand { - Create { - id: ExternalId, - namespace: ExternalId, - attributes: Attributes, - }, - Instant { - id: ActivityId, - namespace: ExternalId, - time: Option>, - agent: Option, - }, - Start { - id: ActivityId, - namespace: ExternalId, - time: Option>, - agent: Option, - }, - End { - id: ActivityId, - namespace: ExternalId, - time: Option>, - agent: Option, - }, - Use { - id: EntityId, - namespace: ExternalId, - activity: ActivityId, - }, - Generate { - id: EntityId, - namespace: ExternalId, - activity: ActivityId, - }, - WasInformedBy { - id: ActivityId, - namespace: ExternalId, - informing_activity: ActivityId, - }, - Associate { - id: ActivityId, - namespace: ExternalId, - responsible: AgentId, - role: Option, - }, + Create { + id: ExternalId, + namespace: ExternalId, + attributes: Attributes, + }, + Instant { + id: ActivityId, + namespace: ExternalId, + time: Option>, + agent: Option, + }, + Start { + id: ActivityId, + namespace: ExternalId, + time: Option>, + agent: Option, + }, + End { + id: ActivityId, + namespace: ExternalId, + time: Option>, + agent: Option, + }, + Use { + id: EntityId, + namespace: ExternalId, + activity: ActivityId, + }, + Generate { + id: EntityId, + namespace: ExternalId, + activity: ActivityId, + }, + WasInformedBy { + id: ActivityId, + namespace: ExternalId, + informing_activity: ActivityId, + }, + Associate { + id: ActivityId, + namespace: ExternalId, + responsible: AgentId, + role: Option, + }, } impl ActivityCommand { - pub fn create( - external_id: impl AsRef, - namespace: impl AsRef, - attributes: Attributes, - ) -> Self { - Self::Create { - id: external_id.as_ref().into(), - namespace: namespace.as_ref().into(), - attributes, - } - } + pub fn create( + external_id: impl AsRef, + namespace: impl AsRef, + attributes: Attributes, + ) -> Self { + Self::Create { + id: external_id.as_ref().into(), + namespace: namespace.as_ref().into(), + attributes, + } + } - pub fn start( - id: ActivityId, - namespace: impl AsRef, - time: Option>, - agent: Option, - ) -> Self { - Self::Start { id, namespace: namespace.as_ref().into(), time, agent } - } + pub fn start( + id: ActivityId, + namespace: impl AsRef, + time: Option>, + agent: Option, + ) -> Self { + Self::Start { id, namespace: namespace.as_ref().into(), time, agent } + } - pub fn end( - id: ActivityId, - namespace: impl AsRef, - time: Option>, - agent: Option, - ) -> Self { - Self::End { id, namespace: namespace.as_ref().into(), time, agent } - } + pub fn end( + id: ActivityId, + namespace: impl AsRef, + time: Option>, + agent: Option, + ) -> Self { + Self::End { id, namespace: namespace.as_ref().into(), time, agent } + } - pub fn instant( - id: ActivityId, - namespace: impl AsRef, - time: Option>, - agent: Option, - ) -> Self { - Self::End { id, namespace: namespace.as_ref().into(), time, agent } - } + pub fn instant( + id: ActivityId, + namespace: impl AsRef, + time: Option>, + agent: Option, + ) -> Self { + Self::End { id, namespace: namespace.as_ref().into(), time, agent } + } - pub fn r#use(id: EntityId, namespace: impl AsRef, activity: ActivityId) -> Self { - Self::Use { id, namespace: namespace.as_ref().into(), activity } - } + pub fn r#use(id: EntityId, namespace: impl AsRef, activity: ActivityId) -> Self { + Self::Use { id, namespace: namespace.as_ref().into(), activity } + } - pub fn was_informed_by( - id: ActivityId, - namespace: impl AsRef, - informing_activity: ActivityId, - ) -> Self { - Self::WasInformedBy { id, namespace: namespace.as_ref().into(), informing_activity } - } + pub fn was_informed_by( + id: ActivityId, + namespace: impl AsRef, + informing_activity: ActivityId, + ) -> Self { + Self::WasInformedBy { id, namespace: namespace.as_ref().into(), informing_activity } + } - pub fn generate(id: EntityId, namespace: impl AsRef, activity: ActivityId) -> Self { - Self::Generate { id, namespace: namespace.as_ref().into(), activity } - } + pub fn generate(id: EntityId, namespace: impl AsRef, activity: ActivityId) -> Self { + Self::Generate { id, namespace: namespace.as_ref().into(), activity } + } } #[derive(Clone)] pub enum PathOrFile { - Path(PathBuf), - File(Arc>>), + Path(PathBuf), + File(Arc>>), } impl core::fmt::Debug for PathOrFile { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - PathOrFile::Path(path) => f.debug_struct("Path").field("path", path).finish(), - PathOrFile::File(_) => f - .debug_struct("File") - .field("file", &"Non serialisable variant, used in process") - .finish(), - } - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + PathOrFile::Path(path) => f.debug_struct("Path").field("path", path).finish(), + PathOrFile::File(_) => f + .debug_struct("File") + .field("file", &"Non serialisable variant, used in process") + .finish(), + } + } } impl Serialize for PathOrFile { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match self { - PathOrFile::Path(path) => path.serialize(serializer), - _ => { - unreachable!() - }, - } - } + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + PathOrFile::Path(path) => path.serialize(serializer), + _ => { + unreachable!() + } + } + } } impl<'de> Deserialize<'de> for PathOrFile { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - Ok(PathOrFile::Path(PathBuf::deserialize(deserializer)?)) - } + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Ok(PathOrFile::Path(PathBuf::deserialize(deserializer)?)) + } } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum EntityCommand { - Create { - id: ExternalId, - namespace: ExternalId, - attributes: Attributes, - }, - Attribute { - id: EntityId, - namespace: ExternalId, - responsible: AgentId, - role: Option, - }, - Derive { - id: EntityId, - namespace: ExternalId, - derivation: DerivationType, - activity: Option, - used_entity: EntityId, - }, + Create { + id: ExternalId, + namespace: ExternalId, + attributes: Attributes, + }, + Attribute { + id: EntityId, + namespace: ExternalId, + responsible: AgentId, + role: Option, + }, + Derive { + id: EntityId, + namespace: ExternalId, + derivation: DerivationType, + activity: Option, + used_entity: EntityId, + }, } impl EntityCommand { - pub fn create( - external_id: impl AsRef, - namespace: impl AsRef, - attributes: Attributes, - ) -> Self { - Self::Create { - id: external_id.as_ref().into(), - namespace: namespace.as_ref().into(), - attributes, - } - } + pub fn create( + external_id: impl AsRef, + namespace: impl AsRef, + attributes: Attributes, + ) -> Self { + Self::Create { + id: external_id.as_ref().into(), + namespace: namespace.as_ref().into(), + attributes, + } + } - pub fn detach( - id: EntityId, - namespace: impl AsRef, - derivation: DerivationType, - activity: Option, - used_entity: EntityId, - ) -> Self { - Self::Derive { id, namespace: namespace.as_ref().into(), derivation, activity, used_entity } - } + pub fn detach( + id: EntityId, + namespace: impl AsRef, + derivation: DerivationType, + activity: Option, + used_entity: EntityId, + ) -> Self { + Self::Derive { id, namespace: namespace.as_ref().into(), derivation, activity, used_entity } + } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct QueryCommand { - pub namespace: String, + pub namespace: String, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DepthChargeCommand { - pub namespace: NamespaceId, + pub namespace: NamespaceId, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ImportCommand { - pub operations: Vec, + pub operations: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ApiCommand { - NameSpace(NamespaceCommand), - Agent(AgentCommand), - Activity(ActivityCommand), - Entity(EntityCommand), - Query(QueryCommand), - DepthCharge(DepthChargeCommand), - Import(ImportCommand), + NameSpace(NamespaceCommand), + Agent(AgentCommand), + Activity(ActivityCommand), + Entity(EntityCommand), + Query(QueryCommand), + DepthCharge(DepthChargeCommand), + Import(ImportCommand), } #[derive(Debug)] pub enum ApiResponse { - /// The api has successfully executed the operation, but has no useful output - Unit, - /// The operation will not result in any data changes - AlreadyRecorded { subject: ChronicleIri, prov: Box }, - /// The aggregate operation will not result in any data changes - AlreadyRecordedAll, - /// The api has validated the command and submitted a transaction to a ledger - Submission { subject: ChronicleIri, prov: Box, tx_id: ChronicleTransactionId }, - /// The api has successfully executed the query - QueryReply { prov: Box }, - /// The api has submitted the import transactions to a ledger - ImportSubmitted { prov: Box, tx_id: ChronicleTransactionId }, - /// The api has submitted the depth charge transaction to a ledger - DepthChargeSubmitted { tx_id: ChronicleTransactionId }, + /// The api has successfully executed the operation, but has no useful output + Unit, + /// The operation will not result in any data changes + AlreadyRecorded { subject: ChronicleIri, prov: Box }, + /// The aggregate operation will not result in any data changes + AlreadyRecordedAll, + /// The api has validated the command and submitted a transaction to a ledger + Submission { subject: ChronicleIri, prov: Box, tx_id: ChronicleTransactionId }, + /// The api has successfully executed the query + QueryReply { prov: Box }, + /// The api has submitted the import transactions to a ledger + ImportSubmitted { prov: Box, tx_id: ChronicleTransactionId }, + /// The api has submitted the depth charge transaction to a ledger + DepthChargeSubmitted { tx_id: ChronicleTransactionId }, } impl ApiResponse { - pub fn submission( - subject: impl Into, - prov: ProvModel, - tx_id: ChronicleTransactionId, - ) -> Self { - ApiResponse::Submission { subject: subject.into(), prov: Box::new(prov), tx_id } - } + pub fn submission( + subject: impl Into, + prov: ProvModel, + tx_id: ChronicleTransactionId, + ) -> Self { + ApiResponse::Submission { subject: subject.into(), prov: Box::new(prov), tx_id } + } - pub fn unit() -> Self { - ApiResponse::Unit - } + pub fn unit() -> Self { + ApiResponse::Unit + } - pub fn query_reply(prov: ProvModel) -> Self { - ApiResponse::QueryReply { prov: Box::new(prov) } - } + pub fn query_reply(prov: ProvModel) -> Self { + ApiResponse::QueryReply { prov: Box::new(prov) } + } - pub fn already_recorded(subject: impl Into, prov: ProvModel) -> Self { - ApiResponse::AlreadyRecorded { subject: subject.into(), prov: Box::new(prov) } - } + pub fn already_recorded(subject: impl Into, prov: ProvModel) -> Self { + ApiResponse::AlreadyRecorded { subject: subject.into(), prov: Box::new(prov) } + } - pub fn depth_charge_submission(tx_id: ChronicleTransactionId) -> Self { - ApiResponse::DepthChargeSubmitted { tx_id } - } + pub fn depth_charge_submission(tx_id: ChronicleTransactionId) -> Self { + ApiResponse::DepthChargeSubmitted { tx_id } + } - pub fn import_submitted(prov: ProvModel, tx_id: ChronicleTransactionId) -> Self { - ApiResponse::ImportSubmitted { prov: Box::new(prov), tx_id } - } + pub fn import_submitted(prov: ProvModel, tx_id: ChronicleTransactionId) -> Self { + ApiResponse::ImportSubmitted { prov: Box::new(prov), tx_id } + } } diff --git a/crates/api/src/dispatch.rs b/crates/api/src/dispatch.rs new file mode 100644 index 000000000..900a8cb81 --- /dev/null +++ b/crates/api/src/dispatch.rs @@ -0,0 +1,84 @@ +use tokio::sync::mpsc; +use tokio::sync::mpsc::Sender; +use tracing::{error, instrument, trace}; +use uuid::Uuid; + +use common::identity::AuthId; +use common::ledger::SubmissionStage; +use common::prov::NamespaceId; +use common::prov::operations::ChronicleOperation; + +use crate::ApiError; +use crate::commands::{ApiCommand, ApiResponse, DepthChargeCommand, ImportCommand}; + +pub type ApiSendWithReply = ((ApiCommand, AuthId), Sender>); + +#[derive(Debug, Clone)] +/// A clonable api handle +pub struct ApiDispatch { + pub(crate) tx: Sender, + pub notify_commit: tokio::sync::broadcast::Sender, +} + +impl ApiDispatch { + #[instrument] + pub async fn dispatch( + &self, + command: ApiCommand, + identity: AuthId, + ) -> Result { + let (reply_tx, mut reply_rx) = mpsc::channel(1); + trace!(?command, "Dispatch command to api"); + self.tx.clone().send(((command, identity), reply_tx)).await?; + + let reply = reply_rx.recv().await; + + if let Some(Err(ref error)) = reply { + error!(?error, "Api dispatch"); + } + + reply.ok_or(ApiError::ApiShutdownRx {})? + } + + #[instrument] + pub async fn handle_import_command( + &self, + identity: AuthId, + operations: Vec, + ) -> Result { + self.import_operations(identity, operations).await + } + + #[instrument] + async fn import_operations( + &self, + identity: AuthId, + operations: Vec, + ) -> Result { + self.dispatch(ApiCommand::Import(ImportCommand { operations }), identity.clone()) + .await + } + + #[instrument] + pub async fn handle_depth_charge( + &self, + namespace: &str, + uuid: &Uuid, + ) -> Result { + self.dispatch_depth_charge( + AuthId::Chronicle, + NamespaceId::from_external_id(namespace, *uuid), + ) + .await + } + + #[instrument] + async fn dispatch_depth_charge( + &self, + identity: AuthId, + namespace: NamespaceId, + ) -> Result { + self.dispatch(ApiCommand::DepthCharge(DepthChargeCommand { namespace }), identity.clone()) + .await + } +} diff --git a/crates/api/src/error.rs b/crates/api/src/error.rs new file mode 100644 index 000000000..8dd5f8e7a --- /dev/null +++ b/crates/api/src/error.rs @@ -0,0 +1,153 @@ +use std::convert::Infallible; +use std::net::AddrParseError; + +use thiserror::Error; +use tokio::sync::mpsc::error::SendError; +use tokio::task::JoinError; +use user_error::UFE; + +use chronicle_signing::SecretError; +use common::identity::IdentityError; +use common::ledger::SubmissionError; +use common::prov::{Contradiction, ProcessorError}; +use protocol_substrate::SubxtClientError; + +use crate::chronicle_graphql; +use crate::dispatch::ApiSendWithReply; + +#[derive(Error, Debug)] +pub enum ApiError { + #[error("Storage: {0:?}")] + Store( + #[from] + #[source] + chronicle_persistence::StoreError, + ), + + #[error("Storage: {0:?}")] + ArrowService(#[source] anyhow::Error), + + #[error("Transaction failed: {0}")] + Transaction( + #[from] + #[source] + diesel::result::Error, + ), + + #[error("Invalid IRI: {0}")] + Iri( + #[from] + #[source] + iref::Error, + ), + + #[error("JSON-LD processing: {0}")] + JsonLD(String), + + #[error("Signing: {0}")] + Signing( + #[from] + #[source] + SecretError, + ), + + #[error("No agent is currently in use, please call agent use or supply an agent in your call")] + NoCurrentAgent, + + #[error("Api shut down before reply")] + ApiShutdownRx, + + #[error("Api shut down before send: {0}")] + ApiShutdownTx( + #[from] + #[source] + SendError, + ), + + #[error("Invalid socket address: {0}")] + AddressParse( + #[from] + #[source] + AddrParseError, + ), + + #[error("Connection pool: {0}")] + ConnectionPool( + #[from] + #[source] + r2d2::Error, + ), + + #[error("IO error: {0}")] + InputOutput( + #[from] + #[source] + std::io::Error, + ), + + #[error("Blocking thread pool: {0}")] + Join( + #[from] + #[source] + JoinError, + ), + + #[error("No appropriate activity to end")] + NotCurrentActivity, + + #[error("Processor: {0}")] + ProcessorError( + #[from] + #[source] + ProcessorError, + ), + + #[error("Identity: {0}")] + IdentityError( + #[from] + #[source] + IdentityError, + ), + + #[error("Authentication endpoint error: {0}")] + AuthenticationEndpoint( + #[from] + #[source] + chronicle_graphql::AuthorizationError, + ), + + #[error("Substrate : {0}")] + ClientError( + #[from] + #[source] + SubxtClientError, + ), + + #[error("Submission : {0}")] + Submission( + #[from] + #[source] + SubmissionError, + ), + + #[error("Contradiction: {0}")] + Contradiction(Contradiction), + + #[error("Embedded substrate: {0}")] + EmbeddedSubstrate(anyhow::Error), +} + +/// Ugly but we need this until ! is stable, see +impl From for ApiError { + fn from(_: Infallible) -> Self { + unreachable!() + } +} + +impl From for ApiError { + fn from(x: Contradiction) -> Self { + Self::Contradiction(x) + } +} + +impl UFE for ApiError {} diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index 00c0155e7..57196f343 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -1,1745 +1,52 @@ #![cfg_attr(feature = "strict", deny(warnings))] -pub mod chronicle_graphql; -pub mod commands; - -pub use chronicle_persistence::Store; -use chronicle_signing::{ChronicleKnownKeyNamesSigner, ChronicleSigning, SecretError}; -use chrono::{DateTime, Utc}; - -use common::{ - attributes::Attributes, - identity::{AuthId, IdentityError, SignedIdentity}, - ledger::{Commit, SubmissionError, SubmissionStage}, - opa::PolicyAddress, - prov::{ - json_ld::ToJson, - operations::{ - ActivityExists, ActivityUses, ActsOnBehalfOf, AgentExists, ChronicleOperation, - CreateNamespace, DerivationType, EndActivity, EntityDerive, EntityExists, - SetAttributes, StartActivity, WasAssociatedWith, WasAttributedTo, WasGeneratedBy, - WasInformedBy, - }, - ActivityId, AgentId, ChronicleIri, ChronicleTransactionId, Contradiction, EntityId, - ExternalId, ExternalIdPart, NamespaceId, ProcessorError, ProvModel, Role, UuidPart, - SYSTEM_ID, SYSTEM_UUID, - }, -}; -use diesel::{r2d2::ConnectionManager, PgConnection}; -use diesel_migrations::MigrationHarness; -use futures::{select, FutureExt, StreamExt}; - -pub use chronicle_persistence::StoreError; -use chronicle_persistence::MIGRATIONS; -use diesel::r2d2::Pool; -use metrics::histogram; -use metrics_exporter_prometheus::PrometheusBuilder; -use protocol_substrate::SubxtClientError; -use protocol_substrate_chronicle::{ - protocol::{BlockId, FromBlock, LedgerReader, LedgerWriter}, - ChronicleEvent, ChronicleTransaction, -}; -use std::{ - convert::Infallible, - marker::PhantomData, - net::AddrParseError, - time::{Duration, Instant}, -}; -use thiserror::Error; -use tokio::{ - sync::mpsc::{self, error::SendError, Sender}, - task::JoinError, -}; - -use commands::*; -pub mod import; -use tracing::{debug, error, info, info_span, instrument, trace, warn, Instrument}; - -use user_error::UFE; -use uuid::Uuid; -#[derive(Error, Debug)] -pub enum ApiError { - #[error("Storage: {0:?}")] - Store( - #[from] - #[source] - chronicle_persistence::StoreError, - ), - - #[error("Storage: {0:?}")] - ArrowService(#[source] anyhow::Error), - - #[error("Transaction failed: {0}")] - Transaction( - #[from] - #[source] - diesel::result::Error, - ), - - #[error("Invalid IRI: {0}")] - Iri( - #[from] - #[source] - iref::Error, - ), - - #[error("JSON-LD processing: {0}")] - JsonLD(String), - - #[error("Signing: {0}")] - Signing( - #[from] - #[source] - SecretError, - ), - - #[error("No agent is currently in use, please call agent use or supply an agent in your call")] - NoCurrentAgent, - - #[error("Api shut down before reply")] - ApiShutdownRx, - - #[error("Api shut down before send: {0}")] - ApiShutdownTx( - #[from] - #[source] - SendError, - ), - - #[error("Ledger shut down before send: {0}")] - LedgerShutdownTx( - #[from] - #[source] - SendError, - ), - - #[error("Invalid socket address: {0}")] - AddressParse( - #[from] - #[source] - AddrParseError, - ), - - #[error("Connection pool: {0}")] - ConnectionPool( - #[from] - #[source] - r2d2::Error, - ), - - #[error("IO error: {0}")] - InputOutput( - #[from] - #[source] - std::io::Error, - ), - #[error("Blocking thread pool: {0}")] - Join( - #[from] - #[source] - JoinError, - ), - #[error("No appropriate activity to end")] - NotCurrentActivity, - #[error("Processor: {0}")] - ProcessorError( - #[from] - #[source] - ProcessorError, - ), - #[error("Identity: {0}")] - IdentityError( - #[from] - #[source] - IdentityError, - ), - #[error("Authentication endpoint error: {0}")] - AuthenticationEndpoint( - #[from] - #[source] - chronicle_graphql::AuthorizationError, - ), - #[error("Substrate : {0}")] - ClientError( - #[from] - #[source] - SubxtClientError, - ), - - #[error("Submission : {0}")] - Submission( - #[from] - #[source] - SubmissionError, - ), - - #[error("Contradiction: {0}")] - Contradiction(Contradiction), - - #[error("Embedded substrate: {0}")] - EmbeddedSubstrate(anyhow::Error), -} - -/// Ugly but we need this until ! is stable, see -impl From for ApiError { - fn from(_: Infallible) -> Self { - unreachable!() - } -} - -impl From for ApiError { - fn from(x: Contradiction) -> Self { - Self::Contradiction(x) - } -} - -impl UFE for ApiError {} +pub use api::{Api, UuidGen}; +pub use chronicle_persistence::Store; +pub use chronicle_persistence::StoreError; +use chronicle_signing::ChronicleKnownKeyNamesSigner; +use common::{ + identity::{AuthId, IdentityError, SignedIdentity}, +}; +pub use dispatch::ApiDispatch; +pub use error::ApiError; -type LedgerSendWithReply = - (ChronicleTransaction, Sender>); -type ApiSendWithReply = ((ApiCommand, AuthId), Sender>); +pub mod chronicle_graphql; +pub mod commands; -pub trait UuidGen { - fn uuid() -> Uuid { - Uuid::new_v4() - } -} +pub mod import; +mod error; +mod api; +mod dispatch; pub trait ChronicleSigned { - /// Get the user identity's [`SignedIdentity`] - fn signed_identity( - &self, - store: &S, - ) -> Result; + /// Get the user identity's [`SignedIdentity`] + fn signed_identity( + &self, + store: &S, + ) -> Result; } impl ChronicleSigned for AuthId { - fn signed_identity( - &self, - store: &S, - ) -> Result { - let signable = self.to_string(); - let signature = futures::executor::block_on(store.chronicle_sign(signable.as_bytes())) - .map_err(|e| IdentityError::Signing(e.into()))?; - let public_key = futures::executor::block_on(store.chronicle_verifying()) - .map_err(|e| IdentityError::Signing(e.into()))?; - - Ok(SignedIdentity { - identity: signable, - signature: signature.into(), - verifying_key: Some(public_key.to_bytes().to_vec()), - }) - } -} - -#[derive(Clone)] -pub struct Api< - U: UuidGen + Send + Sync + Clone, - W: LedgerWriter - + Clone - + Send - + Sync - + 'static, -> { - submit_tx: tokio::sync::broadcast::Sender, - signing: ChronicleSigning, - ledger_writer: W, - store: chronicle_persistence::Store, - uuid_source: PhantomData, -} - -#[derive(Debug, Clone)] -/// A clonable api handle -pub struct ApiDispatch { - tx: Sender, - pub notify_commit: tokio::sync::broadcast::Sender, -} - -impl ApiDispatch { - #[instrument] - pub async fn dispatch( - &self, - command: ApiCommand, - identity: AuthId, - ) -> Result { - let (reply_tx, mut reply_rx) = mpsc::channel(1); - trace!(?command, "Dispatch command to api"); - self.tx.clone().send(((command, identity), reply_tx)).await?; - - let reply = reply_rx.recv().await; - - if let Some(Err(ref error)) = reply { - error!(?error, "Api dispatch"); - } - - reply.ok_or(ApiError::ApiShutdownRx {})? - } - - #[instrument] - pub async fn handle_import_command( - &self, - identity: AuthId, - operations: Vec, - ) -> Result { - self.import_operations(identity, operations).await - } - - #[instrument] - async fn import_operations( - &self, - identity: AuthId, - operations: Vec, - ) -> Result { - self.dispatch(ApiCommand::Import(ImportCommand { operations }), identity.clone()) - .await - } - - #[instrument] - pub async fn handle_depth_charge( - &self, - namespace: &str, - uuid: &Uuid, - ) -> Result { - self.dispatch_depth_charge( - AuthId::Chronicle, - NamespaceId::from_external_id(namespace, *uuid), - ) - .await - } - - #[instrument] - async fn dispatch_depth_charge( - &self, - identity: AuthId, - namespace: NamespaceId, - ) -> Result { - self.dispatch(ApiCommand::DepthCharge(DepthChargeCommand { namespace }), identity.clone()) - .await - } -} - -fn install_prometheus_metrics_exporter() { - let metrics_endpoint = "127.0.0.1:9000"; - let metrics_listen_socket = match metrics_endpoint.parse::() { - Ok(addr) => addr, - Err(e) => { - error!("Unable to parse metrics listen socket address: {e:?}"); - return; - }, - }; - - if let Err(e) = PrometheusBuilder::new().with_http_listener(metrics_listen_socket).install() { - error!("Prometheus exporter installation for liveness check metrics failed: {e:?}"); - } else { - debug!("Liveness check metrics Prometheus exporter installed with endpoint on {metrics_endpoint}/metrics"); - } -} - -impl Api -where - U: UuidGen + Send + Sync + Clone + core::fmt::Debug + 'static, - LEDGER: LedgerWriter - + LedgerReader - + Clone - + Send - + Sync - + 'static, -{ - #[instrument(skip(ledger))] - pub async fn new( - pool: Pool>, - ledger: LEDGER, - uuidgen: U, - signing: ChronicleSigning, - namespace_bindings: Vec, - policy_address: Option, - liveness_check_interval: Option, - ) -> Result { - let (commit_tx, mut commit_rx) = mpsc::channel::(10); - - let (commit_notify_tx, _) = tokio::sync::broadcast::channel(20); - let dispatch = - ApiDispatch { tx: commit_tx.clone(), notify_commit: commit_notify_tx.clone() }; - - let store = Store::new(pool.clone())?; - - pool.get()? - .build_transaction() - .run(|connection| connection.run_pending_migrations(MIGRATIONS).map(|_| ())) - .map_err(StoreError::DbMigration)?; - - let system_namespace_uuid = (SYSTEM_ID, Uuid::try_from(SYSTEM_UUID).unwrap()); - - // Append namespace bindings and system namespace - store.namespace_binding(system_namespace_uuid.0, system_namespace_uuid.1)?; - for ns in namespace_bindings { - info!( - "Binding namespace with external ID: {}, UUID: {}", - ns.external_id_part().as_str(), - ns.uuid_part() - ); - store.namespace_binding(ns.external_id_part().as_str(), ns.uuid_part().to_owned())? - } - - let reuse_reader = ledger.clone(); - - let last_seen_block = store.get_last_block_id(); - - let start_from_block = if let Ok(Some(start_from_block)) = last_seen_block { - FromBlock::BlockId(start_from_block) - } else { - FromBlock::First //Full catch up, as we have no last seen block - }; - - debug!(start_from_block = ?start_from_block, "Starting from block"); - - tokio::task::spawn(async move { - let mut api = Api:: { - submit_tx: commit_notify_tx.clone(), - signing, - ledger_writer: ledger, - store: store.clone(), - uuid_source: PhantomData, - }; - - loop { - let state_updates = reuse_reader.clone(); - - let state_updates = state_updates.state_updates(start_from_block, None).await; - - if let Err(e) = state_updates { - error!(subscribe_to_events = ?e); - tokio::time::sleep(Duration::from_secs(2)).await; - continue; - } - - let mut state_updates = state_updates.unwrap(); - - loop { - select! { - state = state_updates.next().fuse() =>{ - - match state { - None => { - debug!("Ledger reader stream ended"); - break; - } - // Ledger contradicted or error, so nothing to - // apply, but forward notification - Some((ChronicleEvent::Contradicted{contradiction,identity,..},tx,_block_id,_position, _span)) => { - commit_notify_tx.send(SubmissionStage::not_committed( - tx,contradiction, identity - )).ok(); - }, - // Successfully committed to ledger, so apply - // to db and broadcast notification to - // subscription subscribers - Some((ChronicleEvent::Committed{ref diff, ref identity, ..},tx,block_id,_position,_span )) => { - - debug!(diff = ?diff.summarize()); - trace!(delta = %serde_json::to_string_pretty(&diff.to_json().compact().await.unwrap()).unwrap()); - - api.sync( diff.clone().into(), &block_id,tx ) - .instrument(info_span!("Incoming confirmation", offset = ?block_id, tx = %tx)) - .await - .map_err(|e| { - error!(?e, "Api sync to confirmed commit"); - }).map(|_| commit_notify_tx.send(SubmissionStage::committed(Commit::new( - tx,block_id.to_string(), Box::new(diff.clone()) - ), identity.clone() )).ok()) - .ok(); - }, - } - }, - cmd = commit_rx.recv().fuse() => { - if let Some((command, reply)) = cmd { - - let result = api - .dispatch(command) - .await; - - reply - .send(result) - .await - .map_err(|e| { - warn!(?e, "Send reply to Api consumer failed"); - }) - .ok(); - } - } - complete => break - } - } - } - }); - - if let Some(interval) = liveness_check_interval { - debug!("Starting liveness depth charge task"); - - let depth_charge_api = dispatch.clone(); - - tokio::task::spawn(async move { - // Configure and install Prometheus exporter - install_prometheus_metrics_exporter(); - - loop { - tokio::time::sleep(std::time::Duration::from_secs(interval)).await; - let api = depth_charge_api.clone(); - - let start_time = Instant::now(); - - let response = api - .handle_depth_charge(system_namespace_uuid.0, &system_namespace_uuid.1) - .await; - - match response { - Ok(ApiResponse::DepthChargeSubmitted { tx_id }) => { - let mut tx_notifications = api.notify_commit.subscribe(); - - loop { - let stage = match tx_notifications.recv().await { - Ok(stage) => stage, - Err(e) => { - error!("Error receiving depth charge transaction notifications: {}", e); - continue; - }, - }; - - match stage { - SubmissionStage::Submitted(Ok(id)) => - if id == tx_id { - debug!("Depth charge operation submitted: {id}"); - continue; - }, - SubmissionStage::Submitted(Err(err)) => { - if err.tx_id() == &tx_id { - error!("Depth charge transaction rejected by Chronicle: {} {}", - err, - err.tx_id() - ); - break; - } - }, - SubmissionStage::Committed(commit, _) => { - if commit.tx_id == tx_id { - let end_time = Instant::now(); - let elapsed_time = end_time - start_time; - debug!( - "Depth charge transaction committed: {}", - commit.tx_id - ); - debug!( - "Depth charge round trip time: {:.2?}", - elapsed_time - ); - let hist = histogram!("depth_charge_round_trip",); - - hist.record(elapsed_time.as_millis() as f64); - - break; - } - }, - SubmissionStage::NotCommitted((id, contradiction, _)) => { - if id == tx_id { - error!("Depth charge transaction rejected by ledger: {id} {contradiction}"); - break; - } - }, - } - } - }, - Ok(res) => error!("Unexpected ApiResponse from depth charge: {res:?}"), - Err(e) => error!("ApiError submitting depth charge: {e}"), - } - } - }); - } - - Ok(dispatch) - } - - /// Notify after a successful submission, depending on the consistency requirement TODO: set in - /// the transaction - fn submit_blocking( - &mut self, - tx: ChronicleTransaction, - ) -> Result { - let (submission, _id) = futures::executor::block_on(self.ledger_writer.pre_submit(tx))?; - - let res = - futures::executor::block_on(self.ledger_writer.do_submit( - protocol_substrate_chronicle::protocol::WriteConsistency::Weak, - submission, - )); - match res { - Ok(tx_id) => { - self.submit_tx.send(SubmissionStage::submitted(&tx_id)).ok(); - Ok(tx_id) - }, - Err((e, id)) => { - // We need the cloneable SubmissionError wrapper here - let submission_error = SubmissionError::communication(&id, e.into()); - self.submit_tx.send(SubmissionStage::submitted_error(&submission_error)).ok(); - Err(submission_error.into()) - }, - } - } - - /// Generate and submit the signed identity to send to the Transaction Processor along with the - /// transactions to be applied - fn submit( - &mut self, - id: impl Into, - identity: AuthId, - to_apply: Vec, - ) -> Result { - let identity = identity.signed_identity(&self.signing)?; - let model = ProvModel::from_tx(&to_apply).map_err(ApiError::Contradiction)?; - let tx_id = self.submit_blocking(futures::executor::block_on( - ChronicleTransaction::new(&self.signing, identity, to_apply), - )?)?; - - Ok(ApiResponse::submission(id, model, tx_id)) - } - - /// Checks if ChronicleOperations resulting from Chronicle API calls will result in any changes - /// in state - /// - /// # Arguments - /// * `connection` - Connection to the Chronicle database - /// * `to_apply` - Chronicle operations resulting from an API call - #[instrument(skip(self, connection, to_apply))] - fn check_for_effects( - &mut self, - connection: &mut PgConnection, - to_apply: &Vec, - ) -> Result>, ApiError> { - debug!(checking_for_effects = to_apply.len()); - let mut model = ProvModel::default(); - let mut transactions = Vec::::with_capacity(to_apply.len()); - for op in to_apply { - let mut applied_model = match op { - ChronicleOperation::CreateNamespace(CreateNamespace { id, .. }) => { - let (namespace, _) = - self.ensure_namespace(connection, id.external_id_part())?; - model.namespace_context(&namespace); - model - }, - ChronicleOperation::AgentExists(AgentExists { ref namespace, ref id }) => - self.store.apply_prov_model_for_agent_id( - connection, - model, - id, - namespace.external_id_part(), - )?, - ChronicleOperation::ActivityExists(ActivityExists { ref namespace, ref id }) => - self.store.apply_prov_model_for_activity_id( - connection, - model, - id, - namespace.external_id_part(), - )?, - ChronicleOperation::EntityExists(EntityExists { ref namespace, ref id }) => - self.store.apply_prov_model_for_entity_id( - connection, - model, - id, - namespace.external_id_part(), - )?, - ChronicleOperation::ActivityUses(ActivityUses { - ref namespace, - ref id, - ref activity, - }) => self.store.prov_model_for_usage( - connection, - model, - id, - activity, - namespace.external_id_part(), - )?, - ChronicleOperation::SetAttributes(ref o) => match o { - SetAttributes::Activity { namespace, id, .. } => - self.store.apply_prov_model_for_activity_id( - connection, - model, - id, - namespace.external_id_part(), - )?, - SetAttributes::Agent { namespace, id, .. } => - self.store.apply_prov_model_for_agent_id( - connection, - model, - id, - namespace.external_id_part(), - )?, - SetAttributes::Entity { namespace, id, .. } => - self.store.apply_prov_model_for_entity_id( - connection, - model, - id, - namespace.external_id_part(), - )?, - }, - ChronicleOperation::StartActivity(StartActivity { namespace, id, .. }) => - self.store.apply_prov_model_for_activity_id( - connection, - model, - id, - namespace.external_id_part(), - )?, - ChronicleOperation::EndActivity(EndActivity { namespace, id, .. }) => - self.store.apply_prov_model_for_activity_id( - connection, - model, - id, - namespace.external_id_part(), - )?, - ChronicleOperation::WasInformedBy(WasInformedBy { - namespace, - activity, - informing_activity, - }) => { - let model = self.store.apply_prov_model_for_activity_id( - connection, - model, - activity, - namespace.external_id_part(), - )?; - self.store.apply_prov_model_for_activity_id( - connection, - model, - informing_activity, - namespace.external_id_part(), - )? - }, - ChronicleOperation::AgentActsOnBehalfOf(ActsOnBehalfOf { - activity_id, - responsible_id, - delegate_id, - namespace, - .. - }) => { - let model = self.store.apply_prov_model_for_agent_id( - connection, - model, - responsible_id, - namespace.external_id_part(), - )?; - let model = self.store.apply_prov_model_for_agent_id( - connection, - model, - delegate_id, - namespace.external_id_part(), - )?; - if let Some(id) = activity_id { - self.store.apply_prov_model_for_activity_id( - connection, - model, - id, - namespace.external_id_part(), - )? - } else { - model - } - }, - ChronicleOperation::WasAssociatedWith(WasAssociatedWith { - namespace, - activity_id, - agent_id, - .. - }) => { - let model = self.store.apply_prov_model_for_activity_id( - connection, - model, - activity_id, - namespace.external_id_part(), - )?; - - self.store.apply_prov_model_for_agent_id( - connection, - model, - agent_id, - namespace.external_id_part(), - )? - }, - ChronicleOperation::WasGeneratedBy(WasGeneratedBy { namespace, id, activity }) => { - let model = self.store.apply_prov_model_for_activity_id( - connection, - model, - activity, - namespace.external_id_part(), - )?; - - self.store.apply_prov_model_for_entity_id( - connection, - model, - id, - namespace.external_id_part(), - )? - }, - ChronicleOperation::EntityDerive(EntityDerive { - namespace, - id, - used_id, - activity_id, - .. - }) => { - let model = self.store.apply_prov_model_for_entity_id( - connection, - model, - id, - namespace.external_id_part(), - )?; - - let model = self.store.apply_prov_model_for_entity_id( - connection, - model, - used_id, - namespace.external_id_part(), - )?; - - if let Some(id) = activity_id { - self.store.apply_prov_model_for_activity_id( - connection, - model, - id, - namespace.external_id_part(), - )? - } else { - model - } - }, - ChronicleOperation::WasAttributedTo(WasAttributedTo { - namespace, - entity_id, - agent_id, - .. - }) => { - let model = self.store.apply_prov_model_for_entity_id( - connection, - model, - entity_id, - namespace.external_id_part(), - )?; - - self.store.apply_prov_model_for_agent_id( - connection, - model, - agent_id, - namespace.external_id_part(), - )? - }, - }; - let state = applied_model.clone(); - applied_model.apply(op)?; - if state != applied_model { - transactions.push(op.clone()); - } - - model = applied_model; - } - - if transactions.is_empty() { - Ok(None) - } else { - Ok(Some(transactions)) - } - } - - fn apply_effects_and_submit( - &mut self, - connection: &mut PgConnection, - id: impl Into, - identity: AuthId, - to_apply: Vec, - applying_new_namespace: bool, - ) -> Result { - if applying_new_namespace { - self.submit(id, identity, to_apply) - } else if let Some(to_apply) = self.check_for_effects(connection, &to_apply)? { - info!(sending_operations = to_apply.len()); - self.submit(id, identity, to_apply) - } else { - info!("API call will not result in any data changes"); - let model = ProvModel::from_tx(&to_apply)?; - Ok(ApiResponse::already_recorded(id, model)) - } - } - - /// Ensures that the named namespace exists, returns an existing namespace, and a vector - /// containing a `ChronicleTransaction` to create one if not present - /// - /// A namespace uri is of the form chronicle:ns:{external_id}:{uuid} - /// Namespaces must be globally unique, so are disambiguated by uuid but are locally referred to - /// by external_id only For coordination between chronicle nodes we also need a namespace - /// binding operation to tie the UUID from another instance to a external_id # Arguments - /// * `external_id` - an arbitrary namespace identifier - #[instrument(skip(self, connection))] - fn ensure_namespace( - &mut self, - connection: &mut PgConnection, - id: &ExternalId, - ) -> Result<(NamespaceId, Vec), ApiError> { - match self.store.namespace_by_external_id(connection, id) { - Ok((namespace_id, _)) => { - trace!(%id, "Namespace already exists."); - Ok((namespace_id, vec![])) - }, - Err(e) => { - debug!(error = %e, %id, "Namespace does not exist, creating."); - let uuid = Uuid::new_v4(); - let namespace_id = NamespaceId::from_external_id(id, uuid); - let create_namespace_op = - ChronicleOperation::CreateNamespace(CreateNamespace::new(namespace_id.clone())); - Ok((namespace_id, vec![create_namespace_op])) - }, - } - } - - /// Creates and submits a (ChronicleTransaction::GenerateEntity), and possibly - /// (ChronicleTransaction::Domaintype) if specified - /// - /// We use our local store for a best guess at the activity, either by external_id or the last - /// one started as a convenience for command line - #[instrument(skip(self))] - async fn activity_generate( - &self, - id: EntityId, - namespace: ExternalId, - activity_id: ActivityId, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let create = ChronicleOperation::WasGeneratedBy(WasGeneratedBy { - namespace, - id: id.clone(), - activity: activity_id, - }); - - to_apply.push(create); - - api.apply_effects_and_submit( - connection, - id, - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - /// Creates and submits a (ChronicleTransaction::ActivityUses), and possibly - /// (ChronicleTransaction::Domaintype) if specified We use our local store for a best guess at - /// the activity, either by name or the last one started as a convenience for command line - #[instrument(skip(self))] - async fn activity_use( - &self, - id: EntityId, - namespace: ExternalId, - activity_id: ActivityId, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let (id, to_apply) = { - let create = ChronicleOperation::ActivityUses(ActivityUses { - namespace, - id: id.clone(), - activity: activity_id, - }); - - to_apply.push(create); - - (id, to_apply) - }; - - api.apply_effects_and_submit( - connection, - id, - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - /// Creates and submits a (ChronicleTransaction::ActivityWasInformedBy) - /// - /// We use our local store for a best guess at the activity, either by external_id or the last - /// one started as a convenience for command line - #[instrument(skip(self))] - async fn activity_was_informed_by( - &self, - id: ActivityId, - namespace: ExternalId, - informing_activity_id: ActivityId, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let (id, to_apply) = { - let create = ChronicleOperation::WasInformedBy(WasInformedBy { - namespace, - activity: id.clone(), - informing_activity: informing_activity_id, - }); - - to_apply.push(create); - - (id, to_apply) - }; - - api.apply_effects_and_submit( - connection, - id, - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - /// Submits operations [`CreateEntity`], and [`SetAttributes::Entity`] - /// - /// We use our local store to see if the agent already exists, disambiguating the URI if so - #[instrument(skip(self))] - #[instrument(skip(self))] - async fn create_entity( - &self, - id: EntityId, - namespace_id: ExternalId, - attributes: Attributes, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace_id)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let create = ChronicleOperation::EntityExists(EntityExists { - namespace: namespace.clone(), - id: id.clone(), - }); - - to_apply.push(create); - - let set_type = ChronicleOperation::SetAttributes(SetAttributes::Entity { - id: id.clone(), - namespace, - attributes, - }); - - to_apply.push(set_type); - - api.apply_effects_and_submit( - connection, - id, - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - /// Submits operations [`CreateActivity`], and [`SetAttributes::Activity`] - /// - /// We use our local store to see if the activity already exists, disambiguating the URI if so - #[instrument(skip(self))] - async fn create_activity( - &self, - activity_id: ExternalId, - namespace_id: ExternalId, - attributes: Attributes, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace_id)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let create = ChronicleOperation::ActivityExists(ActivityExists { - namespace: namespace.clone(), - id: ActivityId::from_external_id(&activity_id), - }); - - to_apply.push(create); - - let set_type = ChronicleOperation::SetAttributes(SetAttributes::Activity { - id: ActivityId::from_external_id(&activity_id), - namespace, - attributes, - }); - - to_apply.push(set_type); - - api.apply_effects_and_submit( - connection, - ActivityId::from_external_id(&activity_id), - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - /// Submits operations [`CreateAgent`], and [`SetAttributes::Agent`] - /// - /// We use our local store to see if the agent already exists, disambiguating the URI if so - #[instrument(skip(self))] - async fn create_agent( - &self, - agent_id: ExternalId, - namespace: ExternalId, - attributes: Attributes, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let create = ChronicleOperation::AgentExists(AgentExists { - id: AgentId::from_external_id(&agent_id), - namespace: namespace.clone(), - }); - - to_apply.push(create); - - let id = AgentId::from_external_id(&agent_id); - let set_type = ChronicleOperation::SetAttributes(SetAttributes::Agent { - id: id.clone(), - namespace, - attributes, - }); - - to_apply.push(set_type); - - api.apply_effects_and_submit( - connection, - id, - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - /// Creates and submits a (ChronicleTransaction::CreateNamespace) if the external_id part does - /// not already exist in local storage - async fn create_namespace( - &self, - name: &ExternalId, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - let name = name.to_owned(); - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - connection.build_transaction().run(|connection| { - let (namespace, to_apply) = api.ensure_namespace(connection, &name)?; - - api.submit(namespace, identity, to_apply) - }) - }) - .await? - } - - #[instrument(skip(self))] - async fn depth_charge( - &self, - namespace: NamespaceId, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - let id = ActivityId::from_external_id(Uuid::new_v4().to_string()); - tokio::task::spawn_blocking(move || { - let to_apply = vec![ - ChronicleOperation::StartActivity(StartActivity { - namespace: namespace.clone(), - id: id.clone(), - time: Utc::now().into(), - }), - ChronicleOperation::EndActivity(EndActivity { - namespace, - id, - time: Utc::now().into(), - }), - ]; - api.submit_depth_charge(identity, to_apply) - }) - .await? - } - - fn submit_depth_charge( - &mut self, - identity: AuthId, - to_apply: Vec, - ) -> Result { - let identity = identity.signed_identity(&self.signing)?; - let tx_id = self.submit_blocking(futures::executor::block_on( - ChronicleTransaction::new(&self.signing, identity, to_apply), - )?)?; - Ok(ApiResponse::depth_charge_submission(tx_id)) - } - - #[instrument(skip(self))] - async fn dispatch(&mut self, command: (ApiCommand, AuthId)) -> Result { - match command { - (ApiCommand::DepthCharge(DepthChargeCommand { namespace }), identity) => - self.depth_charge(namespace, identity).await, - (ApiCommand::Import(ImportCommand { operations }), identity) => - self.submit_import_operations(identity, operations).await, - (ApiCommand::NameSpace(NamespaceCommand::Create { id }), identity) => - self.create_namespace(&id, identity).await, - (ApiCommand::Agent(AgentCommand::Create { id, namespace, attributes }), identity) => - self.create_agent(id, namespace, attributes, identity).await, - (ApiCommand::Agent(AgentCommand::UseInContext { id, namespace }), _identity) => - self.use_agent_in_cli_context(id, namespace).await, - ( - ApiCommand::Agent(AgentCommand::Delegate { - id, - delegate, - activity, - namespace, - role, - }), - identity, - ) => self.delegate(namespace, id, delegate, activity, role, identity).await, - ( - ApiCommand::Activity(ActivityCommand::Create { id, namespace, attributes }), - identity, - ) => self.create_activity(id, namespace, attributes, identity).await, - ( - ApiCommand::Activity(ActivityCommand::Instant { id, namespace, time, agent }), - identity, - ) => self.instant(id, namespace, time, agent, identity).await, - ( - ApiCommand::Activity(ActivityCommand::Start { id, namespace, time, agent }), - identity, - ) => self.start_activity(id, namespace, time, agent, identity).await, - ( - ApiCommand::Activity(ActivityCommand::End { id, namespace, time, agent }), - identity, - ) => self.end_activity(id, namespace, time, agent, identity).await, - (ApiCommand::Activity(ActivityCommand::Use { id, namespace, activity }), identity) => - self.activity_use(id, namespace, activity, identity).await, - ( - ApiCommand::Activity(ActivityCommand::WasInformedBy { - id, - namespace, - informing_activity, - }), - identity, - ) => self.activity_was_informed_by(id, namespace, informing_activity, identity).await, - ( - ApiCommand::Activity(ActivityCommand::Associate { - id, - namespace, - responsible, - role, - }), - identity, - ) => self.associate(namespace, responsible, id, role, identity).await, - ( - ApiCommand::Entity(EntityCommand::Attribute { id, namespace, responsible, role }), - identity, - ) => self.attribute(namespace, responsible, id, role, identity).await, - (ApiCommand::Entity(EntityCommand::Create { id, namespace, attributes }), identity) => - self.create_entity(EntityId::from_external_id(&id), namespace, attributes, identity) - .await, - ( - ApiCommand::Activity(ActivityCommand::Generate { id, namespace, activity }), - identity, - ) => self.activity_generate(id, namespace, activity, identity).await, - ( - ApiCommand::Entity(EntityCommand::Derive { - id, - namespace, - activity, - used_entity, - derivation, - }), - identity, - ) => - self.entity_derive(id, namespace, activity, used_entity, derivation, identity) - .await, - (ApiCommand::Query(query), _identity) => self.query(query).await, - } - } - - #[instrument(skip(self))] - async fn delegate( - &self, - namespace: ExternalId, - responsible_id: AgentId, - delegate_id: AgentId, - activity_id: Option, - role: Option, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let tx = ChronicleOperation::agent_acts_on_behalf_of( - namespace, - responsible_id.clone(), - delegate_id, - activity_id, - role, - ); - - to_apply.push(tx); - - api.apply_effects_and_submit( - connection, - responsible_id, - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - #[instrument(skip(self))] - async fn associate( - &self, - namespace: ExternalId, - responsible_id: AgentId, - activity_id: ActivityId, - role: Option, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let tx = ChronicleOperation::was_associated_with( - namespace, - activity_id, - responsible_id.clone(), - role, - ); - - to_apply.push(tx); - - api.apply_effects_and_submit( - connection, - responsible_id, - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - #[instrument(skip(self))] - async fn attribute( - &self, - namespace: ExternalId, - responsible_id: AgentId, - entity_id: EntityId, - role: Option, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let tx = ChronicleOperation::was_attributed_to( - namespace, - entity_id, - responsible_id.clone(), - role, - ); - - to_apply.push(tx); - - api.apply_effects_and_submit( - connection, - responsible_id, - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - #[instrument(skip(self))] - async fn entity_derive( - &self, - id: EntityId, - namespace: ExternalId, - activity_id: Option, - used_id: EntityId, - typ: DerivationType, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let tx = ChronicleOperation::EntityDerive(EntityDerive { - namespace, - id: id.clone(), - used_id: used_id.clone(), - activity_id: activity_id.clone(), - typ, - }); - - to_apply.push(tx); - - api.apply_effects_and_submit( - connection, - id, - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - async fn query(&self, query: QueryCommand) -> Result { - let api = self.clone(); - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - - let (id, _) = api - .store - .namespace_by_external_id(&mut connection, &ExternalId::from(&query.namespace))?; - Ok(ApiResponse::query_reply(api.store.prov_model_for_namespace(&mut connection, &id)?)) - }) - .await? - } - - async fn submit_import_operations( - &self, - identity: AuthId, - operations: Vec, - ) -> Result { - let mut api = self.clone(); - let identity = identity.signed_identity(&self.signing)?; - let model = ProvModel::from_tx(&operations)?; - let signer = self.signing.clone(); - tokio::task::spawn_blocking(move || { - // Check here to ensure that import operations result in data changes - let mut connection = api.store.connection()?; - connection.build_transaction().run(|connection| { - if let Some(operations_to_apply) = api.check_for_effects(connection, &operations)? { - tracing::trace!( - operations_to_apply = operations_to_apply.len(), - "Import operations submitted" - ); - let tx_id = api.submit_blocking(futures::executor::block_on( - ChronicleTransaction::new(&signer, identity, operations_to_apply), - )?)?; - Ok(ApiResponse::import_submitted(model, tx_id)) - } else { - info!("Import will not result in any data changes"); - Ok(ApiResponse::AlreadyRecordedAll) - } - }) - }) - .await? - } - - #[instrument(level = "trace", skip(self), ret(Debug))] - async fn sync( - &self, - prov: Box, - block_id: &BlockId, - tx_id: ChronicleTransactionId, - ) -> Result { - let api = self.clone(); - let block_id = *block_id; - tokio::task::spawn_blocking(move || { - api.store.apply_prov(&prov)?; - api.store.set_last_block_id(&block_id, tx_id)?; - - Ok(ApiResponse::Unit) - }) - .await? - } - - /// Creates and submits a (ChronicleTransaction::StartActivity) determining the appropriate - /// agent by external_id, or via [use_agent] context - #[instrument(skip(self))] - async fn instant( - &self, - id: ActivityId, - namespace: ExternalId, - time: Option>, - agent: Option, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let agent_id = { - if let Some(agent) = agent { - Some(agent) - } else { - api.store - .get_current_agent(connection) - .ok() - .map(|x| AgentId::from_external_id(x.external_id)) - } - }; - - let now = Utc::now(); - - to_apply.push(ChronicleOperation::StartActivity(StartActivity { - namespace: namespace.clone(), - id: id.clone(), - time: time.unwrap_or(now).into(), - })); - - to_apply.push(ChronicleOperation::EndActivity(EndActivity { - namespace: namespace.clone(), - id: id.clone(), - time: time.unwrap_or(now).into(), - })); - - if let Some(agent_id) = agent_id { - to_apply.push(ChronicleOperation::was_associated_with( - namespace, - id.clone(), - agent_id, - None, - )); - } - - api.apply_effects_and_submit( - connection, - id, - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - /// Creates and submits a (ChronicleTransaction::StartActivity), determining the appropriate - /// agent by name, or via [use_agent] context - #[instrument(skip(self))] - async fn start_activity( - &self, - id: ActivityId, - namespace: ExternalId, - time: Option>, - agent: Option, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let agent_id = { - if let Some(agent) = agent { - Some(agent) - } else { - api.store - .get_current_agent(connection) - .ok() - .map(|x| AgentId::from_external_id(x.external_id)) - } - }; - - to_apply.push(ChronicleOperation::StartActivity(StartActivity { - namespace: namespace.clone(), - id: id.clone(), - time: time.unwrap_or_else(Utc::now).into(), - })); - - if let Some(agent_id) = agent_id { - to_apply.push(ChronicleOperation::was_associated_with( - namespace, - id.clone(), - agent_id, - None, - )); - } - - api.apply_effects_and_submit( - connection, - id, - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - /// Creates and submits a (ChronicleTransaction::EndActivity), determining the appropriate agent - /// by name or via [use_agent] context - #[instrument(skip(self))] - async fn end_activity( - &self, - id: ActivityId, - namespace: ExternalId, - time: Option>, - agent: Option, - identity: AuthId, - ) -> Result { - let mut api = self.clone(); - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - connection.build_transaction().run(|connection| { - let (namespace, mut to_apply) = api.ensure_namespace(connection, &namespace)?; - - let applying_new_namespace = !to_apply.is_empty(); - - let agent_id = { - if let Some(agent) = agent { - Some(agent) - } else { - api.store - .get_current_agent(connection) - .ok() - .map(|x| AgentId::from_external_id(x.external_id)) - } - }; - - to_apply.push(ChronicleOperation::EndActivity(EndActivity { - namespace: namespace.clone(), - id: id.clone(), - time: time.unwrap_or_else(Utc::now).into(), - })); - - if let Some(agent_id) = agent_id { - to_apply.push(ChronicleOperation::was_associated_with( - namespace, - id.clone(), - agent_id, - None, - )); - } - - api.apply_effects_and_submit( - connection, - id, - identity, - to_apply, - applying_new_namespace, - ) - }) - }) - .await? - } - - #[instrument(skip(self))] - async fn use_agent_in_cli_context( - &self, - id: AgentId, - namespace: ExternalId, - ) -> Result { - let api = self.clone(); - tokio::task::spawn_blocking(move || { - let mut connection = api.store.connection()?; - - connection.build_transaction().run(|connection| { - api.store.use_agent(connection, id.external_id_part(), &namespace) - })?; - - Ok(ApiResponse::Unit) - }) - .await? - } + fn signed_identity( + &self, + store: &S, + ) -> Result { + let signable = self.to_string(); + let signature = futures::executor::block_on(store.chronicle_sign(signable.as_bytes())) + .map_err(|e| IdentityError::Signing(e.into()))?; + let public_key = futures::executor::block_on(store.chronicle_verifying()) + .map_err(|e| IdentityError::Signing(e.into()))?; + + Ok(SignedIdentity { + identity: signable, + signature: signature.into(), + verifying_key: Some(public_key.to_bytes().to_vec()), + }) + } } diff --git a/crates/chronicle-arrow/Cargo.toml b/crates/chronicle-arrow/Cargo.toml index 56a051f94..999ec2e17 100644 --- a/crates/chronicle-arrow/Cargo.toml +++ b/crates/chronicle-arrow/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "chronicle-arrow" +name = "chronicle-arrow" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -23,30 +23,30 @@ serde = { workspace = true } serde_json = { workspace = true } thiserror = { workspace = true } tokio = { version = "^1", default-features = false, features = [ - "macros", - "rt", - "rt-multi-thread", + "macros", + "rt", + "rt-multi-thread", ] } tonic = { version = "0.10.2", default-features = false, features = [ - "transport", - "codegen", - "prost", + "transport", + "codegen", + "prost", ] } tracing = { workspace = true } uuid = { workspace = true } #local dependencies -api = { path = "../api" } +api = { path = "../api" } chronicle-persistence = { path = "../chronicle-persistence" } -common = { path = "../common", features = ["std"] } +common = { path = "../common", features = ["std"] } [dev-dependencies] -arrow-json = { version = "50" } -chronicle-telemetry = { path = "../chronicle-telemetry" } +arrow-json = { version = "50" } +chronicle-telemetry = { path = "../chronicle-telemetry" } chronicle-test-infrastructure = { path = "../chronicle-test-infrastructure" } -insta = { workspace = true, features = ["toml"] } -portpicker = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde_arrow = { version = "*", features = ["arrow-50"] } +insta = { workspace = true, features = ["toml"] } +portpicker = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_arrow = { version = "*", features = ["arrow-50"] } diff --git a/crates/chronicle-arrow/src/lib.rs b/crates/chronicle-arrow/src/lib.rs index 7755605ef..8eb9f2c06 100644 --- a/crates/chronicle-arrow/src/lib.rs +++ b/crates/chronicle-arrow/src/lib.rs @@ -1,640 +1,633 @@ -mod meta; -mod operations; -mod peekablestream; -mod query; -use api::chronicle_graphql::EndpointSecurityConfiguration; -use lazy_static::lazy_static; -use tokio::sync::broadcast; - -use api::{ApiDispatch, ApiError}; - -use arrow_flight::decode::FlightRecordBatchStream; +use std::{sync::Arc, vec::Vec}; +use std::net::SocketAddr; use arrow_flight::{ - flight_service_server::FlightService, Action, ActionType, Criteria, Empty, FlightData, + Action, ActionType, Criteria, Empty, flight_service_server::FlightService, FlightData, FlightDescriptor, FlightInfo, HandshakeRequest, HandshakeResponse, PutResult, SchemaResult, Ticket, }; - use arrow_flight::{FlightEndpoint, IpcMessage, SchemaAsIpc}; - +use arrow_flight::decode::FlightRecordBatchStream; use arrow_schema::ArrowError; - -use common::{domain::TypeName, prov::ExternalIdPart}; - -use common::prov::{DomaintypeId, ParseIriError}; -use diesel::{r2d2::ConnectionManager, PgConnection}; - +use diesel::{PgConnection, r2d2::ConnectionManager}; use futures::{ future::join_all, - stream::{self, BoxStream}, - FutureExt, StreamExt, -}; - -use meta::{DomainTypeMeta, Term}; -use query::{ - activity_count_by_type, agent_count_by_type, entity_count_by_type, EntityAndReferences, + FutureExt, + stream::{self, BoxStream}, StreamExt, }; +use lazy_static::lazy_static; use r2d2::Pool; use serde::Serialize; -use std::net::SocketAddr; +use thiserror::Error; +use tokio::sync::broadcast; use tokio::task::spawn_blocking; - -use std::{sync::Arc, vec::Vec}; -use tonic::{transport::Server, Request, Response, Status, Streaming}; +use tonic::{Request, Response, Status, Streaming, transport::Server}; use tracing::{info, instrument}; -use thiserror::Error; +use api::ApiDispatch; +use api::ApiError; +use api::chronicle_graphql::EndpointSecurityConfiguration; +use common::{domain::TypeName, prov::ExternalIdPart}; +use common::prov::{DomaintypeId, ParseIriError}; +use meta::{DomainTypeMeta, Term}; +use query::{ + activity_count_by_type, agent_count_by_type, entity_count_by_type, EntityAndReferences, +}; use crate::{ meta::get_domain_type_meta_from_cache, operations::{batch_to_flight_data, process_record_batch}, peekablestream::PeekableFlightDataStream, query::{ - load_activities_by_type, load_agents_by_type, load_entities_by_type, ActivityAndReferences, - AgentAndReferences, + ActivityAndReferences, AgentAndReferences, load_activities_by_type, load_agents_by_type, + load_entities_by_type, }, }; +mod meta; +mod operations; +mod peekablestream; +mod query; + #[derive(Error, Debug)] pub enum ChronicleArrowError { - #[error("Arrow error: {0}")] - ArrowSchemaError( - #[from] - #[source] - ArrowError, - ), - #[error("Missing schema for the requested entity or activity")] - MissingSchemaError, - - #[error("Schema field not found: {0}")] - SchemaFieldNotFound(String), - - #[error("Missing column: {0}")] - MissingColumn(String), - - #[error("Column type mismatch for: {0}")] - ColumnTypeMismatch(String), - - #[error("Invalid value: {0}")] - InvalidValue(String), - - #[error("Invalid descriptor path")] - InvalidDescriptorPath, - - #[error("Metadata not found")] - MetadataNotFound, - - #[error("API error: {0}")] - ApiError( - #[from] - #[source] - ApiError, - ), - #[error("Parse IRI : {0}")] - IriError( - #[from] - #[source] - ParseIriError, - ), - - #[error("Database connection pool error: {0}")] - PoolError( - #[from] - #[source] - r2d2::Error, - ), - - #[error("Diesel error: {0}")] - DieselError( - #[from] - #[source] - diesel::result::Error, - ), - - #[error("Serde JSON error: {0}")] - SerdeJsonError( - #[from] - #[source] - serde_json::Error, - ), - - #[error("Join error: {0}")] - JoinError( - #[from] - #[source] - tokio::task::JoinError, - ), - - #[error("UUID parse error: {0}")] - UuidParseError( - #[from] - #[source] - uuid::Error, - ), + #[error("Arrow error: {0}")] + ArrowSchemaError( + #[from] + #[source] + ArrowError, + ), + #[error("Missing schema for the requested entity or activity")] + MissingSchemaError, + + #[error("Schema field not found: {0}")] + SchemaFieldNotFound(String), + + #[error("Missing column: {0}")] + MissingColumn(String), + + #[error("Column type mismatch for: {0}")] + ColumnTypeMismatch(String), + + #[error("Invalid value: {0}")] + InvalidValue(String), + + #[error("Invalid descriptor path")] + InvalidDescriptorPath, + + #[error("Metadata not found")] + MetadataNotFound, + + #[error("API error: {0}")] + ApiError( + #[from] + #[source] + ApiError, + ), + #[error("Parse IRI : {0}")] + IriError( + #[from] + #[source] + ParseIriError, + ), + + #[error("Database connection pool error: {0}")] + PoolError( + #[from] + #[source] + r2d2::Error, + ), + + #[error("Diesel error: {0}")] + DieselError( + #[from] + #[source] + diesel::result::Error, + ), + + #[error("Serde JSON error: {0}")] + SerdeJsonError( + #[from] + #[source] + serde_json::Error, + ), + + #[error("Join error: {0}")] + JoinError( + #[from] + #[source] + tokio::task::JoinError, + ), + + #[error("UUID parse error: {0}")] + UuidParseError( + #[from] + #[source] + uuid::Error, + ), } #[instrument(skip(pool, term, domaintype))] pub async fn calculate_count_by_metadata_term( - pool: &Pool>, - term: &Term, - domaintype: Option, + pool: &Pool>, + term: &Term, + domaintype: Option, ) -> Result { - let pool = pool.clone(); - match term { - Term::Entity => - spawn_blocking(move || { - entity_count_by_type( - &pool, - domaintype.map(|x| x.to_string()).iter().map(|s| s.as_str()).collect(), - ) - }) - .await, - Term::Agent => - spawn_blocking(move || { - agent_count_by_type( - &pool, - domaintype.map(|x| x.to_string()).iter().map(|s| s.as_str()).collect(), - ) - }) - .await, - Term::Activity => - spawn_blocking(move || { - activity_count_by_type( - &pool, - domaintype.map(|x| x.to_string()).iter().map(|s| s.as_str()).collect(), - ) - }) - .await, - _ => Ok(Ok(0)), - } - .map_err(|e| Status::from_error(e.into())) - .and_then(|res| res.map_err(|e| Status::from_error(e.into()))) + let pool = pool.clone(); + match term { + Term::Entity => + spawn_blocking(move || { + entity_count_by_type( + &pool, + domaintype.map(|x| x.to_string()).iter().map(|s| s.as_str()).collect(), + ) + }) + .await, + Term::Agent => + spawn_blocking(move || { + agent_count_by_type( + &pool, + domaintype.map(|x| x.to_string()).iter().map(|s| s.as_str()).collect(), + ) + }) + .await, + Term::Activity => + spawn_blocking(move || { + activity_count_by_type( + &pool, + domaintype.map(|x| x.to_string()).iter().map(|s| s.as_str()).collect(), + ) + }) + .await, + _ => Ok(Ok(0)), + } + .map_err(|e| Status::from_error(e.into())) + .and_then(|res| res.map_err(|e| Status::from_error(e.into()))) } async fn create_flight_info_for_type( - pool: Arc>>, - domain_items: Vec, - term: Term, - record_batch_size: usize, + pool: Arc>>, + domain_items: Vec, + term: Term, + record_batch_size: usize, ) -> BoxStream<'static, Result> { - stream::iter(domain_items.into_iter().map(|item| Ok::<_, tonic::Status>(item))) - .then(move |item| { - let pool = pool.clone(); - async move { - let item = item?; // Handle the Result from the iterator - let descriptor_path = vec![term.to_string(), item.as_type_name()]; - let metadata = - get_domain_type_meta_from_cache(&descriptor_path).ok_or_else(|| { - Status::from_error(Box::new(ChronicleArrowError::MissingSchemaError)) - })?; - - let count = calculate_count_by_metadata_term( - &pool, - &term, - Some(item.as_type_name().to_string()), - ) - .await?; - - let tickets = (0..count) - .step_by(record_batch_size as _) - .map(|start| { - let end = std::cmp::min(start as usize + record_batch_size, count as usize); - - let ticket_metadata = ChronicleTicket::new( - term, - metadata.typ.as_ref().map(|x| x.as_domain_type_id()), - start as _, - (end - start as usize) as _, - ); - Ticket::try_from(ticket_metadata) - .map_err(|e| Status::from_error(Box::new(ChronicleArrowError::from(e)))) - }) - .collect::, _>>()?; - - let mut flight_info = FlightInfo::new(); - - for ticket in tickets { - flight_info = - flight_info.with_endpoint(FlightEndpoint::new().with_ticket(ticket)); - } - - Ok(flight_info - .with_descriptor(FlightDescriptor::new_path(descriptor_path)) - .try_with_schema(&metadata.schema) - .map_err(|e| Status::from_error(Box::new(ChronicleArrowError::from(e))))? - .with_total_records(count)) - } - }) - .boxed() + stream::iter(domain_items.into_iter().map(|item| Ok::<_, tonic::Status>(item))) + .then(move |item| { + let pool = pool.clone(); + async move { + let item = item?; // Handle the Result from the iterator + let descriptor_path = vec![term.to_string(), item.as_type_name()]; + let metadata = + get_domain_type_meta_from_cache(&descriptor_path).ok_or_else(|| { + Status::from_error(Box::new(ChronicleArrowError::MissingSchemaError)) + })?; + + let count = calculate_count_by_metadata_term( + &pool, + &term, + Some(item.as_type_name().to_string()), + ) + .await?; + + let tickets = (0..count) + .step_by(record_batch_size as _) + .map(|start| { + let end = std::cmp::min(start as usize + record_batch_size, count as usize); + + let ticket_metadata = ChronicleTicket::new( + term, + metadata.typ.as_ref().map(|x| x.as_domain_type_id()), + start as _, + (end - start as usize) as _, + ); + Ticket::try_from(ticket_metadata) + .map_err(|e| Status::from_error(Box::new(ChronicleArrowError::from(e)))) + }) + .collect::, _>>()?; + + let mut flight_info = FlightInfo::new(); + + for ticket in tickets { + flight_info = + flight_info.with_endpoint(FlightEndpoint::new().with_ticket(ticket)); + } + + Ok(flight_info + .with_descriptor(FlightDescriptor::new_path(descriptor_path)) + .try_with_schema(&metadata.schema) + .map_err(|e| Status::from_error(Box::new(ChronicleArrowError::from(e))))? + .with_total_records(count)) + } + }) + .boxed() } #[derive(Clone)] pub struct FlightServiceImpl { - domain: common::domain::ChronicleDomainDef, - pool: r2d2::Pool>, - api: ApiDispatch, - record_batch_size: usize, - security: EndpointSecurityConfiguration, + domain: common::domain::ChronicleDomainDef, + pool: r2d2::Pool>, + api: ApiDispatch, + record_batch_size: usize, + security: EndpointSecurityConfiguration, } impl FlightServiceImpl { - pub fn new( - domain: &common::domain::ChronicleDomainDef, - pool: &r2d2::Pool>, - api: &ApiDispatch, - security: EndpointSecurityConfiguration, - record_batch_size: usize, - ) -> Self { - Self { - domain: domain.clone(), - pool: pool.clone(), - api: api.clone(), - security, - record_batch_size, - } - } + pub fn new( + domain: &common::domain::ChronicleDomainDef, + pool: &r2d2::Pool>, + api: &ApiDispatch, + security: EndpointSecurityConfiguration, + record_batch_size: usize, + ) -> Self { + Self { + domain: domain.clone(), + pool: pool.clone(), + api: api.clone(), + security, + record_batch_size, + } + } } #[derive(Debug, Serialize, serde::Deserialize)] struct ChronicleTicket { - term: Term, - descriptor_path: Vec, - typ: Option, - start: u64, - count: u64, + term: Term, + descriptor_path: Vec, + typ: Option, + start: u64, + count: u64, } impl ChronicleTicket { - pub fn new(term: Term, typ: Option, start: u64, count: u64) -> Self { - Self { - term, - descriptor_path: vec![ - term.to_string(), - typ.as_ref() - .map(|x| x.external_id_part().to_string()) - .unwrap_or_else(|| format!("Prov{}", term)), - ], - typ, - start, - count, - } - } - - pub fn descriptor_path(&self) -> &Vec { - &self.descriptor_path - } + pub fn new(term: Term, typ: Option, start: u64, count: u64) -> Self { + Self { + term, + descriptor_path: vec![ + term.to_string(), + typ.as_ref() + .map(|x| x.external_id_part().to_string()) + .unwrap_or_else(|| format!("Prov{}", term)), + ], + typ, + start, + count, + } + } + + pub fn descriptor_path(&self) -> &Vec { + &self.descriptor_path + } } impl TryFrom for Ticket { - type Error = serde_json::Error; + type Error = serde_json::Error; - fn try_from(ticket: ChronicleTicket) -> Result { - let ticket_bytes = serde_json::to_vec(&ticket)?; - Ok(Ticket { ticket: ticket_bytes.into() }) - } + fn try_from(ticket: ChronicleTicket) -> Result { + let ticket_bytes = serde_json::to_vec(&ticket)?; + Ok(Ticket { ticket: ticket_bytes.into() }) + } } impl TryFrom for ChronicleTicket { - type Error = serde_json::Error; + type Error = serde_json::Error; - fn try_from(ticket: Ticket) -> Result { - let ticket_data = ticket.ticket.to_vec(); - serde_json::from_slice(&ticket_data) - } + fn try_from(ticket: Ticket) -> Result { + let ticket_data = ticket.ticket.to_vec(); + serde_json::from_slice(&ticket_data) + } } fn parse_flight_descriptor_path(descriptor: &FlightDescriptor) -> Result<(Term, String), Status> { - let path = &descriptor.path; - if path.is_empty() { - return Err(Status::invalid_argument("FlightDescriptor path is empty")); - } + let path = &descriptor.path; + if path.is_empty() { + return Err(Status::invalid_argument("FlightDescriptor path is empty")); + } - let term = path[0] - .parse::() - .map_err(|_| Status::invalid_argument("First element of the path must be a valid Term"))?; + let term = path[0] + .parse::() + .map_err(|_| Status::invalid_argument("First element of the path must be a valid Term"))?; - Ok((term, path[1].to_string())) + Ok((term, path[1].to_string())) } #[tonic::async_trait] impl FlightService for FlightServiceImpl { - type DoActionStream = BoxStream<'static, Result>; - type DoExchangeStream = BoxStream<'static, Result>; - type DoGetStream = BoxStream<'static, Result>; - type DoPutStream = BoxStream<'static, Result>; - type HandshakeStream = BoxStream<'static, Result>; - type ListActionsStream = BoxStream<'static, Result>; - type ListFlightsStream = BoxStream<'static, Result>; - - async fn handshake( - &self, - _request: Request>, - ) -> Result, Status> { - Ok(Response::new(Box::pin(futures::stream::empty()) as Self::HandshakeStream)) - } - - #[instrument(skip(self, _request))] - async fn list_flights( - &self, - _request: Request, - ) -> Result, Status> { - let entity_flights_stream = create_flight_info_for_type( - Arc::new(self.pool.clone()), - self.domain.entities.to_vec(), - Term::Entity, - self.record_batch_size, - ) - .await; - let activities_flights_stream = create_flight_info_for_type( - Arc::new(self.pool.clone()), - self.domain.activities.to_vec(), - Term::Activity, - self.record_batch_size, - ) - .await; - let agents_flights_stream = create_flight_info_for_type( - Arc::new(self.pool.clone()), - self.domain.agents.to_vec(), - Term::Agent, - self.record_batch_size, - ) - .await; - - let combined_stream = futures::stream::select_all(vec![ - entity_flights_stream, - activities_flights_stream, - agents_flights_stream, - ]) - .boxed(); - - Ok(Response::new(combined_stream as Self::ListFlightsStream)) - } - - #[instrument(skip(self, request))] - async fn get_flight_info( - &self, - request: Request, - ) -> Result, Status> { - let descriptor = request.into_inner(); - - let (term, type_name) = parse_flight_descriptor_path(&descriptor)?; - - let mut flight_info_stream = match term { - Term::Entity => { - let definition = self - .domain - .entities - .iter() - .find(|&item| item.as_type_name() == type_name) - .ok_or_else(|| { - Status::not_found(format!( - "Definition not found for term: {:?}, type_name: {}", - term, type_name - )) - })?; - create_flight_info_for_type( - Arc::new(self.pool.clone()), - vec![definition.clone()], - term, - self.record_batch_size, - ) - .boxed() - }, - Term::Activity => { - let definition = self - .domain - .activities - .iter() - .find(|&item| item.as_type_name() == type_name) - .ok_or_else(|| { - Status::not_found(format!( - "Definition not found for term: {:?}, type_name: {}", - term, type_name - )) - })?; - create_flight_info_for_type( - Arc::new(self.pool.clone()), - vec![definition.clone()], - term, - self.record_batch_size, - ) - .boxed() - }, - Term::Agent => { - let definition = self - .domain - .agents - .iter() - .find(|&item| item.as_type_name() == type_name) - .ok_or_else(|| { - Status::not_found(format!( - "Definition not found for term: {:?}, type_name: {}", - term, type_name - )) - })?; - create_flight_info_for_type( - Arc::new(self.pool.clone()), - vec![definition.clone()], - term, - self.record_batch_size, - ) - .boxed() - }, - _ => - return Err(Status::not_found(format!( - "Definition not found for term: {:?}, type_name: {}", - term, type_name - ))), - } - .await; - - let flight_info = flight_info_stream - .next() - .await - .ok_or(Status::not_found("No flight info for descriptor"))? - .map_err(|e| Status::from_error(e.into()))?; - - Ok(Response::new(flight_info)) - } - - #[instrument(skip(self, request))] - async fn get_schema( - &self, - request: Request, - ) -> Result, Status> { - let descriptor = request.into_inner(); - - let schema = get_domain_type_meta_from_cache(&descriptor.path) - .ok_or_else(|| ChronicleArrowError::MissingSchemaError) - .map_err(|e| Status::internal(format!("Failed to get cached schema: {}", e)))?; - - let options = arrow_ipc::writer::IpcWriteOptions::default(); - let ipc_message_result = SchemaAsIpc::new(&schema.schema, &options).try_into(); - match ipc_message_result { - Ok(IpcMessage(schema)) => Ok(Response::new(SchemaResult { schema })), - Err(e) => - Err(Status::internal(format!("Failed to convert schema to IPC message: {}", e))), - } - } - - #[instrument(skip(self))] - async fn do_get( - &self, - request: Request, - ) -> Result, Status> { - let ticket = request.into_inner(); - let ticket: ChronicleTicket = ticket - .try_into() - .map_err(|e| Status::from_error(Box::new(ChronicleArrowError::from(e))))?; - - let meta = get_domain_type_meta_from_cache(&ticket.descriptor_path) - .ok_or(Status::from_error(Box::new(ChronicleArrowError::InvalidDescriptorPath)))?; - - tracing::debug!(ticket = ?ticket); - - let terms_result = match ticket.term { - Term::Entity => { - let pool = self.pool.clone(); - let meta_clone = meta.clone(); - let result = tokio::task::spawn_blocking(move || { - load_entities_by_type( - &pool, - &ticket.typ, - &meta_clone.attributes, - ticket.start, - ticket.count, - ) - }) - .await - .map_err(|e| Status::from_error(Box::new(ChronicleArrowError::from(e))))? - .map_err(|e| Status::from_error(Box::new(e)))?; - - let (entities, _returned_records, _total_records) = result; - - EntityAndReferences::to_record_batch(entities, &meta).map_err(|e| { - Status::internal(format!("Failed to convert to record batch: {}", e)) - })? - }, - Term::Activity => { - let pool = self.pool.clone(); - let result = tokio::task::spawn_blocking(move || { - load_activities_by_type(&pool, &ticket.typ, ticket.start, ticket.count) - }) - .await - .map_err(|e| Status::from_error(Box::new(ChronicleArrowError::from(e))))? - .map_err(|e| Status::from_error(Box::new(e)))?; - - let (activities, _returned_records, _total_records) = result; - - ActivityAndReferences::to_record_batch(activities, &meta).map_err(|e| { - Status::internal(format!("Failed to convert to record batch: {}", e)) - })? - }, - Term::Agent => { - let pool = self.pool.clone(); - let result = tokio::task::spawn_blocking(move || { - load_agents_by_type(&pool, &ticket.typ, ticket.start, ticket.count) - }) - .await - .map_err(|e| Status::from_error(Box::new(ChronicleArrowError::from(e))))? - .map_err(|e| Status::from_error(Box::new(e)))?; - - let (agents, _returned_records, _total_records) = result; - - AgentAndReferences::to_record_batch(agents, &meta).map_err(|e| { - Status::internal(format!("Failed to convert to record batch: {}", e)) - })? - }, - Term::Namespace => { - tracing::error!("Attempted to put namespaces, which is not supported."); - return Err(Status::internal("Cannot put namespaces")); - }, - }; - - let flight_data_result = batch_to_flight_data( - &FlightDescriptor::new_path(ticket.descriptor_path), - &meta, - terms_result, - ); - - match flight_data_result { - Ok(flight_data) => { - let stream = futures::stream::iter(flight_data.into_iter().map(Ok)).boxed(); - Ok(Response::new(stream)) - }, - Err(e) => Err(Status::internal(e.to_string())), - } - } - - #[instrument(skip(self, request))] - async fn do_put( - &self, - request: Request>, - ) -> Result, Status> { - let mut stream = request.map(PeekableFlightDataStream::new).into_inner(); - let first_item = stream.peek().await; - - let flight_descriptor = match &first_item { - Some(Ok(flight_data)) => match flight_data.flight_descriptor.clone() { - Some(descriptor) => descriptor, - None => return Err(Status::invalid_argument("Flight data has no descriptor")), - }, - Some(Err(e)) => - return Err(Status::internal(format!("Failed to get first item from stream: {}", e))), - None => { - return Err(Status::invalid_argument("Stream is empty")); - }, - }; - - let filtered_stream = stream.filter_map(|item| async move { - match item { - Ok(flight_data) => { - tracing::trace!("Processing flight data item {:?}", flight_data); - Some(Ok(flight_data)) - }, - Err(e) => { - tracing::error!(error = %e, "Error processing stream item."); - None - }, - } - }); - - let mut decoder = FlightRecordBatchStream::new_from_flight_data(filtered_stream); - while let Some(batch) = decoder.next().await { - let batch = batch?; - tracing::debug!("Processing batch of: {:?}", batch.num_rows()); - process_record_batch(&flight_descriptor.path, batch, &self.api) - .await - .map_err(|e| Status::from_error(e.into()))?; - } - Ok(Response::new(Box::pin(stream::empty()) as Self::DoPutStream)) - } - - #[tracing::instrument(skip(self, _request))] - async fn do_action( - &self, - _request: Request, - ) -> Result, Status> { - tracing::info!("No actions available, returning empty stream."); - Ok(Response::new(Box::pin(stream::empty()))) - } - - #[tracing::instrument(skip(self, _request))] - async fn list_actions( - &self, - _request: Request, - ) -> Result, Status> { - tracing::info!("No actions available."); - Ok(Response::new(Box::pin(stream::empty()))) - } - - async fn do_exchange( - &self, - _request: Request>, - ) -> Result, Status> { - Err(Status::unimplemented("Implement do_exchange")) - } + type DoActionStream = BoxStream<'static, Result>; + type DoExchangeStream = BoxStream<'static, Result>; + type DoGetStream = BoxStream<'static, Result>; + type DoPutStream = BoxStream<'static, Result>; + type HandshakeStream = BoxStream<'static, Result>; + type ListActionsStream = BoxStream<'static, Result>; + type ListFlightsStream = BoxStream<'static, Result>; + + async fn handshake( + &self, + _request: Request>, + ) -> Result, Status> { + Ok(Response::new(Box::pin(futures::stream::empty()) as Self::HandshakeStream)) + } + + #[instrument(skip(self, _request))] + async fn list_flights( + &self, + _request: Request, + ) -> Result, Status> { + let entity_flights_stream = create_flight_info_for_type( + Arc::new(self.pool.clone()), + self.domain.entities.to_vec(), + Term::Entity, + self.record_batch_size, + ) + .await; + let activities_flights_stream = create_flight_info_for_type( + Arc::new(self.pool.clone()), + self.domain.activities.to_vec(), + Term::Activity, + self.record_batch_size, + ) + .await; + let agents_flights_stream = create_flight_info_for_type( + Arc::new(self.pool.clone()), + self.domain.agents.to_vec(), + Term::Agent, + self.record_batch_size, + ) + .await; + + let combined_stream = futures::stream::select_all(vec![ + entity_flights_stream, + activities_flights_stream, + agents_flights_stream, + ]) + .boxed(); + + Ok(Response::new(combined_stream as Self::ListFlightsStream)) + } + + #[instrument(skip(self, request))] + async fn get_flight_info( + &self, + request: Request, + ) -> Result, Status> { + let descriptor = request.into_inner(); + + let (term, type_name) = parse_flight_descriptor_path(&descriptor)?; + + let mut flight_info_stream = match term { + Term::Entity => { + let definition = self + .domain + .entities + .iter() + .find(|&item| item.as_type_name() == type_name) + .ok_or_else(|| { + Status::not_found(format!( + "Definition not found for term: {:?}, type_name: {}", + term, type_name + )) + })?; + create_flight_info_for_type( + Arc::new(self.pool.clone()), + vec![definition.clone()], + term, + self.record_batch_size, + ) + .boxed() + } + Term::Activity => { + let definition = self + .domain + .activities + .iter() + .find(|&item| item.as_type_name() == type_name) + .ok_or_else(|| { + Status::not_found(format!( + "Definition not found for term: {:?}, type_name: {}", + term, type_name + )) + })?; + create_flight_info_for_type( + Arc::new(self.pool.clone()), + vec![definition.clone()], + term, + self.record_batch_size, + ) + .boxed() + } + Term::Agent => { + let definition = self + .domain + .agents + .iter() + .find(|&item| item.as_type_name() == type_name) + .ok_or_else(|| { + Status::not_found(format!( + "Definition not found for term: {:?}, type_name: {}", + term, type_name + )) + })?; + create_flight_info_for_type( + Arc::new(self.pool.clone()), + vec![definition.clone()], + term, + self.record_batch_size, + ) + .boxed() + } + _ => + return Err(Status::not_found(format!( + "Definition not found for term: {:?}, type_name: {}", + term, type_name + ))), + } + .await; + + let flight_info = flight_info_stream + .next() + .await + .ok_or(Status::not_found("No flight info for descriptor"))? + .map_err(|e| Status::from_error(e.into()))?; + + Ok(Response::new(flight_info)) + } + + #[instrument(skip(self, request))] + async fn get_schema( + &self, + request: Request, + ) -> Result, Status> { + let descriptor = request.into_inner(); + + let schema = get_domain_type_meta_from_cache(&descriptor.path) + .ok_or_else(|| ChronicleArrowError::MissingSchemaError) + .map_err(|e| Status::internal(format!("Failed to get cached schema: {}", e)))?; + + let options = arrow_ipc::writer::IpcWriteOptions::default(); + let ipc_message_result = SchemaAsIpc::new(&schema.schema, &options).try_into(); + match ipc_message_result { + Ok(IpcMessage(schema)) => Ok(Response::new(SchemaResult { schema })), + Err(e) => + Err(Status::internal(format!("Failed to convert schema to IPC message: {}", e))), + } + } + + #[instrument(skip(self))] + async fn do_get( + &self, + request: Request, + ) -> Result, Status> { + let ticket = request.into_inner(); + let ticket: ChronicleTicket = ticket + .try_into() + .map_err(|e| Status::from_error(Box::new(ChronicleArrowError::from(e))))?; + + let meta = get_domain_type_meta_from_cache(&ticket.descriptor_path) + .ok_or(Status::from_error(Box::new(ChronicleArrowError::InvalidDescriptorPath)))?; + + tracing::debug!(ticket = ?ticket); + + let terms_result = match ticket.term { + Term::Entity => { + let pool = self.pool.clone(); + let meta_clone = meta.clone(); + let result = tokio::task::spawn_blocking(move || { + load_entities_by_type( + &pool, + &ticket.typ, + &meta_clone.attributes, + ticket.start, + ticket.count, + ) + }) + .await + .map_err(|e| Status::from_error(Box::new(ChronicleArrowError::from(e))))? + .map_err(|e| Status::from_error(Box::new(e)))?; + + let (entities, _returned_records, _total_records) = result; + + EntityAndReferences::to_record_batch(entities, &meta).map_err(|e| { + Status::internal(format!("Failed to convert to record batch: {}", e)) + })? + } + Term::Activity => { + let pool = self.pool.clone(); + let result = tokio::task::spawn_blocking(move || { + load_activities_by_type(&pool, &ticket.typ, ticket.start, ticket.count) + }) + .await + .map_err(|e| Status::from_error(Box::new(ChronicleArrowError::from(e))))? + .map_err(|e| Status::from_error(Box::new(e)))?; + + let (activities, _returned_records, _total_records) = result; + + ActivityAndReferences::to_record_batch(activities, &meta).map_err(|e| { + Status::internal(format!("Failed to convert to record batch: {}", e)) + })? + } + Term::Agent => { + let pool = self.pool.clone(); + let result = tokio::task::spawn_blocking(move || { + load_agents_by_type(&pool, &ticket.typ, ticket.start, ticket.count) + }) + .await + .map_err(|e| Status::from_error(Box::new(ChronicleArrowError::from(e))))? + .map_err(|e| Status::from_error(Box::new(e)))?; + + let (agents, _returned_records, _total_records) = result; + + AgentAndReferences::to_record_batch(agents, &meta).map_err(|e| { + Status::internal(format!("Failed to convert to record batch: {}", e)) + })? + } + Term::Namespace => { + tracing::error!("Attempted to put namespaces, which is not supported."); + return Err(Status::internal("Cannot put namespaces")); + } + }; + + let flight_data_result = batch_to_flight_data( + &FlightDescriptor::new_path(ticket.descriptor_path), + &meta, + terms_result, + ); + + match flight_data_result { + Ok(flight_data) => { + let stream = futures::stream::iter(flight_data.into_iter().map(Ok)).boxed(); + Ok(Response::new(stream)) + } + Err(e) => Err(Status::internal(e.to_string())), + } + } + + #[instrument(skip(self, request))] + async fn do_put( + &self, + request: Request>, + ) -> Result, Status> { + let mut stream = request.map(PeekableFlightDataStream::new).into_inner(); + let first_item = stream.peek().await; + + let flight_descriptor = match &first_item { + Some(Ok(flight_data)) => match flight_data.flight_descriptor.clone() { + Some(descriptor) => descriptor, + None => return Err(Status::invalid_argument("Flight data has no descriptor")), + }, + Some(Err(e)) => + return Err(Status::internal(format!("Failed to get first item from stream: {}", e))), + None => { + return Err(Status::invalid_argument("Stream is empty")); + } + }; + + let filtered_stream = stream.filter_map(|item| async move { + match item { + Ok(flight_data) => { + tracing::trace!("Processing flight data item {:?}", flight_data); + Some(Ok(flight_data)) + } + Err(e) => { + tracing::error!(error = %e, "Error processing stream item."); + None + } + } + }); + + let mut decoder = FlightRecordBatchStream::new_from_flight_data(filtered_stream); + while let Some(batch) = decoder.next().await { + let batch = batch?; + tracing::debug!("Processing batch of: {:?}", batch.num_rows()); + process_record_batch(&flight_descriptor.path, batch, &self.api) + .await + .map_err(|e| Status::from_error(e.into()))?; + } + Ok(Response::new(Box::pin(stream::empty()) as Self::DoPutStream)) + } + + #[tracing::instrument(skip(self, _request))] + async fn do_action( + &self, + _request: Request, + ) -> Result, Status> { + tracing::info!("No actions available, returning empty stream."); + Ok(Response::new(Box::pin(stream::empty()))) + } + + #[tracing::instrument(skip(self, _request))] + async fn list_actions( + &self, + _request: Request, + ) -> Result, Status> { + tracing::info!("No actions available."); + Ok(Response::new(Box::pin(stream::empty()))) + } + + async fn do_exchange( + &self, + _request: Request>, + ) -> Result, Status> { + Err(Status::unimplemented("Implement do_exchange")) + } } lazy_static! { @@ -644,78 +637,77 @@ lazy_static! { /// Triggers a shutdown signal across the application. pub fn trigger_shutdown() { - let _ = SHUTDOWN_CHANNEL.0.send(()); + let _ = SHUTDOWN_CHANNEL.0.send(()); } /// Returns a receiver for the shutdown signal. pub async fn await_shutdown() { - SHUTDOWN_CHANNEL.0.subscribe().recv().await.ok(); + SHUTDOWN_CHANNEL.0.subscribe().recv().await.ok(); } #[instrument(skip(pool, api, security))] pub async fn run_flight_service( - domain: &common::domain::ChronicleDomainDef, - pool: &Pool>, - api: &ApiDispatch, - security: EndpointSecurityConfiguration, - addrs: &Vec, - record_batch_size: usize, + domain: &common::domain::ChronicleDomainDef, + pool: &Pool>, + api: &ApiDispatch, + security: EndpointSecurityConfiguration, + addrs: &Vec, + record_batch_size: usize, ) -> Result<(), tonic::transport::Error> { - meta::cache_domain_schemas(domain); - let mut services = vec![]; - for addr in addrs { - let flight_service = - FlightServiceImpl::new(domain, pool, api, security.clone(), record_batch_size); + meta::cache_domain_schemas(domain); + let mut services = vec![]; + for addr in addrs { + let flight_service = + FlightServiceImpl::new(domain, pool, api, security.clone(), record_batch_size); - info!("Starting flight service at {}", addr); + info!("Starting flight service at {}", addr); - let server = Server::builder() - .add_service(arrow_flight::flight_service_server::FlightServiceServer::new( - flight_service, - )) - .serve_with_shutdown(*addr, await_shutdown()); + let server = Server::builder() + .add_service(arrow_flight::flight_service_server::FlightServiceServer::new( + flight_service, + )) + .serve_with_shutdown(*addr, await_shutdown()); - services.push(server); - } + services.push(server); + } - let results: Result, _> = join_all(services.into_iter()).await.into_iter().collect(); - results?; + let results: Result, _> = join_all(services.into_iter()).await.into_iter().collect(); + results?; - Ok(()) + Ok(()) } #[cfg(test)] mod tests { - use api::{ - chronicle_graphql::{authorization::TokenChecker, EndpointSecurityConfiguration}, - commands::{ApiCommand, ImportCommand}, - }; + use std::{collections::HashMap, net::SocketAddr, time::Duration}; + use arrow_array::RecordBatch; use arrow_flight::{ - decode::FlightRecordBatchStream, flight_service_client::FlightServiceClient, Criteria, + Criteria, decode::FlightRecordBatchStream, flight_service_client::FlightServiceClient, FlightData, FlightDescriptor, FlightInfo, SchemaAsIpc, }; - use arrow_ipc::writer::{self, IpcWriteOptions}; use arrow_schema::ArrowError; + use chrono::{TimeZone, Utc}; + use futures::{pin_mut, stream, StreamExt}; + use portpicker::pick_unused_port; + use tonic::{Request, Status, transport::Channel}; + use uuid::Uuid; + use api::{ + chronicle_graphql::{authorization::TokenChecker, EndpointSecurityConfiguration}, + commands::{ApiCommand, ImportCommand}, + }; use chronicle_test_infrastructure::substitutes::{test_api, TestDispatch}; - use chrono::{TimeZone, Utc}; use common::{ attributes::{Attribute, Attributes}, domain::{ChronicleDomainDef, PrimitiveType}, identity::AuthId, - prov::{operations::ChronicleOperation, NamespaceId}, + prov::{NamespaceId, operations::ChronicleOperation}, }; - use futures::{pin_mut, stream, StreamExt}; - use portpicker::pick_unused_port; - - use std::{collections::HashMap, net::SocketAddr, time::Duration}; - use tonic::{transport::Channel, Request, Status}; - use uuid::Uuid; use crate::{ - meta::{cache_domain_schemas, get_domain_type_meta_from_cache, DomainTypeMeta}, + meta::{cache_domain_schemas, DomainTypeMeta, get_domain_type_meta_from_cache}, query::{ ActedOnBehalfOfRef, ActivityAndReferences, ActivityAssociationRef, AgentAndReferences, AgentAttributionRef, AgentInteraction, DerivationRef, EntityAndReferences, @@ -724,43 +716,43 @@ mod tests { }; async fn setup_test_environment<'a>( - domain: &ChronicleDomainDef, - ) -> Result< - (FlightServiceClient, TestDispatch<'a>), - Box, - > { - chronicle_telemetry::telemetry(None, chronicle_telemetry::ConsoleLogging::Pretty); - let api = test_api().await; - let port = pick_unused_port().expect("No ports free"); - let addr = SocketAddr::from(([127, 0, 0, 1], port)); - let pool = api.temporary_database().connection_pool().unwrap(); - let dispatch = api.api_dispatch().clone(); - let domain = domain.clone(); - tokio::spawn(async move { - super::run_flight_service( - &domain, - &pool, - &dispatch, - EndpointSecurityConfiguration::new( - TokenChecker::new(None, None, 30), - HashMap::default(), - true, - ), - &vec![addr], - 10, - ) - .await - .unwrap(); - }); - - tokio::time::sleep(Duration::from_secs(5)).await; - - let client = FlightServiceClient::connect(format!("http://{}", addr)).await?; - Ok((client, api)) - } - - fn create_test_domain_def() -> ChronicleDomainDef { - let yaml = r#" + domain: &ChronicleDomainDef, + ) -> Result< + (FlightServiceClient, TestDispatch<'a>), + Box, + > { + chronicle_telemetry::telemetry(false, chronicle_telemetry::ConsoleLogging::Pretty); + let api = test_api().await; + let port = pick_unused_port().expect("No ports free"); + let addr = SocketAddr::from(([127, 0, 0, 1], port)); + let pool = api.temporary_database().connection_pool().unwrap(); + let dispatch = api.api_dispatch().clone(); + let domain = domain.clone(); + tokio::spawn(async move { + super::run_flight_service( + &domain, + &pool, + &dispatch, + EndpointSecurityConfiguration::new( + TokenChecker::new(None, None, 30), + HashMap::default(), + true, + ), + &vec![addr], + 10, + ) + .await + .unwrap(); + }); + + tokio::time::sleep(Duration::from_secs(5)).await; + + let client = FlightServiceClient::connect(format!("http://{}", addr)).await?; + Ok((client, api)) + } + + fn create_test_domain_def() -> ChronicleDomainDef { + let yaml = r#" name: Manufacturing attributes: BatchID: @@ -796,356 +788,356 @@ roles: - MANUFACTURER "#; - ChronicleDomainDef::from_input_string(yaml).unwrap() - } - - fn create_attributes( - typ: Option<&(dyn common::domain::TypeName + Send + Sync)>, - attributes: &[(String, PrimitiveType)], - ) -> Attributes { - Attributes::new( - typ.map(|x| x.as_domain_type_id()), - attributes - .iter() - .map(|(name, typ)| { - let value = match typ { - PrimitiveType::String => - serde_json::Value::String(format!("{}-value", name)), - PrimitiveType::Int => - serde_json::Value::Number(serde_json::Number::from(42)), - PrimitiveType::Bool => serde_json::Value::Bool(true), - PrimitiveType::JSON => - serde_json::Value::String(format!("{{\"{}\": \"example\"}}", name)), - }; - Attribute::new(name, value) - }) - .collect(), - ) - } - - fn create_test_entity( - attributes: Vec<(String, PrimitiveType)>, - meta: &DomainTypeMeta, - count: u32, - ) -> RecordBatch { - let mut entities = Vec::new(); - for i in 0..count { - let entity = EntityAndReferences { - id: format!("{}-{}", meta.typ.as_ref().map(|x| x.as_type_name()).unwrap(), i), - namespace_name: "default".to_string(), - namespace_uuid: Uuid::default().into_bytes(), - attributes: create_attributes(meta.typ.as_deref(), &attributes), - was_generated_by: vec![format!("activity-{}", i), format!("activity-{}", i + 1)], - was_attributed_to: vec![ - EntityAttributionRef { - agent: format!("agent-{}", i), - role: Some("CERTIFIER".to_string()), - }, - EntityAttributionRef { - agent: format!("agent-{}", i + 1), - role: Some("MANUFACTURER".to_string()), - }, - ], - was_derived_from: vec![ - DerivationRef { - source: format!("entity-d-{}", i), - activity: format!("activity-d-{}", i), - }, - DerivationRef { - source: format!("entity-d-{}", i), - activity: format!("activity-d-{}", i), - }, - ], - was_quoted_from: vec![ - DerivationRef { - source: format!("entity-q-{}", i), - activity: format!("activity-q-{}", i), - }, - DerivationRef { - source: format!("entity-q-{}", i), - activity: format!("activity-q-{}", i), - }, - ], - was_revision_of: vec![ - DerivationRef { - source: format!("entity-r-{}", i), - activity: format!("activity-r-{}", i), - }, - DerivationRef { - source: format!("entity-r-{}", i), - activity: format!("activity-r-{}", i), - }, - ], - had_primary_source: vec![ - DerivationRef { - source: format!("entity-ps-{}", i), - activity: format!("activity-ps-{}", i), - }, - DerivationRef { - source: format!("entity-ps-{}", i), - activity: format!("activity-ps-{}", i), - }, - ], - }; - entities.push(entity); - } - - EntityAndReferences::to_record_batch(entities.into_iter(), meta) - .expect("Failed to convert entities to record batch") - } - - fn create_test_activity( - attributes: Vec<(String, PrimitiveType)>, - meta: &DomainTypeMeta, - count: u32, - ) -> RecordBatch { - let mut activities = Vec::new(); - for i in 0..count { - let activity = ActivityAndReferences { - id: format!("{}-{}", meta.typ.as_ref().map(|x| x.as_type_name()).unwrap(), i), - namespace_name: "default".to_string(), - namespace_uuid: Uuid::default().into_bytes(), - attributes: create_attributes(meta.typ.as_deref(), &attributes), - started: Some(Utc.with_ymd_and_hms(2022, 1, 1, 0, 0, 0).unwrap()), - ended: Some(Utc.with_ymd_and_hms(2022, 1, 2, 0, 0, 0).unwrap()), - generated: vec![format!("entity-{}", i), format!("entity-{}", i + 1)], - was_informed_by: vec![format!("activity-{}", i), format!("activity-{}", i + 1)], - was_associated_with: vec![ActivityAssociationRef { - responsible: AgentInteraction { - agent: format!("agent-{}", i), - role: Some("ROLE_TYPE".to_string()), - }, - delegated: vec![AgentInteraction { - agent: format!("delegated-agent-{}", i), - role: Some("DELEGATED_ROLE".to_string()), - }], - }], - used: vec![format!("entity-{}", i), format!("entity-{}", i + 1)], - }; - activities.push(activity); - } - - ActivityAndReferences::to_record_batch(activities.into_iter(), meta) - .expect("Failed to convert activities to record batch") - } - - fn create_test_agent( - attributes: Vec<(String, PrimitiveType)>, - meta: &DomainTypeMeta, - count: u32, - ) -> RecordBatch { - let mut agents = Vec::new(); - for i in 0..count { - let agent = AgentAndReferences { - id: format!("{}-{}", meta.typ.as_ref().map(|x| x.as_type_name()).unwrap(), i), - namespace_name: "default".to_string(), - namespace_uuid: Uuid::default().into_bytes(), - attributes: create_attributes(meta.typ.as_deref(), &attributes), - acted_on_behalf_of: vec![ActedOnBehalfOfRef { - agent: format!("agent-{}", i), - role: Some("DELEGATED_CERTIFIER".to_string()), - activity: format!("activity-{}", i), - }], - was_attributed_to: vec![AgentAttributionRef { - entity: format!("entity-{}", i), - role: Some("UNSPECIFIED_INTERACTION".to_string()), - }], - }; - agents.push(agent); - } - - AgentAndReferences::to_record_batch(agents.into_iter(), meta) - .expect("Failed to convert agents to record batch") - } - - pub fn batches_to_flight_data( - descriptor: &FlightDescriptor, - meta: &DomainTypeMeta, - batches: Vec, - ) -> Result, ArrowError> { - let options = IpcWriteOptions::default(); - let schema_flight_data: FlightData = - std::convert::Into::::into(SchemaAsIpc::new(&meta.schema, &options)) - .with_descriptor(descriptor.clone()); - let mut dictionaries = vec![]; - let mut flight_data = vec![]; - - let data_gen = writer::IpcDataGenerator::default(); - let mut dictionary_tracker = writer::DictionaryTracker::new(false); - - for batch in batches.iter() { - let (encoded_dictionaries, encoded_batch) = - data_gen.encoded_batch(batch, &mut dictionary_tracker, &options)?; - - dictionaries.extend(encoded_dictionaries.into_iter().map(Into::into)); - let next: FlightData = encoded_batch.into(); - flight_data.push(next); - } - - let mut stream = vec![schema_flight_data]; - stream.extend(dictionaries); - stream.extend(flight_data); - let flight_data: Vec<_> = stream.into_iter().collect(); - Ok(flight_data) - } - - async fn create_test_flight_data( - count: u32, - ) -> Result>, Box> { - let entity_meta = get_domain_type_meta_from_cache(&vec![ - "Entity".to_string(), - "CertificateEntity".to_owned(), - ]) - .expect("Failed to get entity meta"); - let entity_batch = create_test_entity( - vec![("certIDAttribute".to_string(), PrimitiveType::String)], - &entity_meta, - count, - ); - let entity_flight_data = batches_to_flight_data( - &FlightDescriptor::new_path(vec!["Entity".to_string(), "CertificateEntity".to_owned()]), - &entity_meta, - vec![entity_batch], - )?; - - let activity_meta = get_domain_type_meta_from_cache(&vec![ - "Activity".to_string(), - "ItemManufacturedActivity".to_owned(), - ]) - .expect("Failed to get activity meta"); - let activity_batch = create_test_activity( - vec![("batchIDAttribute".to_string(), PrimitiveType::String)], - &activity_meta, - count, - ); - let activity_flight_data = batches_to_flight_data( - &FlightDescriptor::new_path(vec![ - "Activity".to_string(), - "ItemManufacturedActivity".to_owned(), - ]), - &activity_meta, - vec![activity_batch], - )?; - - let agent_meta = get_domain_type_meta_from_cache(&vec![ - "Agent".to_string(), - "ContractorAgent".to_owned(), - ]) - .expect("Failed to get agent meta"); - let agent_batch = create_test_agent( - vec![ - ("companyNameAttribute".to_string(), PrimitiveType::String), - ("locationAttribute".to_string(), PrimitiveType::String), - ], - &agent_meta, - count, - ); - let agent_flight_data = batches_to_flight_data( - &FlightDescriptor::new_path(vec!["Agent".to_string(), "ContractorAgent".to_owned()]), - &agent_meta, - vec![agent_batch], - )?; - - let combined_flight_data = - vec![entity_flight_data, agent_flight_data, activity_flight_data]; - - Ok(combined_flight_data) - } - - async fn put_test_data( - count: u32, - client: &mut FlightServiceClient, - api: &mut TestDispatch<'_>, - ) -> Result<(), Box> { - let create_namespace_operation = ChronicleOperation::create_namespace( - NamespaceId::from_external_id("default", Uuid::default()), - ); - api.dispatch( - ApiCommand::Import(ImportCommand { operations: vec![create_namespace_operation] }), - AuthId::anonymous(), - ) - .await - .map_err(|e| Status::from_error(e.into()))?; - - for flight_data in create_test_flight_data(count).await? { - client.do_put(stream::iter(flight_data)).await?; - } - - Ok(()) - } - - async fn stable_sorted_flight_info( - client: &mut FlightServiceClient, - ) -> Result, Box> { - let list_flights_response = client.list_flights(Request::new(Criteria::default())).await?; - - let flights = list_flights_response.into_inner().collect::>().await; - let mut valid_flights: Vec = - flights.into_iter().filter_map(Result::ok).collect(); - - valid_flights.sort_by(|a, b| { - a.flight_descriptor - .as_ref() - .map(|a| a.path.clone()) - .cmp(&b.flight_descriptor.as_ref().map(|b| b.path.clone())) - }); - Ok(valid_flights) - } - - async fn load_flights( - flights: &[FlightInfo], - client: &mut FlightServiceClient, - ) -> Result>, Box> { - let mut all_flight_data_results = Vec::new(); - for flight_info in flights { - for endpoint in &flight_info.endpoint { - if let Some(ticket) = &endpoint.ticket { - let request = Request::new(ticket.clone()); - let mut stream = client.do_get(request).await?.into_inner(); - let mut flight_data_results = Vec::new(); - while let Some(flight_data) = stream.message().await? { - flight_data_results.push(flight_data); - } - all_flight_data_results.push(flight_data_results); - } - } - } - Ok(all_flight_data_results) - } - - async fn decode_flight_data( - flight_data: Vec, - ) -> Result, Box> { - let decoder = FlightRecordBatchStream::new_from_flight_data(stream::iter( - flight_data.into_iter().map(Ok), - )); - let mut record_batches = Vec::new(); - pin_mut!(decoder); - while let Some(batch) = decoder.next().await.transpose()? { - record_batches.push(batch); - } - Ok(record_batches) - } - - #[tokio::test] - //Test using a reasonably large data set, over the endpoint paging boundary size so we can - // observe it - async fn flight_service_info() { - chronicle_telemetry::full_telemetry( - None, - None, - chronicle_telemetry::ConsoleLogging::Pretty, - ); - let domain = create_test_domain_def(); - let (mut client, mut api) = setup_test_environment(&domain).await.unwrap(); - cache_domain_schemas(&domain); - put_test_data(22, &mut client, &mut api).await.unwrap(); - - tokio::time::sleep(Duration::from_secs(10)).await; - - let flights = stable_sorted_flight_info(&mut client).await.unwrap(); - - insta::assert_debug_snapshot!(flights, @r###" + ChronicleDomainDef::from_input_string(yaml).unwrap() + } + + fn create_attributes( + typ: Option<&(dyn common::domain::TypeName + Send + Sync)>, + attributes: &[(String, PrimitiveType)], + ) -> Attributes { + Attributes::new( + typ.map(|x| x.as_domain_type_id()), + attributes + .iter() + .map(|(name, typ)| { + let value = match typ { + PrimitiveType::String => + serde_json::Value::String(format!("{}-value", name)), + PrimitiveType::Int => + serde_json::Value::Number(serde_json::Number::from(42)), + PrimitiveType::Bool => serde_json::Value::Bool(true), + PrimitiveType::JSON => + serde_json::Value::String(format!("{{\"{}\": \"example\"}}", name)), + }; + Attribute::new(name, value) + }) + .collect(), + ) + } + + fn create_test_entity( + attributes: Vec<(String, PrimitiveType)>, + meta: &DomainTypeMeta, + count: u32, + ) -> RecordBatch { + let mut entities = Vec::new(); + for i in 0..count { + let entity = EntityAndReferences { + id: format!("{}-{}", meta.typ.as_ref().map(|x| x.as_type_name()).unwrap(), i), + namespace_name: "default".to_string(), + namespace_uuid: Uuid::default().into_bytes(), + attributes: create_attributes(meta.typ.as_deref(), &attributes), + was_generated_by: vec![format!("activity-{}", i), format!("activity-{}", i + 1)], + was_attributed_to: vec![ + EntityAttributionRef { + agent: format!("agent-{}", i), + role: Some("CERTIFIER".to_string()), + }, + EntityAttributionRef { + agent: format!("agent-{}", i + 1), + role: Some("MANUFACTURER".to_string()), + }, + ], + was_derived_from: vec![ + DerivationRef { + source: format!("entity-d-{}", i), + activity: format!("activity-d-{}", i), + }, + DerivationRef { + source: format!("entity-d-{}", i), + activity: format!("activity-d-{}", i), + }, + ], + was_quoted_from: vec![ + DerivationRef { + source: format!("entity-q-{}", i), + activity: format!("activity-q-{}", i), + }, + DerivationRef { + source: format!("entity-q-{}", i), + activity: format!("activity-q-{}", i), + }, + ], + was_revision_of: vec![ + DerivationRef { + source: format!("entity-r-{}", i), + activity: format!("activity-r-{}", i), + }, + DerivationRef { + source: format!("entity-r-{}", i), + activity: format!("activity-r-{}", i), + }, + ], + had_primary_source: vec![ + DerivationRef { + source: format!("entity-ps-{}", i), + activity: format!("activity-ps-{}", i), + }, + DerivationRef { + source: format!("entity-ps-{}", i), + activity: format!("activity-ps-{}", i), + }, + ], + }; + entities.push(entity); + } + + EntityAndReferences::to_record_batch(entities.into_iter(), meta) + .expect("Failed to convert entities to record batch") + } + + fn create_test_activity( + attributes: Vec<(String, PrimitiveType)>, + meta: &DomainTypeMeta, + count: u32, + ) -> RecordBatch { + let mut activities = Vec::new(); + for i in 0..count { + let activity = ActivityAndReferences { + id: format!("{}-{}", meta.typ.as_ref().map(|x| x.as_type_name()).unwrap(), i), + namespace_name: "default".to_string(), + namespace_uuid: Uuid::default().into_bytes(), + attributes: create_attributes(meta.typ.as_deref(), &attributes), + started: Some(Utc.with_ymd_and_hms(2022, 1, 1, 0, 0, 0).unwrap()), + ended: Some(Utc.with_ymd_and_hms(2022, 1, 2, 0, 0, 0).unwrap()), + generated: vec![format!("entity-{}", i), format!("entity-{}", i + 1)], + was_informed_by: vec![format!("activity-{}", i), format!("activity-{}", i + 1)], + was_associated_with: vec![ActivityAssociationRef { + responsible: AgentInteraction { + agent: format!("agent-{}", i), + role: Some("ROLE_TYPE".to_string()), + }, + delegated: vec![AgentInteraction { + agent: format!("delegated-agent-{}", i), + role: Some("DELEGATED_ROLE".to_string()), + }], + }], + used: vec![format!("entity-{}", i), format!("entity-{}", i + 1)], + }; + activities.push(activity); + } + + ActivityAndReferences::to_record_batch(activities.into_iter(), meta) + .expect("Failed to convert activities to record batch") + } + + fn create_test_agent( + attributes: Vec<(String, PrimitiveType)>, + meta: &DomainTypeMeta, + count: u32, + ) -> RecordBatch { + let mut agents = Vec::new(); + for i in 0..count { + let agent = AgentAndReferences { + id: format!("{}-{}", meta.typ.as_ref().map(|x| x.as_type_name()).unwrap(), i), + namespace_name: "default".to_string(), + namespace_uuid: Uuid::default().into_bytes(), + attributes: create_attributes(meta.typ.as_deref(), &attributes), + acted_on_behalf_of: vec![ActedOnBehalfOfRef { + agent: format!("agent-{}", i), + role: Some("DELEGATED_CERTIFIER".to_string()), + activity: format!("activity-{}", i), + }], + was_attributed_to: vec![AgentAttributionRef { + entity: format!("entity-{}", i), + role: Some("UNSPECIFIED_INTERACTION".to_string()), + }], + }; + agents.push(agent); + } + + AgentAndReferences::to_record_batch(agents.into_iter(), meta) + .expect("Failed to convert agents to record batch") + } + + pub fn batches_to_flight_data( + descriptor: &FlightDescriptor, + meta: &DomainTypeMeta, + batches: Vec, + ) -> Result, ArrowError> { + let options = IpcWriteOptions::default(); + let schema_flight_data: FlightData = + std::convert::Into::::into(SchemaAsIpc::new(&meta.schema, &options)) + .with_descriptor(descriptor.clone()); + let mut dictionaries = vec![]; + let mut flight_data = vec![]; + + let data_gen = writer::IpcDataGenerator::default(); + let mut dictionary_tracker = writer::DictionaryTracker::new(false); + + for batch in batches.iter() { + let (encoded_dictionaries, encoded_batch) = + data_gen.encoded_batch(batch, &mut dictionary_tracker, &options)?; + + dictionaries.extend(encoded_dictionaries.into_iter().map(Into::into)); + let next: FlightData = encoded_batch.into(); + flight_data.push(next); + } + + let mut stream = vec![schema_flight_data]; + stream.extend(dictionaries); + stream.extend(flight_data); + let flight_data: Vec<_> = stream.into_iter().collect(); + Ok(flight_data) + } + + async fn create_test_flight_data( + count: u32, + ) -> Result>, Box> { + let entity_meta = get_domain_type_meta_from_cache(&vec![ + "Entity".to_string(), + "CertificateEntity".to_owned(), + ]) + .expect("Failed to get entity meta"); + let entity_batch = create_test_entity( + vec![("certIDAttribute".to_string(), PrimitiveType::String)], + &entity_meta, + count, + ); + let entity_flight_data = batches_to_flight_data( + &FlightDescriptor::new_path(vec!["Entity".to_string(), "CertificateEntity".to_owned()]), + &entity_meta, + vec![entity_batch], + )?; + + let activity_meta = get_domain_type_meta_from_cache(&vec![ + "Activity".to_string(), + "ItemManufacturedActivity".to_owned(), + ]) + .expect("Failed to get activity meta"); + let activity_batch = create_test_activity( + vec![("batchIDAttribute".to_string(), PrimitiveType::String)], + &activity_meta, + count, + ); + let activity_flight_data = batches_to_flight_data( + &FlightDescriptor::new_path(vec![ + "Activity".to_string(), + "ItemManufacturedActivity".to_owned(), + ]), + &activity_meta, + vec![activity_batch], + )?; + + let agent_meta = get_domain_type_meta_from_cache(&vec![ + "Agent".to_string(), + "ContractorAgent".to_owned(), + ]) + .expect("Failed to get agent meta"); + let agent_batch = create_test_agent( + vec![ + ("companyNameAttribute".to_string(), PrimitiveType::String), + ("locationAttribute".to_string(), PrimitiveType::String), + ], + &agent_meta, + count, + ); + let agent_flight_data = batches_to_flight_data( + &FlightDescriptor::new_path(vec!["Agent".to_string(), "ContractorAgent".to_owned()]), + &agent_meta, + vec![agent_batch], + )?; + + let combined_flight_data = + vec![entity_flight_data, agent_flight_data, activity_flight_data]; + + Ok(combined_flight_data) + } + + async fn put_test_data( + count: u32, + client: &mut FlightServiceClient, + api: &mut TestDispatch<'_>, + ) -> Result<(), Box> { + let create_namespace_operation = ChronicleOperation::create_namespace( + NamespaceId::from_external_id("default", Uuid::default()), + ); + api.dispatch( + ApiCommand::Import(ImportCommand { operations: vec![create_namespace_operation] }), + AuthId::anonymous(), + ) + .await + .map_err(|e| Status::from_error(e.into()))?; + + for flight_data in create_test_flight_data(count).await? { + client.do_put(stream::iter(flight_data)).await?; + } + + Ok(()) + } + + async fn stable_sorted_flight_info( + client: &mut FlightServiceClient, + ) -> Result, Box> { + let list_flights_response = client.list_flights(Request::new(Criteria::default())).await?; + + let flights = list_flights_response.into_inner().collect::>().await; + let mut valid_flights: Vec = + flights.into_iter().filter_map(Result::ok).collect(); + + valid_flights.sort_by(|a, b| { + a.flight_descriptor + .as_ref() + .map(|a| a.path.clone()) + .cmp(&b.flight_descriptor.as_ref().map(|b| b.path.clone())) + }); + Ok(valid_flights) + } + + async fn load_flights( + flights: &[FlightInfo], + client: &mut FlightServiceClient, + ) -> Result>, Box> { + let mut all_flight_data_results = Vec::new(); + for flight_info in flights { + for endpoint in &flight_info.endpoint { + if let Some(ticket) = &endpoint.ticket { + let request = Request::new(ticket.clone()); + let mut stream = client.do_get(request).await?.into_inner(); + let mut flight_data_results = Vec::new(); + while let Some(flight_data) = stream.message().await? { + flight_data_results.push(flight_data); + } + all_flight_data_results.push(flight_data_results); + } + } + } + Ok(all_flight_data_results) + } + + async fn decode_flight_data( + flight_data: Vec, + ) -> Result, Box> { + let decoder = FlightRecordBatchStream::new_from_flight_data(stream::iter( + flight_data.into_iter().map(Ok), + )); + let mut record_batches = Vec::new(); + pin_mut!(decoder); + while let Some(batch) = decoder.next().await.transpose()? { + record_batches.push(batch); + } + Ok(record_batches) + } + + #[tokio::test] + //Test using a reasonably large data set, over the endpoint paging boundary size so we can + // observe it + async fn flight_service_info() { + chronicle_telemetry::full_telemetry( + false, + None, + chronicle_telemetry::ConsoleLogging::Pretty, + ); + let domain = create_test_domain_def(); + let (mut client, mut api) = setup_test_environment(&domain).await.unwrap(); + cache_domain_schemas(&domain); + put_test_data(22, &mut client, &mut api).await.unwrap(); + + tokio::time::sleep(Duration::from_secs(10)).await; + + let flights = stable_sorted_flight_info(&mut client).await.unwrap(); + + insta::assert_debug_snapshot!(flights, @r###" [ FlightInfo { schema: b"\xff\xff\xff\xff8\x04\0\0\x10\0\0\0\0\0\n\0\x0c\0\n\0\t\0\x04\0\n\0\0\0\x10\0\0\0\0\x01\x04\0\x08\0\x08\0\0\0\x04\0\x08\0\0\0\x04\0\0\0\t\0\0\0\xb4\x03\0\0p\x03\0\0H\x03\0\0\x04\x03\0\0\xb8\x02\0\0`\x02\0\0\x04\x02\0\0\xa4\x01\0\0\x04\0\0\0\x80\xfc\xff\xff\x18\0\0\0\x0c\0\0\0\0\0\0\x0ct\x01\0\0\x01\0\0\0\x08\0\0\0t\xfc\xff\xffD\xfd\xff\xff\x1c\0\0\0\x0c\0\0\0\0\0\x01\rH\x01\0\0\x02\0\0\0\xbc\0\0\0\x08\0\0\0\x98\xfc\xff\xff\xc4\xfc\xff\xff\x18\0\0\0\x0c\0\0\0\0\0\0\x0c\x90\0\0\0\x01\0\0\0\x08\0\0\0\xb8\xfc\xff\xff\x88\xfd\xff\xff\x1c\0\0\0\x0c\0\0\0\0\0\x01\rd\0\0\0\x02\0\0\04\0\0\0\x08\0\0\0\xdc\xfc\xff\xff\xac\xfd\xff\xff\x14\0\0\0\x0c\0\0\0\0\0\x01\x05\x0c\0\0\0\0\0\0\0\xf8\xfc\xff\xff\x04\0\0\0role\0\0\0\00\xfd\xff\xff\x14\0\0\0\x0c\0\0\0\0\0\0\x05\x0c\0\0\0\0\0\0\0 \xfd\xff\xff\x05\0\0\0agent\0\0\0\x04\0\0\0item\0\0\0\0\t\0\0\0delegated\0\0\0t\xfd\xff\xff\x1c\0\0\0\x0c\0\0\0\0\0\0\rd\0\0\0\x02\0\0\04\0\0\0\x08\0\0\0l\xfd\xff\xff<\xfe\xff\xff\x14\0\0\0\x0c\0\0\0\0\0\x01\x05\x0c\0\0\0\0\0\0\0\x88\xfd\xff\xff\x04\0\0\0role\0\0\0\0\xc0\xfd\xff\xff\x14\0\0\0\x0c\0\0\0\0\0\0\x05\x0c\0\0\0\0\0\0\0\xb0\xfd\xff\xff\x05\0\0\0agent\0\0\0\x0b\0\0\0responsible\0\x04\0\0\0item\0\0\0\0\x13\0\0\0was_associated_with\0\x1c\xfe\xff\xff\x18\0\0\0\x0c\0\0\0\0\0\0\x0c8\0\0\0\x01\0\0\0\x08\0\0\0\x10\xfe\xff\xff<\xfe\xff\xff\x14\0\0\0\x0c\0\0\0\0\0\0\x05\x0c\0\0\0\0\0\0\0,\xfe\xff\xff\x04\0\0\0item\0\0\0\0\x0f\0\0\0was_informed_by\0x\xfe\xff\xff\x18\0\0\0\x0c\0\0\0\0\0\0\x0c8\0\0\0\x01\0\0\0\x08\0\0\0l\xfe\xff\xff\x98\xfe\xff\xff\x14\0\0\0\x0c\0\0\0\0\0\0\x05\x0c\0\0\0\0\0\0\0\x88\xfe\xff\xff\x04\0\0\0item\0\0\0\0\t\0\0\0generated\0\0\0\xd0\xfe\xff\xff\x18\0\0\0\x0c\0\0\0\0\0\0\x0c8\0\0\0\x01\0\0\0\x08\0\0\0\xc4\xfe\xff\xff\xf0\xfe\xff\xff\x14\0\0\0\x0c\0\0\0\0\0\0\x05\x0c\0\0\0\0\0\0\0\xe0\xfe\xff\xff\x04\0\0\0item\0\0\0\0\x04\0\0\0used\0\0\0\0\xc8\xff\xff\xff\x14\0\0\0\x0c\0\0\0\0\0\x01\n\x1c\0\0\0\0\0\0\0\xb8\xff\xff\xff\x08\0\0\0\0\0\x03\0\x03\0\0\0UTC\0\x05\0\0\0ended\0\0\0\x10\0\x14\0\x10\0\x0e\0\x0f\0\x04\0\0\0\x08\0\x10\0\0\0\x1c\0\0\0\x0c\0\0\0\0\0\x01\n$\0\0\0\0\0\0\0\x08\0\x0c\0\n\0\x04\0\x08\0\0\0\x08\0\0\0\0\0\x03\0\x03\0\0\0UTC\0\x07\0\0\0started\0\xac\xff\xff\xff\x14\0\0\0\x0c\0\0\0\0\0\0\x05\x0c\0\0\0\0\0\0\0\x9c\xff\xff\xff\x02\0\0\0id\0\0\xd0\xff\xff\xff\x14\0\0\0\x0c\0\0\0\0\0\0\x05\x0c\0\0\0\0\0\0\0\xc0\xff\xff\xff\x0e\0\0\0namespace_uuid\0\0\x10\0\x14\0\x10\0\0\0\x0f\0\x04\0\0\0\x08\0\x10\0\0\0\x18\0\0\0\x0c\0\0\0\0\0\0\x05\x10\0\0\0\0\0\0\0\x04\0\x04\0\x04\0\0\0\x0e\0\0\0namespace_name\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", @@ -1309,38 +1301,38 @@ roles: }, ] "###); - } - - #[tokio::test] - async fn get_and_put_are_isomorphic() { - chronicle_telemetry::telemetry(None, chronicle_telemetry::ConsoleLogging::Pretty); - let domain = create_test_domain_def(); - let (mut client, mut api) = setup_test_environment(&domain).await.unwrap(); - cache_domain_schemas(&domain); - put_test_data(8, &mut client, &mut api).await.unwrap(); - - tokio::time::sleep(Duration::from_secs(2)).await; - - let flights = stable_sorted_flight_info(&mut client).await.unwrap(); - let flight_data = load_flights(&flights, &mut client).await.unwrap(); - - let mut decoded_flight_data = vec![]; - - for flight_data in flight_data.into_iter() { - decoded_flight_data - .push(decode_flight_data(flight_data).await.expect("Failed to decode flight data")); - } - - let json_arrays = decoded_flight_data - .into_iter() - .map(|batch| { - let batch_refs: Vec<&RecordBatch> = batch.iter().collect(); - arrow::json::writer::record_batches_to_json_rows(&batch_refs) - .expect("Failed to convert record batches to JSON") - }) - .collect::>(); - - insta::assert_debug_snapshot!(json_arrays, @r###" + } + + #[tokio::test] + async fn get_and_put_are_isomorphic() { + chronicle_telemetry::telemetry(false, chronicle_telemetry::ConsoleLogging::Pretty); + let domain = create_test_domain_def(); + let (mut client, mut api) = setup_test_environment(&domain).await.unwrap(); + cache_domain_schemas(&domain); + put_test_data(8, &mut client, &mut api).await.unwrap(); + + tokio::time::sleep(Duration::from_secs(2)).await; + + let flights = stable_sorted_flight_info(&mut client).await.unwrap(); + let flight_data = load_flights(&flights, &mut client).await.unwrap(); + + let mut decoded_flight_data = vec![]; + + for flight_data in flight_data.into_iter() { + decoded_flight_data + .push(decode_flight_data(flight_data).await.expect("Failed to decode flight data")); + } + + let json_arrays = decoded_flight_data + .into_iter() + .map(|batch| { + let batch_refs: Vec<&RecordBatch> = batch.iter().collect(); + arrow::json::writer::record_batches_to_json_rows(&batch_refs) + .expect("Failed to convert record batches to JSON") + }) + .collect::>(); + + insta::assert_debug_snapshot!(json_arrays, @r###" [ [ { @@ -2042,5 +2034,5 @@ roles: ], ] "###); - } + } } diff --git a/crates/chronicle-arrow/src/meta.rs b/crates/chronicle-arrow/src/meta.rs index 70f66acd0..ce32679e3 100644 --- a/crates/chronicle-arrow/src/meta.rs +++ b/crates/chronicle-arrow/src/meta.rs @@ -1,277 +1,276 @@ use std::{ - collections::HashMap, - sync::{Arc, Mutex}, + collections::HashMap, + sync::{Arc, Mutex}, }; +use std::fmt; +use std::str::FromStr; use arrow_schema::{Schema, SchemaBuilder}; + use common::domain::{ - ActivityDef, AgentDef, ChronicleDomainDef, EntityDef, PrimitiveType, TypeName, + ActivityDef, AgentDef, ChronicleDomainDef, EntityDef, PrimitiveType, TypeName, }; fn field_for_domain_primitive(prim: &PrimitiveType) -> Option { - match prim { - PrimitiveType::String => Some(arrow_schema::DataType::Utf8), - PrimitiveType::Int => Some(arrow_schema::DataType::Int64), - PrimitiveType::Bool => Some(arrow_schema::DataType::Boolean), - PrimitiveType::JSON => Some(arrow_schema::DataType::Binary), - } + match prim { + PrimitiveType::String => Some(arrow_schema::DataType::Utf8), + PrimitiveType::Int => Some(arrow_schema::DataType::Int64), + PrimitiveType::Bool => Some(arrow_schema::DataType::Boolean), + PrimitiveType::JSON => Some(arrow_schema::DataType::Binary), + } } #[tracing::instrument] fn schema_for_namespace() -> Schema { - let mut builder = SchemaBuilder::new(); + let mut builder = SchemaBuilder::new(); - builder.push(arrow_schema::Field::new("name", arrow_schema::DataType::Utf8, false)); - builder.push(arrow_schema::Field::new("uuid", arrow_schema::DataType::Utf8, false)); + builder.push(arrow_schema::Field::new("name", arrow_schema::DataType::Utf8, false)); + builder.push(arrow_schema::Field::new("uuid", arrow_schema::DataType::Utf8, false)); - builder.finish() + builder.finish() } pub fn attribution_struct() -> arrow_schema::DataType { - arrow_schema::DataType::Struct( - vec![ - arrow_schema::Field::new("agent", arrow_schema::DataType::Utf8, false), - arrow_schema::Field::new("role", arrow_schema::DataType::Utf8, true), - ] - .into(), - ) + arrow_schema::DataType::Struct( + vec![ + arrow_schema::Field::new("agent", arrow_schema::DataType::Utf8, false), + arrow_schema::Field::new("role", arrow_schema::DataType::Utf8, true), + ] + .into(), + ) } pub fn derivation_struct() -> arrow_schema::DataType { - arrow_schema::DataType::Struct( - vec![ - arrow_schema::Field::new("source", arrow_schema::DataType::Utf8, false), - arrow_schema::Field::new("activity", arrow_schema::DataType::Utf8, false), - ] - .into(), - ) + arrow_schema::DataType::Struct( + vec![ + arrow_schema::Field::new("source", arrow_schema::DataType::Utf8, false), + arrow_schema::Field::new("activity", arrow_schema::DataType::Utf8, false), + ] + .into(), + ) } pub fn qualified_agent_struct() -> arrow_schema::DataType { - arrow_schema::DataType::Struct( - vec![ - arrow_schema::Field::new("agent", arrow_schema::DataType::Utf8, false), - arrow_schema::Field::new("role", arrow_schema::DataType::Utf8, true), - ] - .into(), - ) + arrow_schema::DataType::Struct( + vec![ + arrow_schema::Field::new("agent", arrow_schema::DataType::Utf8, false), + arrow_schema::Field::new("role", arrow_schema::DataType::Utf8, true), + ] + .into(), + ) } pub fn association_struct() -> arrow_schema::DataType { - arrow_schema::DataType::Struct( - vec![ - arrow_schema::Field::new("responsible", qualified_agent_struct(), false), - arrow_schema::Field::new( - "delegated", - arrow_schema::DataType::new_list( - qualified_agent_struct(), - true, // Set the List type as non-nullable - ), - false, - ), - ] - .into(), - ) + arrow_schema::DataType::Struct( + vec![ + arrow_schema::Field::new("responsible", qualified_agent_struct(), false), + arrow_schema::Field::new( + "delegated", + arrow_schema::DataType::new_list( + qualified_agent_struct(), + true, // Set the List type as non-nullable + ), + false, + ), + ] + .into(), + ) } pub fn agent_delegation_struct() -> arrow_schema::DataType { - arrow_schema::DataType::Struct( - vec![ - arrow_schema::Field::new("agent", arrow_schema::DataType::Utf8, false), - arrow_schema::Field::new("activity", arrow_schema::DataType::Utf8, false), - arrow_schema::Field::new("role", arrow_schema::DataType::Utf8, true), - ] - .into(), - ) + arrow_schema::DataType::Struct( + vec![ + arrow_schema::Field::new("agent", arrow_schema::DataType::Utf8, false), + arrow_schema::Field::new("activity", arrow_schema::DataType::Utf8, false), + arrow_schema::Field::new("role", arrow_schema::DataType::Utf8, true), + ] + .into(), + ) } pub fn agent_attribution_struct() -> arrow_schema::DataType { - arrow_schema::DataType::Struct( - vec![ - arrow_schema::Field::new("entity", arrow_schema::DataType::Utf8, false), - arrow_schema::Field::new("role", arrow_schema::DataType::Utf8, true), - ] - .into(), - ) + arrow_schema::DataType::Struct( + vec![ + arrow_schema::Field::new("entity", arrow_schema::DataType::Utf8, false), + arrow_schema::Field::new("role", arrow_schema::DataType::Utf8, true), + ] + .into(), + ) } pub fn schema_for_entity(entity: &EntityDef) -> Schema { - let mut builder = SchemaBuilder::new(); - - builder.push(arrow_schema::Field::new("namespace_name", arrow_schema::DataType::Utf8, false)); - builder.push(arrow_schema::Field::new("namespace_uuid", arrow_schema::DataType::Utf8, false)); - builder.push(arrow_schema::Field::new("id", arrow_schema::DataType::Utf8, false)); - - for attribute in &entity.attributes { - if let Some(data_type) = field_for_domain_primitive(&attribute.primitive_type) { - builder.push(arrow_schema::Field::new( - &attribute.preserve_inflection(), - data_type, - true, - )); - } - } - - builder.push(arrow_schema::Field::new( - "was_generated_by", - arrow_schema::DataType::new_list(arrow_schema::DataType::Utf8, false), - false, - )); - - builder.push(arrow_schema::Field::new( - "was_attributed_to", - arrow_schema::DataType::new_list(attribution_struct(), false), - false, - )); - - builder.push(arrow_schema::Field::new( - "was_derived_from", - arrow_schema::DataType::new_list(derivation_struct(), false), - false, - )); - - builder.push(arrow_schema::Field::new( - "had_primary_source", - arrow_schema::DataType::new_list(derivation_struct(), false), - false, - )); - - builder.push(arrow_schema::Field::new( - "was_quoted_from", - arrow_schema::DataType::new_list(derivation_struct(), false), - false, - )); - - builder.push(arrow_schema::Field::new( - "was_revision_of", - arrow_schema::DataType::new_list(derivation_struct(), false), - false, - )); - - builder.finish() + let mut builder = SchemaBuilder::new(); + + builder.push(arrow_schema::Field::new("namespace_name", arrow_schema::DataType::Utf8, false)); + builder.push(arrow_schema::Field::new("namespace_uuid", arrow_schema::DataType::Utf8, false)); + builder.push(arrow_schema::Field::new("id", arrow_schema::DataType::Utf8, false)); + + for attribute in &entity.attributes { + if let Some(data_type) = field_for_domain_primitive(&attribute.primitive_type) { + builder.push(arrow_schema::Field::new( + &attribute.preserve_inflection(), + data_type, + true, + )); + } + } + + builder.push(arrow_schema::Field::new( + "was_generated_by", + arrow_schema::DataType::new_list(arrow_schema::DataType::Utf8, false), + false, + )); + + builder.push(arrow_schema::Field::new( + "was_attributed_to", + arrow_schema::DataType::new_list(attribution_struct(), false), + false, + )); + + builder.push(arrow_schema::Field::new( + "was_derived_from", + arrow_schema::DataType::new_list(derivation_struct(), false), + false, + )); + + builder.push(arrow_schema::Field::new( + "had_primary_source", + arrow_schema::DataType::new_list(derivation_struct(), false), + false, + )); + + builder.push(arrow_schema::Field::new( + "was_quoted_from", + arrow_schema::DataType::new_list(derivation_struct(), false), + false, + )); + + builder.push(arrow_schema::Field::new( + "was_revision_of", + arrow_schema::DataType::new_list(derivation_struct(), false), + false, + )); + + builder.finish() } pub fn schema_for_activity(activity: &ActivityDef) -> Schema { - let mut builder = SchemaBuilder::new(); - - builder.push(arrow_schema::Field::new("namespace_name", arrow_schema::DataType::Utf8, false)); - builder.push(arrow_schema::Field::new("namespace_uuid", arrow_schema::DataType::Utf8, false)); - builder.push(arrow_schema::Field::new("id", arrow_schema::DataType::Utf8, false)); - - for attribute in &activity.attributes { - if let Some(typ) = field_for_domain_primitive(&attribute.primitive_type) { - builder.push(arrow_schema::Field::new(&attribute.preserve_inflection(), typ, true)); - } - } - - builder.push(arrow_schema::Field::new( - "started", - arrow_schema::DataType::Timestamp(arrow_schema::TimeUnit::Nanosecond, Some("UTC".into())), - true, - )); - - builder.push(arrow_schema::Field::new( - "ended", - arrow_schema::DataType::Timestamp(arrow_schema::TimeUnit::Nanosecond, Some("UTC".into())), - true, - )); - - builder.push(arrow_schema::Field::new( - "used", - arrow_schema::DataType::new_list(arrow_schema::DataType::Utf8, false), - false, - )); - - builder.push(arrow_schema::Field::new( - "generated", - arrow_schema::DataType::new_list(arrow_schema::DataType::Utf8, false), - false, - )); - - builder.push(arrow_schema::Field::new( - "was_informed_by", - arrow_schema::DataType::new_list(arrow_schema::DataType::Utf8, false), - false, - )); - - builder.push(arrow_schema::Field::new( - "was_associated_with", - arrow_schema::DataType::new_list(association_struct(), true), - false, - )); - - builder.finish() + let mut builder = SchemaBuilder::new(); + + builder.push(arrow_schema::Field::new("namespace_name", arrow_schema::DataType::Utf8, false)); + builder.push(arrow_schema::Field::new("namespace_uuid", arrow_schema::DataType::Utf8, false)); + builder.push(arrow_schema::Field::new("id", arrow_schema::DataType::Utf8, false)); + + for attribute in &activity.attributes { + if let Some(typ) = field_for_domain_primitive(&attribute.primitive_type) { + builder.push(arrow_schema::Field::new(&attribute.preserve_inflection(), typ, true)); + } + } + + builder.push(arrow_schema::Field::new( + "started", + arrow_schema::DataType::Timestamp(arrow_schema::TimeUnit::Nanosecond, Some("UTC".into())), + true, + )); + + builder.push(arrow_schema::Field::new( + "ended", + arrow_schema::DataType::Timestamp(arrow_schema::TimeUnit::Nanosecond, Some("UTC".into())), + true, + )); + + builder.push(arrow_schema::Field::new( + "used", + arrow_schema::DataType::new_list(arrow_schema::DataType::Utf8, false), + false, + )); + + builder.push(arrow_schema::Field::new( + "generated", + arrow_schema::DataType::new_list(arrow_schema::DataType::Utf8, false), + false, + )); + + builder.push(arrow_schema::Field::new( + "was_informed_by", + arrow_schema::DataType::new_list(arrow_schema::DataType::Utf8, false), + false, + )); + + builder.push(arrow_schema::Field::new( + "was_associated_with", + arrow_schema::DataType::new_list(association_struct(), true), + false, + )); + + builder.finish() } pub fn schema_for_agent(agent: &AgentDef) -> Schema { - let mut builder = SchemaBuilder::new(); - builder.push(arrow_schema::Field::new("namespace_name", arrow_schema::DataType::Utf8, false)); - builder.push(arrow_schema::Field::new("namespace_uuid", arrow_schema::DataType::Utf8, false)); - - builder.push(arrow_schema::Field::new("id", arrow_schema::DataType::Utf8, false)); - for attribute in &agent.attributes { - if let Some(typ) = field_for_domain_primitive(&attribute.primitive_type) { - builder.push(arrow_schema::Field::new(&attribute.preserve_inflection(), typ, true)); - } - } - - builder.push(arrow_schema::Field::new( - "acted_on_behalf_of", - arrow_schema::DataType::new_list(agent_delegation_struct(), false), - false, - )); - - builder.push(arrow_schema::Field::new( - "was_attributed_to", - arrow_schema::DataType::new_list(agent_attribution_struct(), false), - false, - )); - - builder.finish() + let mut builder = SchemaBuilder::new(); + builder.push(arrow_schema::Field::new("namespace_name", arrow_schema::DataType::Utf8, false)); + builder.push(arrow_schema::Field::new("namespace_uuid", arrow_schema::DataType::Utf8, false)); + + builder.push(arrow_schema::Field::new("id", arrow_schema::DataType::Utf8, false)); + for attribute in &agent.attributes { + if let Some(typ) = field_for_domain_primitive(&attribute.primitive_type) { + builder.push(arrow_schema::Field::new(&attribute.preserve_inflection(), typ, true)); + } + } + + builder.push(arrow_schema::Field::new( + "acted_on_behalf_of", + arrow_schema::DataType::new_list(agent_delegation_struct(), false), + false, + )); + + builder.push(arrow_schema::Field::new( + "was_attributed_to", + arrow_schema::DataType::new_list(agent_attribution_struct(), false), + false, + )); + + builder.finish() } #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub(crate) enum Term { - Namespace, - Entity, - Activity, - Agent, + Namespace, + Entity, + Activity, + Agent, } -use std::str::FromStr; - impl FromStr for Term { - type Err = (); - - fn from_str(s: &str) -> Result { - match s { - "Namespace" => Ok(Term::Namespace), - "Entity" => Ok(Term::Entity), - "Activity" => Ok(Term::Activity), - "Agent" => Ok(Term::Agent), - _ => Err(()), - } - } + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "Namespace" => Ok(Term::Namespace), + "Entity" => Ok(Term::Entity), + "Activity" => Ok(Term::Activity), + "Agent" => Ok(Term::Agent), + _ => Err(()), + } + } } -use std::fmt; - impl fmt::Display for Term { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Term::Namespace => write!(f, "Namespace"), - Term::Entity => write!(f, "Entity"), - Term::Activity => write!(f, "Activity"), - Term::Agent => write!(f, "Agent"), - } - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Term::Namespace => write!(f, "Namespace"), + Term::Entity => write!(f, "Entity"), + Term::Activity => write!(f, "Activity"), + Term::Agent => write!(f, "Agent"), + } + } } pub(crate) struct DomainTypeMeta { - pub schema: Arc, - pub term: Term, - pub typ: Option>, - pub attributes: Vec<(String, PrimitiveType)>, + pub schema: Arc, + pub term: Term, + pub typ: Option>, + pub attributes: Vec<(String, PrimitiveType)>, } lazy_static::lazy_static! { @@ -280,93 +279,95 @@ lazy_static::lazy_static! { } pub fn get_domain_type_meta_from_cache( - descriptor_path: &Vec, + descriptor_path: &Vec, ) -> Option> { - let cache = SCHEMA_CACHE.lock().unwrap(); - cache.get(descriptor_path).cloned() + let cache = SCHEMA_CACHE.lock().unwrap(); + cache.get(descriptor_path).cloned() } -#[tracing::instrument(skip(domain_type, type_name, schema), fields(term, schema = ?schema, type_name = type_name))] +#[tracing::instrument(skip(domain_type, type_name, schema), fields( + term, schema = ? schema, type_name = type_name +))] pub fn cache_metadata( - term: Term, - domain_type: Box, - type_name: String, - attributes: Vec<(String, PrimitiveType)>, - schema: Schema, + term: Term, + domain_type: Box, + type_name: String, + attributes: Vec<(String, PrimitiveType)>, + schema: Schema, ) { - let mut cache = SCHEMA_CACHE.lock().expect("Failed to lock SCHEMA_CACHE"); - let domain_type_meta = Arc::new(DomainTypeMeta { - schema: schema.into(), - term, - typ: Some(domain_type), - attributes, - }); - cache.insert(vec![term.to_string(), type_name], domain_type_meta); + let mut cache = SCHEMA_CACHE.lock().expect("Failed to lock SCHEMA_CACHE"); + let domain_type_meta = Arc::new(DomainTypeMeta { + schema: schema.into(), + term, + typ: Some(domain_type), + attributes, + }); + cache.insert(vec![term.to_string(), type_name], domain_type_meta); } pub fn cache_namespace_schema() { - let mut cache = SCHEMA_CACHE.lock().unwrap(); - cache.insert( - vec!["Namespace".to_string()], - Arc::new(DomainTypeMeta { - schema: schema_for_namespace().into(), - term: Term::Namespace, - typ: None, - attributes: vec![], - }), - ); + let mut cache = SCHEMA_CACHE.lock().unwrap(); + cache.insert( + vec!["Namespace".to_string()], + Arc::new(DomainTypeMeta { + schema: schema_for_namespace().into(), + term: Term::Namespace, + typ: None, + attributes: vec![], + }), + ); } #[tracing::instrument(skip(domain_def))] pub fn cache_domain_schemas(domain_def: &ChronicleDomainDef) { - for entity in &domain_def.entities { - let schema = schema_for_entity(entity); - - let attributes = entity - .attributes - .iter() - .map(|attr| (attr.preserve_inflection(), attr.primitive_type)) - .collect(); - cache_metadata( - Term::Entity, - Box::new(entity.clone()), - entity.as_type_name(), - attributes, - schema, - ); - } - - for agent in &domain_def.agents { - let schema = schema_for_agent(agent); - - let attributes = agent - .attributes - .iter() - .map(|attr| (attr.preserve_inflection(), attr.primitive_type)) - .collect(); - cache_metadata( - Term::Agent, - Box::new(agent.clone()), - agent.as_type_name(), - attributes, - schema, - ); - } - - for activity in &domain_def.activities { - let schema = schema_for_activity(activity); - - let attributes = activity - .attributes - .iter() - .map(|attr| (attr.preserve_inflection(), attr.primitive_type)) - .collect(); - cache_metadata( - Term::Activity, - Box::new(activity.clone()), - activity.as_type_name(), - attributes, - schema, - ); - } + for entity in &domain_def.entities { + let schema = schema_for_entity(entity); + + let attributes = entity + .attributes + .iter() + .map(|attr| (attr.preserve_inflection(), attr.primitive_type)) + .collect(); + cache_metadata( + Term::Entity, + Box::new(entity.clone()), + entity.as_type_name(), + attributes, + schema, + ); + } + + for agent in &domain_def.agents { + let schema = schema_for_agent(agent); + + let attributes = agent + .attributes + .iter() + .map(|attr| (attr.preserve_inflection(), attr.primitive_type)) + .collect(); + cache_metadata( + Term::Agent, + Box::new(agent.clone()), + agent.as_type_name(), + attributes, + schema, + ); + } + + for activity in &domain_def.activities { + let schema = schema_for_activity(activity); + + let attributes = activity + .attributes + .iter() + .map(|attr| (attr.preserve_inflection(), attr.primitive_type)) + .collect(); + cache_metadata( + Term::Activity, + Box::new(activity.clone()), + activity.as_type_name(), + attributes, + schema, + ); + } } diff --git a/crates/chronicle-arrow/src/operations/activity.rs b/crates/chronicle-arrow/src/operations/activity.rs index f0061db9c..995f29947 100644 --- a/crates/chronicle-arrow/src/operations/activity.rs +++ b/crates/chronicle-arrow/src/operations/activity.rs @@ -1,259 +1,259 @@ use arrow_array::{Array, RecordBatch}; +use futures::StreamExt; + use common::{ - attributes::Attributes, - prov::{ - operations::{ChronicleOperation, SetAttributes}, - ActivityId, AgentId, EntityId, NamespaceId, Role, - }, + attributes::Attributes, + prov::{ + ActivityId, + AgentId, EntityId, NamespaceId, operations::{ChronicleOperation, SetAttributes}, Role, + }, }; -use futures::StreamExt; - use crate::{ - query::{ActivityAssociationRef, AgentInteraction}, - ChronicleArrowError, + ChronicleArrowError, + query::{ActivityAssociationRef, AgentInteraction}, }; use super::{string_list_column, with_implied}; fn get_used( - record_batch: &RecordBatch, - row_index: usize, + record_batch: &RecordBatch, + row_index: usize, ) -> Result, ChronicleArrowError> { - string_list_column(record_batch, "used", row_index) + string_list_column(record_batch, "used", row_index) } fn get_generated( - record_batch: &RecordBatch, - row_index: usize, + record_batch: &RecordBatch, + row_index: usize, ) -> Result, ChronicleArrowError> { - string_list_column(record_batch, "generated", row_index) + string_list_column(record_batch, "generated", row_index) } fn get_was_informed_by( - record_batch: &RecordBatch, - row_index: usize, + record_batch: &RecordBatch, + row_index: usize, ) -> Result, ChronicleArrowError> { - string_list_column(record_batch, "was_informed_by", row_index) + string_list_column(record_batch, "was_informed_by", row_index) } fn opt_time_column( - record_batch: &RecordBatch, - column_name: &str, - row_index: usize, + record_batch: &RecordBatch, + column_name: &str, + row_index: usize, ) -> Result>, ChronicleArrowError> { - let column_index = record_batch - .schema() - .index_of(column_name) - .map_err(|_| ChronicleArrowError::MissingColumn(column_name.to_string()))?; - let column = record_batch.column(column_index); - - if let Some(timestamp_array) = - column.as_any().downcast_ref::() - { - let naive_time = timestamp_array.value_as_datetime(row_index); - let time = naive_time - .map(|nt| chrono::DateTime::::from_naive_utc_and_offset(nt, chrono::Utc)); - Ok(time) - } else { - Ok(None) - } + let column_index = record_batch + .schema() + .index_of(column_name) + .map_err(|_| ChronicleArrowError::MissingColumn(column_name.to_string()))?; + let column = record_batch.column(column_index); + + if let Some(timestamp_array) = + column.as_any().downcast_ref::() + { + let naive_time = timestamp_array.value_as_datetime(row_index); + let time = naive_time + .map(|nt| chrono::DateTime::::from_naive_utc_and_offset(nt, chrono::Utc)); + Ok(time) + } else { + Ok(None) + } } fn get_started( - record_batch: &RecordBatch, - row_index: usize, + record_batch: &RecordBatch, + row_index: usize, ) -> Result>, ChronicleArrowError> { - opt_time_column(record_batch, "started", row_index) + opt_time_column(record_batch, "started", row_index) } fn get_ended( - record_batch: &RecordBatch, - row_index: usize, + record_batch: &RecordBatch, + row_index: usize, ) -> Result>, ChronicleArrowError> { - opt_time_column(record_batch, "ended", row_index) + opt_time_column(record_batch, "ended", row_index) } fn get_was_associated_with( - record_batch: &RecordBatch, - row_index: usize, + record_batch: &RecordBatch, + row_index: usize, ) -> Result, ChronicleArrowError> { - use arrow_array::{ListArray, StringArray, StructArray}; - - let column_index = record_batch - .schema() - .index_of("was_associated_with") - .map_err(|_| ChronicleArrowError::MissingColumn("was_associated_with".to_string()))?; - let column = record_batch.column(column_index); - let list_array = column - .as_any() - .downcast_ref::() - .ok_or(ChronicleArrowError::ColumnTypeMismatch("Expected ListArray".to_string()))?; - let binding = list_array.value(row_index); - let struct_array = binding - .as_any() - .downcast_ref::() - .ok_or(ChronicleArrowError::ColumnTypeMismatch("Expected StructArray".to_string()))?; - - let mut associations = Vec::new(); - for i in 0..struct_array.len() { - let responsible_struct_array = - struct_array.column(0).as_any().downcast_ref::().ok_or( - ChronicleArrowError::ColumnTypeMismatch( - "Expected StructArray for responsible".to_string(), - ), - )?; - - let agent_array = responsible_struct_array - .column(0) - .as_any() - .downcast_ref::() - .ok_or(ChronicleArrowError::ColumnTypeMismatch( - "Expected StringArray for agent".to_string(), - ))?; - let role_array = responsible_struct_array - .column(1) - .as_any() - .downcast_ref::() - .ok_or(ChronicleArrowError::ColumnTypeMismatch( - "Expected StringArray for role".to_string(), - ))?; - - let agent = agent_array.value(i).to_string(); - let role = Some(role_array.value(i).to_string()); - - // Handling the delegated field, which is a ListArray of StructArray - let delegated_list_array = - struct_array.column(1).as_any().downcast_ref::().ok_or( - ChronicleArrowError::ColumnTypeMismatch( - "Expected ListArray for delegated".to_string(), - ), - )?; - let delegated_binding = delegated_list_array.value(i); - let delegated_struct_array = delegated_binding - .as_any() - .downcast_ref::() - .ok_or(ChronicleArrowError::ColumnTypeMismatch( - "Expected StructArray for delegated".to_string(), - ))?; - - let mut delegated_agents = Vec::new(); - for j in 0..delegated_struct_array.len() { - let delegated_agent_array = - delegated_struct_array.column(0).as_any().downcast_ref::().ok_or( - ChronicleArrowError::ColumnTypeMismatch( - "Expected StringArray for delegated agent".to_string(), - ), - )?; - let delegated_role_array = - delegated_struct_array.column(1).as_any().downcast_ref::().ok_or( - ChronicleArrowError::ColumnTypeMismatch( - "Expected StringArray for delegated role".to_string(), - ), - )?; - - let delegated_agent = delegated_agent_array.value(j).to_string(); - let delegated_role = Some(delegated_role_array.value(j).to_string()); - - delegated_agents - .push(AgentInteraction { agent: delegated_agent, role: delegated_role }); - } - - associations.push(ActivityAssociationRef { - responsible: AgentInteraction { agent, role }, - delegated: delegated_agents, - }); - } - - Ok(associations) + use arrow_array::{ListArray, StringArray, StructArray}; + + let column_index = record_batch + .schema() + .index_of("was_associated_with") + .map_err(|_| ChronicleArrowError::MissingColumn("was_associated_with".to_string()))?; + let column = record_batch.column(column_index); + let list_array = column + .as_any() + .downcast_ref::() + .ok_or(ChronicleArrowError::ColumnTypeMismatch("Expected ListArray".to_string()))?; + let binding = list_array.value(row_index); + let struct_array = binding + .as_any() + .downcast_ref::() + .ok_or(ChronicleArrowError::ColumnTypeMismatch("Expected StructArray".to_string()))?; + + let mut associations = Vec::new(); + for i in 0..struct_array.len() { + let responsible_struct_array = + struct_array.column(0).as_any().downcast_ref::().ok_or( + ChronicleArrowError::ColumnTypeMismatch( + "Expected StructArray for responsible".to_string(), + ), + )?; + + let agent_array = responsible_struct_array + .column(0) + .as_any() + .downcast_ref::() + .ok_or(ChronicleArrowError::ColumnTypeMismatch( + "Expected StringArray for agent".to_string(), + ))?; + let role_array = responsible_struct_array + .column(1) + .as_any() + .downcast_ref::() + .ok_or(ChronicleArrowError::ColumnTypeMismatch( + "Expected StringArray for role".to_string(), + ))?; + + let agent = agent_array.value(i).to_string(); + let role = Some(role_array.value(i).to_string()); + + // Handling the delegated field, which is a ListArray of StructArray + let delegated_list_array = + struct_array.column(1).as_any().downcast_ref::().ok_or( + ChronicleArrowError::ColumnTypeMismatch( + "Expected ListArray for delegated".to_string(), + ), + )?; + let delegated_binding = delegated_list_array.value(i); + let delegated_struct_array = delegated_binding + .as_any() + .downcast_ref::() + .ok_or(ChronicleArrowError::ColumnTypeMismatch( + "Expected StructArray for delegated".to_string(), + ))?; + + let mut delegated_agents = Vec::new(); + for j in 0..delegated_struct_array.len() { + let delegated_agent_array = + delegated_struct_array.column(0).as_any().downcast_ref::().ok_or( + ChronicleArrowError::ColumnTypeMismatch( + "Expected StringArray for delegated agent".to_string(), + ), + )?; + let delegated_role_array = + delegated_struct_array.column(1).as_any().downcast_ref::().ok_or( + ChronicleArrowError::ColumnTypeMismatch( + "Expected StringArray for delegated role".to_string(), + ), + )?; + + let delegated_agent = delegated_agent_array.value(j).to_string(); + let delegated_role = Some(delegated_role_array.value(j).to_string()); + + delegated_agents + .push(AgentInteraction { agent: delegated_agent, role: delegated_role }); + } + + associations.push(ActivityAssociationRef { + responsible: AgentInteraction { agent, role }, + delegated: delegated_agents, + }); + } + + Ok(associations) } pub fn activity_operations( - ns: &NamespaceId, - id: &str, - attributes: Attributes, - row_index: usize, - record_batch: &RecordBatch, + ns: &NamespaceId, + id: &str, + attributes: Attributes, + row_index: usize, + record_batch: &RecordBatch, ) -> Result, ChronicleArrowError> { - let mut operations = vec![ - ChronicleOperation::activity_exists(ns.clone(), ActivityId::from_external_id(id)), - ChronicleOperation::set_attributes(SetAttributes::activity( - ns.clone(), - ActivityId::from_external_id(id), - attributes, - )), - ]; - - let generated_ids = get_generated(record_batch, row_index)?; - - for entity_id in generated_ids { - operations.push(ChronicleOperation::was_generated_by( - ns.clone(), - EntityId::from_external_id(&entity_id), - ActivityId::from_external_id(id), - )); - } - - let used_ids = get_used(record_batch, row_index)?; - - for used_id in used_ids { - operations.push(ChronicleOperation::activity_used( - ns.clone(), - ActivityId::from_external_id(id), - EntityId::from_external_id(&used_id), - )); - } - - let was_informed_by_ids = get_was_informed_by(record_batch, row_index)?; - - for informed_by_id in was_informed_by_ids { - operations.push(ChronicleOperation::was_informed_by( - ns.clone(), - ActivityId::from_external_id(id), - ActivityId::from_external_id(&informed_by_id), - )); - } - - let started = get_started(record_batch, row_index)?; - - if let Some(started) = started { - operations.push(ChronicleOperation::start_activity( - ns.clone(), - ActivityId::from_external_id(id), - started, - )); - } - - let ended = get_ended(record_batch, row_index)?; - - if let Some(ended) = ended { - operations.push(ChronicleOperation::end_activity( - ns.clone(), - ActivityId::from_external_id(id), - ended, - )); - } - - let was_associated_with_refs = get_was_associated_with(record_batch, row_index)?; - - for association_ref in was_associated_with_refs { - operations.push(ChronicleOperation::was_associated_with( - ns.clone(), - ActivityId::from_external_id(id), - AgentId::from_external_id(&association_ref.responsible.agent), - association_ref.responsible.role.map(Role), - )); - - for delegated in &association_ref.delegated { - operations.push(ChronicleOperation::agent_acts_on_behalf_of( - ns.clone(), - AgentId::from_external_id(id), - AgentId::from_external_id(&association_ref.responsible.agent), - Some(ActivityId::from_external_id(id)), - delegated.role.as_ref().map(|role| Role(role.clone())), - )); - } - } - - Ok(with_implied(operations)) + let mut operations = vec![ + ChronicleOperation::activity_exists(ns.clone(), ActivityId::from_external_id(id)), + ChronicleOperation::set_attributes(SetAttributes::activity( + ns.clone(), + ActivityId::from_external_id(id), + attributes, + )), + ]; + + let generated_ids = get_generated(record_batch, row_index)?; + + for entity_id in generated_ids { + operations.push(ChronicleOperation::was_generated_by( + ns.clone(), + EntityId::from_external_id(&entity_id), + ActivityId::from_external_id(id), + )); + } + + let used_ids = get_used(record_batch, row_index)?; + + for used_id in used_ids { + operations.push(ChronicleOperation::activity_used( + ns.clone(), + ActivityId::from_external_id(id), + EntityId::from_external_id(&used_id), + )); + } + + let was_informed_by_ids = get_was_informed_by(record_batch, row_index)?; + + for informed_by_id in was_informed_by_ids { + operations.push(ChronicleOperation::was_informed_by( + ns.clone(), + ActivityId::from_external_id(id), + ActivityId::from_external_id(&informed_by_id), + )); + } + + let started = get_started(record_batch, row_index)?; + + if let Some(started) = started { + operations.push(ChronicleOperation::start_activity( + ns.clone(), + ActivityId::from_external_id(id), + started, + )); + } + + let ended = get_ended(record_batch, row_index)?; + + if let Some(ended) = ended { + operations.push(ChronicleOperation::end_activity( + ns.clone(), + ActivityId::from_external_id(id), + ended, + )); + } + + let was_associated_with_refs = get_was_associated_with(record_batch, row_index)?; + + for association_ref in was_associated_with_refs { + operations.push(ChronicleOperation::was_associated_with( + ns.clone(), + ActivityId::from_external_id(id), + AgentId::from_external_id(&association_ref.responsible.agent), + association_ref.responsible.role.map(Role), + )); + + for delegated in &association_ref.delegated { + operations.push(ChronicleOperation::agent_acts_on_behalf_of( + ns.clone(), + AgentId::from_external_id(id), + AgentId::from_external_id(&association_ref.responsible.agent), + Some(ActivityId::from_external_id(id)), + delegated.role.as_ref().map(|role| Role(role.clone())), + )); + } + } + + Ok(with_implied(operations)) } diff --git a/crates/chronicle-arrow/src/operations/agent.rs b/crates/chronicle-arrow/src/operations/agent.rs index d93b5b3ee..8ef92e7cd 100644 --- a/crates/chronicle-arrow/src/operations/agent.rs +++ b/crates/chronicle-arrow/src/operations/agent.rs @@ -1,90 +1,91 @@ use arrow_array::RecordBatch; + use common::{ - attributes::Attributes, - prov::{ - operations::{ChronicleOperation, SetAttributes}, - ActivityId, AgentId, EntityId, NamespaceId, Role, - }, + attributes::Attributes, + prov::{ + ActivityId, + AgentId, EntityId, NamespaceId, operations::{ChronicleOperation, SetAttributes}, Role, + }, }; use crate::{ - query::{ActedOnBehalfOfRef, AgentAttributionRef}, - ChronicleArrowError, + ChronicleArrowError, + query::{ActedOnBehalfOfRef, AgentAttributionRef}, }; use super::{struct_2_list_column_opt_string, struct_3_list_column_opt_string, with_implied}; fn get_agent_attribution( - record_batch: &RecordBatch, - row_index: usize, + record_batch: &RecordBatch, + row_index: usize, ) -> Result, ChronicleArrowError> { - Ok(struct_2_list_column_opt_string( - record_batch, - "was_attributed_to", - row_index, - "entity", - "role", - )? - .into_iter() - .map(|(entity, role)| AgentAttributionRef { entity, role }) - .collect()) + Ok(struct_2_list_column_opt_string( + record_batch, + "was_attributed_to", + row_index, + "entity", + "role", + )? + .into_iter() + .map(|(entity, role)| AgentAttributionRef { entity, role }) + .collect()) } fn get_acted_on_behalf_of( - record_batch: &RecordBatch, - row_index: usize, + record_batch: &RecordBatch, + row_index: usize, ) -> Result, ChronicleArrowError> { - Ok(struct_3_list_column_opt_string( - record_batch, - "acted_on_behalf_of", - row_index, - "agent", - "activity", - "role", - )? - .into_iter() - .map(|(agent, activity, role)| ActedOnBehalfOfRef { agent, role, activity }) - .collect()) + Ok(struct_3_list_column_opt_string( + record_batch, + "acted_on_behalf_of", + row_index, + "agent", + "activity", + "role", + )? + .into_iter() + .map(|(agent, activity, role)| ActedOnBehalfOfRef { agent, role, activity }) + .collect()) } pub fn agent_operations( - ns: &NamespaceId, - id: &str, - attributes: Attributes, - row_index: usize, - record_batch: &RecordBatch, + ns: &NamespaceId, + id: &str, + attributes: Attributes, + row_index: usize, + record_batch: &RecordBatch, ) -> Result, ChronicleArrowError> { - let mut operations = vec![ - ChronicleOperation::agent_exists(ns.clone(), AgentId::from_external_id(id)), - ChronicleOperation::set_attributes(SetAttributes::agent( - ns.clone(), - AgentId::from_external_id(id), - attributes, - )), - ]; + let mut operations = vec![ + ChronicleOperation::agent_exists(ns.clone(), AgentId::from_external_id(id)), + ChronicleOperation::set_attributes(SetAttributes::agent( + ns.clone(), + AgentId::from_external_id(id), + attributes, + )), + ]; - let was_attributed_to_refs = get_agent_attribution(record_batch, row_index)?; + let was_attributed_to_refs = get_agent_attribution(record_batch, row_index)?; - for was_attributed_to_ref in was_attributed_to_refs { - operations.push(ChronicleOperation::was_attributed_to( - ns.clone(), - EntityId::from_external_id(was_attributed_to_ref.entity), - AgentId::from_external_id(id), - was_attributed_to_ref.role.map(Role::from), - )); - } + for was_attributed_to_ref in was_attributed_to_refs { + operations.push(ChronicleOperation::was_attributed_to( + ns.clone(), + EntityId::from_external_id(was_attributed_to_ref.entity), + AgentId::from_external_id(id), + was_attributed_to_ref.role.map(Role::from), + )); + } - let acted_on_behalf_of_refs = get_acted_on_behalf_of(record_batch, row_index)?; + let acted_on_behalf_of_refs = get_acted_on_behalf_of(record_batch, row_index)?; - for acted_on_behalf_of_ref in acted_on_behalf_of_refs { - operations.push(ChronicleOperation::agent_acts_on_behalf_of( - ns.clone(), - AgentId::from_external_id(id), - AgentId::from_external_id(acted_on_behalf_of_ref.agent), - Some(ActivityId::from_external_id(acted_on_behalf_of_ref.activity)), - acted_on_behalf_of_ref.role.map(Role::from), - )); - } + for acted_on_behalf_of_ref in acted_on_behalf_of_refs { + operations.push(ChronicleOperation::agent_acts_on_behalf_of( + ns.clone(), + AgentId::from_external_id(id), + AgentId::from_external_id(acted_on_behalf_of_ref.agent), + Some(ActivityId::from_external_id(acted_on_behalf_of_ref.activity)), + acted_on_behalf_of_ref.role.map(Role::from), + )); + } - Ok(with_implied(operations)) + Ok(with_implied(operations)) } diff --git a/crates/chronicle-arrow/src/operations/entity.rs b/crates/chronicle-arrow/src/operations/entity.rs index cbb59cf07..860571365 100644 --- a/crates/chronicle-arrow/src/operations/entity.rs +++ b/crates/chronicle-arrow/src/operations/entity.rs @@ -1,139 +1,140 @@ use arrow_array::RecordBatch; + use common::{ - attributes::Attributes, - prov::{ - operations::{ChronicleOperation, DerivationType, SetAttributes}, - ActivityId, AgentId, EntityId, NamespaceId, Role, - }, + attributes::Attributes, + prov::{ + ActivityId, + AgentId, EntityId, NamespaceId, operations::{ChronicleOperation, DerivationType, SetAttributes}, Role, + }, }; use crate::{ - query::{DerivationRef, EntityAttributionRef}, - ChronicleArrowError, + ChronicleArrowError, + query::{DerivationRef, EntityAttributionRef}, }; use super::{ - string_list_column, struct_2_list_column, struct_2_list_column_opt_string, with_implied, + string_list_column, struct_2_list_column, struct_2_list_column_opt_string, with_implied, }; fn get_was_generated_by( - record_batch: &RecordBatch, - row_index: usize, + record_batch: &RecordBatch, + row_index: usize, ) -> Result, ChronicleArrowError> { - string_list_column(record_batch, "was_generated_by", row_index) + string_list_column(record_batch, "was_generated_by", row_index) } fn get_entity_was_attributed_to( - record_batch: &RecordBatch, - row_index: usize, + record_batch: &RecordBatch, + row_index: usize, ) -> Result, ChronicleArrowError> { - Ok(struct_2_list_column_opt_string( - record_batch, - "was_attributed_to", - row_index, - "agent", - "role", - )? - .into_iter() - .map(|(agent, role)| EntityAttributionRef { agent, role }) - .collect()) + Ok(struct_2_list_column_opt_string( + record_batch, + "was_attributed_to", + row_index, + "agent", + "role", + )? + .into_iter() + .map(|(agent, role)| EntityAttributionRef { agent, role }) + .collect()) } fn get_derivation( - column_name: &str, - record_batch: &RecordBatch, - row_index: usize, + column_name: &str, + record_batch: &RecordBatch, + row_index: usize, ) -> Result, ChronicleArrowError> { - Ok(struct_2_list_column(record_batch, column_name, row_index, "source", "activity")? - .into_iter() - .map(|(target, activity)| DerivationRef { source: target, activity }) - .collect()) + Ok(struct_2_list_column(record_batch, column_name, row_index, "source", "activity")? + .into_iter() + .map(|(target, activity)| DerivationRef { source: target, activity }) + .collect()) } pub fn entity_operations( - ns: &NamespaceId, - id: &str, - attributes: Attributes, - row_index: usize, - record_batch: &RecordBatch, + ns: &NamespaceId, + id: &str, + attributes: Attributes, + row_index: usize, + record_batch: &RecordBatch, ) -> Result, ChronicleArrowError> { - let mut operations = vec![ - ChronicleOperation::entity_exists(ns.clone(), EntityId::from_external_id(id)), - ChronicleOperation::set_attributes(SetAttributes::entity( - ns.clone(), - EntityId::from_external_id(id), - attributes, - )), - ]; - - let was_generated_by_ids = get_was_generated_by(record_batch, row_index)?; - - for generated_by_id in was_generated_by_ids { - operations.push(ChronicleOperation::was_generated_by( - ns.clone(), - EntityId::from_external_id(id), - ActivityId::from_external_id(&generated_by_id), - )); - } - - let was_attributed_to_refs = get_entity_was_attributed_to(record_batch, row_index)?; - - for was_attributed_to_ref in was_attributed_to_refs { - operations.push(ChronicleOperation::was_attributed_to( - ns.clone(), - EntityId::from_external_id(id), - AgentId::from_external_id(was_attributed_to_ref.agent), - was_attributed_to_ref.role.map(Role::from), - )) - } - - let was_derived_from_refs = get_derivation("was_derived_from", record_batch, row_index)?; - - for was_derived_from_ref in was_derived_from_refs { - operations.push(ChronicleOperation::entity_derive( - ns.clone(), - EntityId::from_external_id(was_derived_from_ref.source), - EntityId::from_external_id(id), - Some(ActivityId::from_external_id(was_derived_from_ref.activity)), - DerivationType::None, - )) - } - - let had_primary_source_refs = get_derivation("had_primary_source", record_batch, row_index)?; - - for had_primary_source_ref in had_primary_source_refs { - operations.push(ChronicleOperation::entity_derive( - ns.clone(), - EntityId::from_external_id(had_primary_source_ref.source), - EntityId::from_external_id(id), - Some(ActivityId::from_external_id(had_primary_source_ref.activity)), - DerivationType::PrimarySource, - )) - } - - let was_quoted_from_refs = get_derivation("was_quoted_from", record_batch, row_index)?; - - for was_quoted_from_ref in was_quoted_from_refs { - operations.push(ChronicleOperation::entity_derive( - ns.clone(), - EntityId::from_external_id(was_quoted_from_ref.source), - EntityId::from_external_id(id), - Some(ActivityId::from_external_id(was_quoted_from_ref.activity)), - DerivationType::Quotation, - )) - } - - let was_revision_of_refs = get_derivation("was_revision_of", record_batch, row_index)?; - - for was_revision_of_ref in was_revision_of_refs { - operations.push(ChronicleOperation::entity_derive( - ns.clone(), - EntityId::from_external_id(was_revision_of_ref.source), - EntityId::from_external_id(id), - Some(ActivityId::from_external_id(was_revision_of_ref.activity)), - DerivationType::Revision, - )) - } - - Ok(with_implied(operations)) + let mut operations = vec![ + ChronicleOperation::entity_exists(ns.clone(), EntityId::from_external_id(id)), + ChronicleOperation::set_attributes(SetAttributes::entity( + ns.clone(), + EntityId::from_external_id(id), + attributes, + )), + ]; + + let was_generated_by_ids = get_was_generated_by(record_batch, row_index)?; + + for generated_by_id in was_generated_by_ids { + operations.push(ChronicleOperation::was_generated_by( + ns.clone(), + EntityId::from_external_id(id), + ActivityId::from_external_id(&generated_by_id), + )); + } + + let was_attributed_to_refs = get_entity_was_attributed_to(record_batch, row_index)?; + + for was_attributed_to_ref in was_attributed_to_refs { + operations.push(ChronicleOperation::was_attributed_to( + ns.clone(), + EntityId::from_external_id(id), + AgentId::from_external_id(was_attributed_to_ref.agent), + was_attributed_to_ref.role.map(Role::from), + )) + } + + let was_derived_from_refs = get_derivation("was_derived_from", record_batch, row_index)?; + + for was_derived_from_ref in was_derived_from_refs { + operations.push(ChronicleOperation::entity_derive( + ns.clone(), + EntityId::from_external_id(was_derived_from_ref.source), + EntityId::from_external_id(id), + Some(ActivityId::from_external_id(was_derived_from_ref.activity)), + DerivationType::None, + )) + } + + let had_primary_source_refs = get_derivation("had_primary_source", record_batch, row_index)?; + + for had_primary_source_ref in had_primary_source_refs { + operations.push(ChronicleOperation::entity_derive( + ns.clone(), + EntityId::from_external_id(had_primary_source_ref.source), + EntityId::from_external_id(id), + Some(ActivityId::from_external_id(had_primary_source_ref.activity)), + DerivationType::PrimarySource, + )) + } + + let was_quoted_from_refs = get_derivation("was_quoted_from", record_batch, row_index)?; + + for was_quoted_from_ref in was_quoted_from_refs { + operations.push(ChronicleOperation::entity_derive( + ns.clone(), + EntityId::from_external_id(was_quoted_from_ref.source), + EntityId::from_external_id(id), + Some(ActivityId::from_external_id(was_quoted_from_ref.activity)), + DerivationType::Quotation, + )) + } + + let was_revision_of_refs = get_derivation("was_revision_of", record_batch, row_index)?; + + for was_revision_of_ref in was_revision_of_refs { + operations.push(ChronicleOperation::entity_derive( + ns.clone(), + EntityId::from_external_id(was_revision_of_ref.source), + EntityId::from_external_id(id), + Some(ActivityId::from_external_id(was_revision_of_ref.activity)), + DerivationType::Revision, + )) + } + + Ok(with_implied(operations)) } diff --git a/crates/chronicle-arrow/src/operations/mod.rs b/crates/chronicle-arrow/src/operations/mod.rs index eef1fcdc6..87102cb93 100644 --- a/crates/chronicle-arrow/src/operations/mod.rs +++ b/crates/chronicle-arrow/src/operations/mod.rs @@ -1,403 +1,399 @@ -mod activity; -mod agent; -mod entity; - -pub(crate) use activity::*; -pub(crate) use agent::*; -pub(crate) use entity::*; - -use api::{ - commands::{ApiCommand, ImportCommand}, - ApiDispatch, -}; use arrow::array::AsArray; use arrow_array::{Array, BooleanArray, Int64Array, RecordBatch, StringArray}; use arrow_flight::{FlightData, FlightDescriptor, SchemaAsIpc}; use arrow_ipc::writer::{DictionaryTracker, IpcDataGenerator, IpcWriteOptions}; use arrow_schema::ArrowError; +use uuid::Uuid; +pub(crate) use activity::*; +pub(crate) use agent::*; +use api::ApiDispatch; +use api::commands::{ApiCommand, ImportCommand}; use common::{ attributes::{Attribute, Attributes}, domain::TypeName, identity::AuthId, - prov::{operations::ChronicleOperation, NamespaceId}, + prov::{NamespaceId, operations::ChronicleOperation}, }; - -use uuid::Uuid; +pub(crate) use entity::*; use crate::{ - meta::{get_domain_type_meta_from_cache, DomainTypeMeta, Term}, ChronicleArrowError, + meta::{DomainTypeMeta, get_domain_type_meta_from_cache, Term}, }; +mod activity; +mod agent; +mod entity; + #[tracing::instrument(skip(record_batch, api))] pub async fn process_record_batch( - descriptor_path: &Vec, - record_batch: RecordBatch, - api: &ApiDispatch, + descriptor_path: &Vec, + record_batch: RecordBatch, + api: &ApiDispatch, ) -> Result<(), ChronicleArrowError> { - let domain_type_meta = get_domain_type_meta_from_cache(descriptor_path) - .ok_or(ChronicleArrowError::MetadataNotFound)?; - - let attribute_columns = domain_type_meta - .schema - .fields() - .iter() - .filter_map(|field| { - if field.name().ends_with("Attribute") { - Some(field.name().clone()) - } else { - None - } - }) - .collect::>(); - - match domain_type_meta.term { - Term::Entity => - create_chronicle_entity(&domain_type_meta.typ, &record_batch, &attribute_columns, api) - .await?, - Term::Activity => - create_chronicle_activity(&domain_type_meta.typ, &record_batch, &attribute_columns, api) - .await?, - Term::Agent => - create_chronicle_agent(&domain_type_meta.typ, &record_batch, &attribute_columns, api) - .await?, - Term::Namespace => create_chronicle_namespace(&record_batch, api).await?, - } - Ok(()) + let domain_type_meta = get_domain_type_meta_from_cache(descriptor_path) + .ok_or(ChronicleArrowError::MetadataNotFound)?; + + let attribute_columns = domain_type_meta + .schema + .fields() + .iter() + .filter_map(|field| { + if field.name().ends_with("Attribute") { + Some(field.name().clone()) + } else { + None + } + }) + .collect::>(); + + match domain_type_meta.term { + Term::Entity => + create_chronicle_entity(&domain_type_meta.typ, &record_batch, &attribute_columns, api) + .await?, + Term::Activity => + create_chronicle_activity(&domain_type_meta.typ, &record_batch, &attribute_columns, api) + .await?, + Term::Agent => + create_chronicle_agent(&domain_type_meta.typ, &record_batch, &attribute_columns, api) + .await?, + Term::Namespace => create_chronicle_namespace(&record_batch, api).await?, + } + Ok(()) } #[tracing::instrument(skip(descriptor, meta, batch))] pub fn batch_to_flight_data( - descriptor: &FlightDescriptor, - meta: &DomainTypeMeta, - batch: RecordBatch, + descriptor: &FlightDescriptor, + meta: &DomainTypeMeta, + batch: RecordBatch, ) -> Result, ArrowError> { - let options = IpcWriteOptions::default(); + let options = IpcWriteOptions::default(); - let schema_flight_data: FlightData = - std::convert::Into::::into(SchemaAsIpc::new(&meta.schema, &options)) - .with_descriptor(descriptor.clone()); + let schema_flight_data: FlightData = + std::convert::Into::::into(SchemaAsIpc::new(&meta.schema, &options)) + .with_descriptor(descriptor.clone()); - let data_gen = IpcDataGenerator::default(); - let mut dictionary_tracker = DictionaryTracker::new(false); + let data_gen = IpcDataGenerator::default(); + let mut dictionary_tracker = DictionaryTracker::new(false); - let (encoded_dictionaries, encoded_batch) = - data_gen.encoded_batch(&batch, &mut dictionary_tracker, &options)?; + let (encoded_dictionaries, encoded_batch) = + data_gen.encoded_batch(&batch, &mut dictionary_tracker, &options)?; - let dictionaries: Vec = encoded_dictionaries.into_iter().map(Into::into).collect(); - let flight_data: FlightData = encoded_batch.into(); + let dictionaries: Vec = encoded_dictionaries.into_iter().map(Into::into).collect(); + let flight_data: FlightData = encoded_batch.into(); - let mut stream = vec![schema_flight_data]; - stream.extend(dictionaries); - stream.push(flight_data); + let mut stream = vec![schema_flight_data]; + stream.extend(dictionaries); + stream.push(flight_data); - Ok(stream) + Ok(stream) } async fn create_chronicle_namespace( - record_batch: &RecordBatch, - _api: &ApiDispatch, + record_batch: &RecordBatch, + _api: &ApiDispatch, ) -> Result<(), ChronicleArrowError> { - let _uuid = record_batch - .column_by_name("uuid") - .ok_or(ChronicleArrowError::MissingColumn("uuid".to_string()))?; - let _name = record_batch - .column_by_name("name") - .ok_or(ChronicleArrowError::MissingColumn("name".to_string()))?; - - Ok(()) + let _uuid = record_batch + .column_by_name("uuid") + .ok_or(ChronicleArrowError::MissingColumn("uuid".to_string()))?; + let _name = record_batch + .column_by_name("name") + .ok_or(ChronicleArrowError::MissingColumn("name".to_string()))?; + + Ok(()) } pub async fn create_chronicle_entity( - domain_type: &Option>, - record_batch: &RecordBatch, - attribute_columns: &Vec, - api: &ApiDispatch, + domain_type: &Option>, + record_batch: &RecordBatch, + attribute_columns: &Vec, + api: &ApiDispatch, ) -> Result<(), ChronicleArrowError> { - create_chronicle_terms(record_batch, Term::Entity, domain_type, attribute_columns, api).await + create_chronicle_terms(record_batch, Term::Entity, domain_type, attribute_columns, api).await } pub async fn create_chronicle_activity( - domain_type: &Option>, - record_batch: &RecordBatch, - attribute_columns: &Vec, - api: &ApiDispatch, + domain_type: &Option>, + record_batch: &RecordBatch, + attribute_columns: &Vec, + api: &ApiDispatch, ) -> Result<(), ChronicleArrowError> { - create_chronicle_terms(record_batch, Term::Activity, domain_type, attribute_columns, api).await + create_chronicle_terms(record_batch, Term::Activity, domain_type, attribute_columns, api).await } pub async fn create_chronicle_agent( - domain_type: &Option>, - record_batch: &RecordBatch, - attribute_columns: &Vec, - api: &ApiDispatch, + domain_type: &Option>, + record_batch: &RecordBatch, + attribute_columns: &Vec, + api: &ApiDispatch, ) -> Result<(), ChronicleArrowError> { - create_chronicle_terms(record_batch, Term::Agent, domain_type, attribute_columns, api).await + create_chronicle_terms(record_batch, Term::Agent, domain_type, attribute_columns, api).await } pub async fn create_chronicle_terms( - record_batch: &RecordBatch, - record_type: Term, - domain_type: &Option>, - attribute_columns: &Vec, - api: &ApiDispatch, + record_batch: &RecordBatch, + record_type: Term, + domain_type: &Option>, + attribute_columns: &Vec, + api: &ApiDispatch, ) -> Result<(), ChronicleArrowError> { - let ns_name_column = record_batch - .column_by_name("namespace_name") - .ok_or(ChronicleArrowError::MissingColumn("namespace_name".to_string()))?; - - let ns_uuid_column = record_batch - .column_by_name("namespace_uuid") - .ok_or(ChronicleArrowError::MissingColumn("namespace_uuid".to_string()))?; - - let id_column = record_batch - .column_by_name("id") - .ok_or(ChronicleArrowError::MissingColumn("id".to_string()))?; - - let attribute_columns_refs: Vec<&String> = attribute_columns.iter().collect(); - let attribute_values = attribute_columns_refs - .iter() - .map(|column_name| (column_name.to_string(), record_batch.column_by_name(column_name))) - .filter_map(|(column_name, array_ref)| array_ref.map(|array_ref| (column_name, array_ref))) - .collect::>(); - - tracing::trace!(?attribute_columns, "Processing attribute columns"); - - let mut operations = Vec::new(); - for row_index in 0..record_batch.num_rows() { - let ns_name = ns_name_column.as_string::().value(row_index); - let ns_uuid = ns_uuid_column.as_string::().value(row_index); - let ns_uuid = Uuid::parse_str(ns_uuid).map_err(ChronicleArrowError::from)?; - let ns: NamespaceId = NamespaceId::from_external_id(ns_name, ns_uuid); - - let id = id_column.as_string::().value(row_index); - - let mut attributes: Vec = Vec::new(); - - for (attribute_name, attribute_array) in attribute_values.iter() { - tracing::trace!(%attribute_name, row_index, "Appending to attributes"); - if let Some(array) = attribute_array.as_any().downcast_ref::() { - let value = array.value(row_index); - attributes.push(Attribute::new( - attribute_name.clone(), - serde_json::Value::String(value.to_string()), - )); - } else if let Some(array) = attribute_array.as_any().downcast_ref::() { - let value = array.value(row_index); - attributes.push(Attribute::new( - attribute_name.clone(), - serde_json::Value::Number(value.into()), - )); - } else if let Some(array) = attribute_array.as_any().downcast_ref::() { - let value = array.value(row_index); - attributes - .push(Attribute::new(attribute_name.clone(), serde_json::Value::Bool(value))); - } else { - tracing::warn!(%attribute_name, row_index, "Unsupported attribute type"); - } - } - let attributes = - Attributes::new(domain_type.as_ref().map(|x| x.as_domain_type_id()), attributes); - - match record_type { - Term::Entity => { - operations.extend(entity_operations(&ns, id, attributes, row_index, record_batch)?); - }, - Term::Activity => { - operations.extend(activity_operations( - &ns, - id, - attributes, - row_index, - record_batch, - )?); - }, - Term::Agent => { - operations.extend(agent_operations(&ns, id, attributes, row_index, record_batch)?); - }, - Term::Namespace => { - // Noop / unreachable - }, - } - } - - api.dispatch(ApiCommand::Import(ImportCommand { operations }), AuthId::anonymous()) - .await?; - - Ok(()) + let ns_name_column = record_batch + .column_by_name("namespace_name") + .ok_or(ChronicleArrowError::MissingColumn("namespace_name".to_string()))?; + + let ns_uuid_column = record_batch + .column_by_name("namespace_uuid") + .ok_or(ChronicleArrowError::MissingColumn("namespace_uuid".to_string()))?; + + let id_column = record_batch + .column_by_name("id") + .ok_or(ChronicleArrowError::MissingColumn("id".to_string()))?; + + let attribute_columns_refs: Vec<&String> = attribute_columns.iter().collect(); + let attribute_values = attribute_columns_refs + .iter() + .map(|column_name| (column_name.to_string(), record_batch.column_by_name(column_name))) + .filter_map(|(column_name, array_ref)| array_ref.map(|array_ref| (column_name, array_ref))) + .collect::>(); + + tracing::trace!(?attribute_columns, "Processing attribute columns"); + + let mut operations = Vec::new(); + for row_index in 0..record_batch.num_rows() { + let ns_name = ns_name_column.as_string::().value(row_index); + let ns_uuid = ns_uuid_column.as_string::().value(row_index); + let ns_uuid = Uuid::parse_str(ns_uuid).map_err(ChronicleArrowError::from)?; + let ns: NamespaceId = NamespaceId::from_external_id(ns_name, ns_uuid); + + let id = id_column.as_string::().value(row_index); + + let mut attributes: Vec = Vec::new(); + + for (attribute_name, attribute_array) in attribute_values.iter() { + tracing::trace!(%attribute_name, row_index, "Appending to attributes"); + if let Some(array) = attribute_array.as_any().downcast_ref::() { + let value = array.value(row_index); + attributes.push(Attribute::new( + attribute_name.clone(), + serde_json::Value::String(value.to_string()), + )); + } else if let Some(array) = attribute_array.as_any().downcast_ref::() { + let value = array.value(row_index); + attributes.push(Attribute::new( + attribute_name.clone(), + serde_json::Value::Number(value.into()), + )); + } else if let Some(array) = attribute_array.as_any().downcast_ref::() { + let value = array.value(row_index); + attributes + .push(Attribute::new(attribute_name.clone(), serde_json::Value::Bool(value))); + } else { + tracing::warn!(%attribute_name, row_index, "Unsupported attribute type"); + } + } + let attributes = + Attributes::new(domain_type.as_ref().map(|x| x.as_domain_type_id()), attributes); + + match record_type { + Term::Entity => { + operations.extend(entity_operations(&ns, id, attributes, row_index, record_batch)?); + } + Term::Activity => { + operations.extend(activity_operations( + &ns, + id, + attributes, + row_index, + record_batch, + )?); + } + Term::Agent => { + operations.extend(agent_operations(&ns, id, attributes, row_index, record_batch)?); + } + Term::Namespace => { + // Noop / unreachable + } + } + } + + api.dispatch(ApiCommand::Import(ImportCommand { operations }), AuthId::anonymous()) + .await?; + + Ok(()) } fn string_list_column( - record_batch: &RecordBatch, - column_name: &str, - row_index: usize, + record_batch: &RecordBatch, + column_name: &str, + row_index: usize, ) -> Result, ChronicleArrowError> { - let column_index = record_batch - .schema() - .index_of(column_name) - .map_err(|_| ChronicleArrowError::MissingColumn(column_name.to_string()))?; - let column = record_batch.column(column_index); - if let Some(list_array) = column.as_any().downcast_ref::() { - if let Some(string_array) = - list_array.value(row_index).as_any().downcast_ref::() - { - Ok((0..string_array.len()).map(|i| string_array.value(i).to_string()).collect()) - } else { - Ok(vec![]) - } - } else { - Ok(vec![]) - } + let column_index = record_batch + .schema() + .index_of(column_name) + .map_err(|_| ChronicleArrowError::MissingColumn(column_name.to_string()))?; + let column = record_batch.column(column_index); + if let Some(list_array) = column.as_any().downcast_ref::() { + if let Some(string_array) = + list_array.value(row_index).as_any().downcast_ref::() + { + Ok((0..string_array.len()).map(|i| string_array.value(i).to_string()).collect()) + } else { + Ok(vec![]) + } + } else { + Ok(vec![]) + } } fn struct_2_list_column_opt_string( - record_batch: &RecordBatch, - column_name: &str, - row_index: usize, - field1_name: &str, - field2_name: &str, + record_batch: &RecordBatch, + column_name: &str, + row_index: usize, + field1_name: &str, + field2_name: &str, ) -> Result)>, ChronicleArrowError> { - let column_index = record_batch - .schema() - .index_of(column_name) - .map_err(|_| ChronicleArrowError::MissingColumn(column_name.to_string()))?; - let column = record_batch.column(column_index); - if let Some(list_array) = column.as_any().downcast_ref::() { - if let Some(struct_array) = - list_array.value(row_index).as_any().downcast_ref::() - { - let field1_index = struct_array - .column_by_name(field1_name) - .ok_or_else(|| ChronicleArrowError::MissingColumn(field1_name.to_string()))?; - let field2_index = struct_array - .column_by_name(field2_name) - .ok_or_else(|| ChronicleArrowError::MissingColumn(field2_name.to_string()))?; - - let field1_array = field1_index - .as_any() - .downcast_ref::() - .ok_or_else(|| ChronicleArrowError::ColumnTypeMismatch(field1_name.to_string()))?; - let field2_array = field2_index.as_any().downcast_ref::(); - - Ok((0..struct_array.len()) - .map(|i| { - ( - field1_array.value(i).to_string(), - field2_array.map(|arr| arr.value(i).to_string()), - ) - }) - .collect()) - } else { - Ok(vec![]) - } - } else { - Ok(vec![]) - } + let column_index = record_batch + .schema() + .index_of(column_name) + .map_err(|_| ChronicleArrowError::MissingColumn(column_name.to_string()))?; + let column = record_batch.column(column_index); + if let Some(list_array) = column.as_any().downcast_ref::() { + if let Some(struct_array) = + list_array.value(row_index).as_any().downcast_ref::() + { + let field1_index = struct_array + .column_by_name(field1_name) + .ok_or_else(|| ChronicleArrowError::MissingColumn(field1_name.to_string()))?; + let field2_index = struct_array + .column_by_name(field2_name) + .ok_or_else(|| ChronicleArrowError::MissingColumn(field2_name.to_string()))?; + + let field1_array = field1_index + .as_any() + .downcast_ref::() + .ok_or_else(|| ChronicleArrowError::ColumnTypeMismatch(field1_name.to_string()))?; + let field2_array = field2_index.as_any().downcast_ref::(); + + Ok((0..struct_array.len()) + .map(|i| { + ( + field1_array.value(i).to_string(), + field2_array.map(|arr| arr.value(i).to_string()), + ) + }) + .collect()) + } else { + Ok(vec![]) + } + } else { + Ok(vec![]) + } } fn struct_3_list_column_opt_string( - record_batch: &RecordBatch, - column_name: &str, - row_index: usize, - field1_name: &str, - field2_name: &str, - field3_name: &str, + record_batch: &RecordBatch, + column_name: &str, + row_index: usize, + field1_name: &str, + field2_name: &str, + field3_name: &str, ) -> Result)>, ChronicleArrowError> { - let column_index = record_batch - .schema() - .index_of(column_name) - .map_err(|_| ChronicleArrowError::MissingColumn(column_name.to_string()))?; - let column = record_batch.column(column_index); - if let Some(list_array) = column.as_any().downcast_ref::() { - if let Some(struct_array) = - list_array.value(row_index).as_any().downcast_ref::() - { - let field1_index = struct_array - .column_by_name(field1_name) - .ok_or_else(|| ChronicleArrowError::MissingColumn(field1_name.to_string()))?; - let field2_index = struct_array - .column_by_name(field2_name) - .ok_or_else(|| ChronicleArrowError::MissingColumn(field2_name.to_string()))?; - let field3_index = struct_array - .column_by_name(field3_name) - .ok_or_else(|| ChronicleArrowError::MissingColumn(field3_name.to_string()))?; - - let field1_array = field1_index - .as_any() - .downcast_ref::() - .ok_or_else(|| ChronicleArrowError::ColumnTypeMismatch(field1_name.to_string()))?; - let field2_array = field2_index - .as_any() - .downcast_ref::() - .ok_or_else(|| ChronicleArrowError::ColumnTypeMismatch(field2_name.to_string()))?; - let field3_array = field3_index.as_any().downcast_ref::(); - - Ok((0..struct_array.len()) - .map(|i| { - ( - field1_array.value(i).to_string(), - field2_array.value(i).to_string(), - field3_array.map(|arr| arr.value(i).to_string()), - ) - }) - .collect::)>>()) - } else { - Ok(vec![]) - } - } else { - Ok(vec![]) - } + let column_index = record_batch + .schema() + .index_of(column_name) + .map_err(|_| ChronicleArrowError::MissingColumn(column_name.to_string()))?; + let column = record_batch.column(column_index); + if let Some(list_array) = column.as_any().downcast_ref::() { + if let Some(struct_array) = + list_array.value(row_index).as_any().downcast_ref::() + { + let field1_index = struct_array + .column_by_name(field1_name) + .ok_or_else(|| ChronicleArrowError::MissingColumn(field1_name.to_string()))?; + let field2_index = struct_array + .column_by_name(field2_name) + .ok_or_else(|| ChronicleArrowError::MissingColumn(field2_name.to_string()))?; + let field3_index = struct_array + .column_by_name(field3_name) + .ok_or_else(|| ChronicleArrowError::MissingColumn(field3_name.to_string()))?; + + let field1_array = field1_index + .as_any() + .downcast_ref::() + .ok_or_else(|| ChronicleArrowError::ColumnTypeMismatch(field1_name.to_string()))?; + let field2_array = field2_index + .as_any() + .downcast_ref::() + .ok_or_else(|| ChronicleArrowError::ColumnTypeMismatch(field2_name.to_string()))?; + let field3_array = field3_index.as_any().downcast_ref::(); + + Ok((0..struct_array.len()) + .map(|i| { + ( + field1_array.value(i).to_string(), + field2_array.value(i).to_string(), + field3_array.map(|arr| arr.value(i).to_string()), + ) + }) + .collect::)>>()) + } else { + Ok(vec![]) + } + } else { + Ok(vec![]) + } } fn struct_2_list_column( - record_batch: &RecordBatch, - column_name: &str, - row_index: usize, - field1_name: &str, - field2_name: &str, + record_batch: &RecordBatch, + column_name: &str, + row_index: usize, + field1_name: &str, + field2_name: &str, ) -> Result, ChronicleArrowError> { - let column_index = record_batch - .schema() - .index_of(column_name) - .map_err(|_| ChronicleArrowError::MissingColumn(column_name.to_string()))?; - let column = record_batch.column(column_index); - if let Some(list_array) = column.as_any().downcast_ref::() { - if let Some(struct_array) = - list_array.value(row_index).as_any().downcast_ref::() - { - let field1_index = struct_array - .column_by_name(field1_name) - .ok_or_else(|| ChronicleArrowError::MissingColumn(field1_name.to_string()))?; - let field2_index = struct_array - .column_by_name(field2_name) - .ok_or_else(|| ChronicleArrowError::MissingColumn(field2_name.to_string()))?; - - if let (Some(field1_array), Some(field2_array)) = ( - field1_index.as_any().downcast_ref::(), - field2_index.as_any().downcast_ref::(), - ) { - Ok((0..struct_array.len()) - .map(|i| (field1_array.value(i).to_string(), field2_array.value(i).to_string())) - .collect()) - } else { - Ok(vec![]) - } - } else { - Ok(vec![]) - } - } else { - Ok(vec![]) - } + let column_index = record_batch + .schema() + .index_of(column_name) + .map_err(|_| ChronicleArrowError::MissingColumn(column_name.to_string()))?; + let column = record_batch.column(column_index); + if let Some(list_array) = column.as_any().downcast_ref::() { + if let Some(struct_array) = + list_array.value(row_index).as_any().downcast_ref::() + { + let field1_index = struct_array + .column_by_name(field1_name) + .ok_or_else(|| ChronicleArrowError::MissingColumn(field1_name.to_string()))?; + let field2_index = struct_array + .column_by_name(field2_name) + .ok_or_else(|| ChronicleArrowError::MissingColumn(field2_name.to_string()))?; + + if let (Some(field1_array), Some(field2_array)) = ( + field1_index.as_any().downcast_ref::(), + field2_index.as_any().downcast_ref::(), + ) { + Ok((0..struct_array.len()) + .map(|i| (field1_array.value(i).to_string(), field2_array.value(i).to_string())) + .collect()) + } else { + Ok(vec![]) + } + } else { + Ok(vec![]) + } + } else { + Ok(vec![]) + } } fn with_implied(operations: Vec) -> Vec { - operations - .into_iter() - .flat_map(|op| { - let mut implied_ops = op.implied_by(); - implied_ops.push(op); - implied_ops - }) - .collect() + operations + .into_iter() + .flat_map(|op| { + let mut implied_ops = op.implied_by(); + implied_ops.push(op); + implied_ops + }) + .collect() } diff --git a/crates/chronicle-arrow/src/peekablestream.rs b/crates/chronicle-arrow/src/peekablestream.rs index 4e8860b50..c916a390b 100644 --- a/crates/chronicle-arrow/src/peekablestream.rs +++ b/crates/chronicle-arrow/src/peekablestream.rs @@ -1,45 +1,45 @@ use std::pin::Pin; use arrow_flight::FlightData; -use futures::{stream::Peekable, Stream, StreamExt}; +use futures::{Stream, stream::Peekable, StreamExt}; use tonic::{Status, Streaming}; pub struct PeekableFlightDataStream { - inner: Peekable>, + inner: Peekable>, } impl PeekableFlightDataStream { - pub fn new(stream: Streaming) -> Self { - Self { inner: stream.peekable() } - } - - /// Convert this stream into a `Streaming`. - /// Any messages observed through [`Self::peek`] will be lost - /// after the conversion. - pub fn into_inner(self) -> Streaming { - self.inner.into_inner() - } - - /// Convert this stream into a `Peekable>`. - /// Preserves the state of the stream, so that calls to [`Self::peek`] - /// and [`Self::poll_next`] are the same. - pub fn into_peekable(self) -> Peekable> { - self.inner - } - - /// Peek at the head of this stream without advancing it. - pub async fn peek(&mut self) -> Option<&Result> { - Pin::new(&mut self.inner).peek().await - } + pub fn new(stream: Streaming) -> Self { + Self { inner: stream.peekable() } + } + + /// Convert this stream into a `Streaming`. + /// Any messages observed through [`Self::peek`] will be lost + /// after the conversion. + pub fn into_inner(self) -> Streaming { + self.inner.into_inner() + } + + /// Convert this stream into a `Peekable>`. + /// Preserves the state of the stream, so that calls to [`Self::peek`] + /// and [`Self::poll_next`] are the same. + pub fn into_peekable(self) -> Peekable> { + self.inner + } + + /// Peek at the head of this stream without advancing it. + pub async fn peek(&mut self) -> Option<&Result> { + Pin::new(&mut self.inner).peek().await + } } impl Stream for PeekableFlightDataStream { - type Item = Result; - - fn poll_next( - mut self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - self.inner.poll_next_unpin(cx) - } + type Item = Result; + + fn poll_next( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.inner.poll_next_unpin(cx) + } } diff --git a/crates/chronicle-arrow/src/query/activity.rs b/crates/chronicle-arrow/src/query/activity.rs index a978201b2..a5daffdae 100644 --- a/crates/chronicle-arrow/src/query/activity.rs +++ b/crates/chronicle-arrow/src/query/activity.rs @@ -1,465 +1,466 @@ use std::{collections::HashMap, sync::Arc}; -use crate::{ChronicleArrowError, DomainTypeMeta}; use arrow::array::{ArrayBuilder, ListBuilder, StringBuilder, StructBuilder}; use arrow_array::{ - Array, BooleanArray, Int64Array, ListArray, RecordBatch, StringArray, TimestampNanosecondArray, + Array, BooleanArray, Int64Array, ListArray, RecordBatch, StringArray, TimestampNanosecondArray, }; - use arrow_schema::{DataType, Field}; -use chronicle_persistence::{ - query::{Activity, Association, Delegation, Generation, Namespace, Usage, WasInformedBy}, - schema::{ - activity, agent, association, delegation, entity, generation, namespace, usage, - wasinformedby, - }, -}; use chrono::{DateTime, Utc}; -use common::{ - attributes::Attributes, - domain::PrimitiveType, - prov::{DomaintypeId, ExternalIdPart}, -}; use diesel::{ - pg::PgConnection, - prelude::*, - r2d2::{ConnectionManager, Pool}, + pg::PgConnection, + prelude::*, + r2d2::{ConnectionManager, Pool}, }; use uuid::Uuid; +use chronicle_persistence::{ + query::{Activity, Association, Delegation, Generation, Namespace, Usage, WasInformedBy}, + schema::{ + activity, agent, association, delegation, entity, generation, namespace, usage, + wasinformedby, + }, +}; +use common::{ + attributes::Attributes, + domain::PrimitiveType, + prov::{DomaintypeId, ExternalIdPart}, +}; + +use crate::{ChronicleArrowError, DomainTypeMeta}; + use super::vec_vec_string_to_list_array; #[tracing::instrument(skip(pool))] pub fn activity_count_by_type( - pool: &Pool>, - typ: Vec<&str>, + pool: &Pool>, + typ: Vec<&str>, ) -> Result { - let mut connection = pool.get()?; - let count = activity::table - .filter(activity::domaintype.eq_any(typ)) - .count() - .get_result(&mut connection)?; - Ok(count) + let mut connection = pool.get()?; + let count = activity::table + .filter(activity::domaintype.eq_any(typ)) + .count() + .get_result(&mut connection)?; + Ok(count) } #[derive(Default)] pub struct AgentInteraction { - pub(crate) agent: String, - pub(crate) role: Option, + pub(crate) agent: String, + pub(crate) role: Option, } #[derive(Default)] pub struct ActivityAssociationRef { - pub(crate) responsible: AgentInteraction, - pub(crate) delegated: Vec, + pub(crate) responsible: AgentInteraction, + pub(crate) delegated: Vec, } #[derive(Default)] pub struct ActivityAndReferences { - pub(crate) id: String, - pub(crate) namespace_name: String, - pub(crate) namespace_uuid: [u8; 16], - pub(crate) started: Option>, - pub(crate) ended: Option>, - pub(crate) attributes: Attributes, - pub(crate) used: Vec, - pub(crate) generated: Vec, - pub(crate) was_informed_by: Vec, - pub(crate) was_associated_with: Vec, + pub(crate) id: String, + pub(crate) namespace_name: String, + pub(crate) namespace_uuid: [u8; 16], + pub(crate) started: Option>, + pub(crate) ended: Option>, + pub(crate) attributes: Attributes, + pub(crate) used: Vec, + pub(crate) generated: Vec, + pub(crate) was_informed_by: Vec, + pub(crate) was_associated_with: Vec, } impl ActivityAndReferences { - #[tracing::instrument(skip(items, meta))] - pub fn to_record_batch( - items: impl Iterator, - meta: &DomainTypeMeta, - ) -> Result { - let mut attributes_map: HashMap>)> = - HashMap::new(); - - for (attribute_name, primitive_type) in meta.attributes.iter() { - attributes_map.insert(attribute_name.to_string(), (*primitive_type, vec![])); - } - - let mut id_vec = Vec::new(); - let mut namespace_name_vec = Vec::new(); - let mut namespace_uuid_vec = Vec::new(); - let mut started_vec = Vec::new(); - let mut ended_vec = Vec::new(); - let mut used_vec = Vec::new(); - let mut generated_vec = Vec::new(); - let mut was_informed_by_vec = Vec::new(); - let mut was_associated_with_vec = Vec::new(); - - for item in items { - id_vec.push(item.id); - namespace_name_vec.push(item.namespace_name); - namespace_uuid_vec.push(Uuid::from_bytes(item.namespace_uuid).to_string()); - started_vec.push(item.started.map(|dt| dt.timestamp_nanos_opt().unwrap_or_default())); - ended_vec.push(item.ended.map(|dt| dt.timestamp_nanos_opt().unwrap_or_default())); - used_vec.push(item.used); - generated_vec.push(item.generated); - was_informed_by_vec.push(item.was_informed_by); - was_associated_with_vec.push(item.was_associated_with); - - for (key, (_primitive_type, values)) in attributes_map.iter_mut() { - if let Some(attribute) = item.attributes.get_attribute(key) { - values.push(Some(attribute.value.clone().into())); - } else { - values.push(None); - } - } - } - - let used_array = vec_vec_string_to_list_array(used_vec)?; - let generated_array = vec_vec_string_to_list_array(generated_vec)?; - let was_informed_by_array = vec_vec_string_to_list_array(was_informed_by_vec)?; - let was_associated_with_array = associations_to_list_array(was_associated_with_vec)?; - - let mut fields = vec![ - ( - "namespace_name".to_string(), - Arc::new(StringArray::from(namespace_name_vec)) as Arc, - ), - ( - "namespace_uuid".to_string(), - Arc::new(StringArray::from(namespace_uuid_vec)) as Arc, - ), - ("id".to_string(), Arc::new(StringArray::from(id_vec)) as Arc), - ]; - - // Dynamically generate fields for attribute key/values based on their primitive type - for (key, (primitive_type, values)) in attributes_map { - let array: Arc = match primitive_type { - PrimitiveType::String => { - tracing::debug!("Converting String attribute values for key: {}", key); - Arc::new(StringArray::from( - values - .iter() - .map(|v| v.as_ref().map(|v| v.as_str()).unwrap_or_default()) - .collect::>(), - )) as Arc - }, - PrimitiveType::Int => { - tracing::debug!("Converting Int attribute values for key: {}", key); - Arc::new(Int64Array::from( - values - .iter() - .map(|v| v.as_ref().map(|v| v.as_i64()).unwrap_or_default()) - .collect::>(), - )) as Arc - }, - PrimitiveType::Bool => { - tracing::debug!("Converting Bool attribute values for key: {}", key); - Arc::new(BooleanArray::from( - values - .iter() - .map(|v| v.as_ref().map(|v| v.as_bool()).unwrap_or_default()) - .collect::>(), - )) as Arc - }, - _ => { - tracing::warn!("Unsupported attribute primitive type for key: {}", key); - continue; - }, - }; - fields.push((key, array as Arc)); - } - - fields.extend(vec![ - ( - "started".to_string(), - Arc::new(TimestampNanosecondArray::with_timezone_opt( - started_vec.into(), - Some("UTC".to_string()), - )) as Arc, - ), - ( - "ended".to_string(), - Arc::new(TimestampNanosecondArray::with_timezone_opt( - ended_vec.into(), - Some("UTC".to_string()), - )) as Arc, - ), - ("used".to_string(), Arc::new(used_array) as Arc), - ("generated".to_string(), Arc::new(generated_array) as Arc), - ( - "was_informed_by".to_string(), - Arc::new(was_informed_by_array) as Arc, - ), - ( - "was_associated_with".to_string(), - Arc::new(was_associated_with_array) as Arc, - ), - ]); - - let hashed_fields = fields.into_iter().collect::>(); - - let mut columns = Vec::new(); - for field in meta.schema.fields() { - let field_name = field.name(); - match hashed_fields.get(field_name) { - Some(array) => columns.push(array.clone()), - None => - return Err(ChronicleArrowError::SchemaFieldNotFound(field_name.to_string())), - } - } - - RecordBatch::try_new(meta.schema.clone(), columns).map_err(ChronicleArrowError::from) - } + #[tracing::instrument(skip(items, meta))] + pub fn to_record_batch( + items: impl Iterator, + meta: &DomainTypeMeta, + ) -> Result { + let mut attributes_map: HashMap>)> = + HashMap::new(); + + for (attribute_name, primitive_type) in meta.attributes.iter() { + attributes_map.insert(attribute_name.to_string(), (*primitive_type, vec![])); + } + + let mut id_vec = Vec::new(); + let mut namespace_name_vec = Vec::new(); + let mut namespace_uuid_vec = Vec::new(); + let mut started_vec = Vec::new(); + let mut ended_vec = Vec::new(); + let mut used_vec = Vec::new(); + let mut generated_vec = Vec::new(); + let mut was_informed_by_vec = Vec::new(); + let mut was_associated_with_vec = Vec::new(); + + for item in items { + id_vec.push(item.id); + namespace_name_vec.push(item.namespace_name); + namespace_uuid_vec.push(Uuid::from_bytes(item.namespace_uuid).to_string()); + started_vec.push(item.started.map(|dt| dt.timestamp_nanos_opt().unwrap_or_default())); + ended_vec.push(item.ended.map(|dt| dt.timestamp_nanos_opt().unwrap_or_default())); + used_vec.push(item.used); + generated_vec.push(item.generated); + was_informed_by_vec.push(item.was_informed_by); + was_associated_with_vec.push(item.was_associated_with); + + for (key, (_primitive_type, values)) in attributes_map.iter_mut() { + if let Some(attribute) = item.attributes.get_attribute(key) { + values.push(Some(attribute.value.clone().into())); + } else { + values.push(None); + } + } + } + + let used_array = vec_vec_string_to_list_array(used_vec)?; + let generated_array = vec_vec_string_to_list_array(generated_vec)?; + let was_informed_by_array = vec_vec_string_to_list_array(was_informed_by_vec)?; + let was_associated_with_array = associations_to_list_array(was_associated_with_vec)?; + + let mut fields = vec![ + ( + "namespace_name".to_string(), + Arc::new(StringArray::from(namespace_name_vec)) as Arc, + ), + ( + "namespace_uuid".to_string(), + Arc::new(StringArray::from(namespace_uuid_vec)) as Arc, + ), + ("id".to_string(), Arc::new(StringArray::from(id_vec)) as Arc), + ]; + + // Dynamically generate fields for attribute key/values based on their primitive type + for (key, (primitive_type, values)) in attributes_map { + let array: Arc = match primitive_type { + PrimitiveType::String => { + tracing::debug!("Converting String attribute values for key: {}", key); + Arc::new(StringArray::from( + values + .iter() + .map(|v| v.as_ref().map(|v| v.as_str()).unwrap_or_default()) + .collect::>(), + )) as Arc + } + PrimitiveType::Int => { + tracing::debug!("Converting Int attribute values for key: {}", key); + Arc::new(Int64Array::from( + values + .iter() + .map(|v| v.as_ref().map(|v| v.as_i64()).unwrap_or_default()) + .collect::>(), + )) as Arc + } + PrimitiveType::Bool => { + tracing::debug!("Converting Bool attribute values for key: {}", key); + Arc::new(BooleanArray::from( + values + .iter() + .map(|v| v.as_ref().map(|v| v.as_bool()).unwrap_or_default()) + .collect::>(), + )) as Arc + } + _ => { + tracing::warn!("Unsupported attribute primitive type for key: {}", key); + continue; + } + }; + fields.push((key, array as Arc)); + } + + fields.extend(vec![ + ( + "started".to_string(), + Arc::new(TimestampNanosecondArray::with_timezone_opt( + started_vec.into(), + Some("UTC".to_string()), + )) as Arc, + ), + ( + "ended".to_string(), + Arc::new(TimestampNanosecondArray::with_timezone_opt( + ended_vec.into(), + Some("UTC".to_string()), + )) as Arc, + ), + ("used".to_string(), Arc::new(used_array) as Arc), + ("generated".to_string(), Arc::new(generated_array) as Arc), + ( + "was_informed_by".to_string(), + Arc::new(was_informed_by_array) as Arc, + ), + ( + "was_associated_with".to_string(), + Arc::new(was_associated_with_array) as Arc, + ), + ]); + + let hashed_fields = fields.into_iter().collect::>(); + + let mut columns = Vec::new(); + for field in meta.schema.fields() { + let field_name = field.name(); + match hashed_fields.get(field_name) { + Some(array) => columns.push(array.clone()), + None => + return Err(ChronicleArrowError::SchemaFieldNotFound(field_name.to_string())), + } + } + + RecordBatch::try_new(meta.schema.clone(), columns).map_err(ChronicleArrowError::from) + } } fn associations_to_list_array( - associations: Vec>, + associations: Vec>, ) -> Result { - let fields = - vec![Field::new("agent", DataType::Utf8, false), Field::new("role", DataType::Utf8, true)]; - - let agent_struct = DataType::Struct(fields.clone().into()); - - let mut builder = ListBuilder::new(StructBuilder::new( - vec![ - Field::new("responsible", agent_struct.clone(), false), - Field::new( - "delegated", - DataType::List(Arc::new(Field::new("item", agent_struct, true))), - false, - ), - ], - vec![ - Box::new(StructBuilder::from_fields(fields.clone(), 0)), - Box::new(ListBuilder::new(StructBuilder::from_fields(fields, 0))), - ], - )); - - for association_vec in associations { - let struct_builder = builder.values(); - - for association in association_vec { - // Build the responsible field - let responsible_builder = struct_builder.field_builder::(0).unwrap(); - responsible_builder - .field_builder::(0) - .unwrap() - .append_value(&association.responsible.agent); - if let Some(role) = &association.responsible.role { - responsible_builder - .field_builder::(1) - .unwrap() - .append_value(role); - } else { - responsible_builder.field_builder::(1).unwrap().append_null(); - } - responsible_builder.append(true); - - // Build the delegated field - let delegated_builder = - struct_builder.field_builder::>(1).unwrap(); - for agent_interaction in &association.delegated { - let interaction_builder = delegated_builder.values(); - interaction_builder - .field_builder::(0) - .unwrap() - .append_value(&agent_interaction.agent); - if let Some(role) = &agent_interaction.role { - interaction_builder - .field_builder::(1) - .unwrap() - .append_value(role); - } else { - interaction_builder.field_builder::(1).unwrap().append_null(); - } - interaction_builder.append(true); - } - delegated_builder.append(true); - - struct_builder.append(true); - } - - builder.append(true); - } - - Ok(builder.finish()) + let fields = + vec![Field::new("agent", DataType::Utf8, false), Field::new("role", DataType::Utf8, true)]; + + let agent_struct = DataType::Struct(fields.clone().into()); + + let mut builder = ListBuilder::new(StructBuilder::new( + vec![ + Field::new("responsible", agent_struct.clone(), false), + Field::new( + "delegated", + DataType::List(Arc::new(Field::new("item", agent_struct, true))), + false, + ), + ], + vec![ + Box::new(StructBuilder::from_fields(fields.clone(), 0)), + Box::new(ListBuilder::new(StructBuilder::from_fields(fields, 0))), + ], + )); + + for association_vec in associations { + let struct_builder = builder.values(); + + for association in association_vec { + // Build the responsible field + let responsible_builder = struct_builder.field_builder::(0).unwrap(); + responsible_builder + .field_builder::(0) + .unwrap() + .append_value(&association.responsible.agent); + if let Some(role) = &association.responsible.role { + responsible_builder + .field_builder::(1) + .unwrap() + .append_value(role); + } else { + responsible_builder.field_builder::(1).unwrap().append_null(); + } + responsible_builder.append(true); + + // Build the delegated field + let delegated_builder = + struct_builder.field_builder::>(1).unwrap(); + for agent_interaction in &association.delegated { + let interaction_builder = delegated_builder.values(); + interaction_builder + .field_builder::(0) + .unwrap() + .append_value(&agent_interaction.agent); + if let Some(role) = &agent_interaction.role { + interaction_builder + .field_builder::(1) + .unwrap() + .append_value(role); + } else { + interaction_builder.field_builder::(1).unwrap().append_null(); + } + interaction_builder.append(true); + } + delegated_builder.append(true); + + struct_builder.append(true); + } + + builder.append(true); + } + + Ok(builder.finish()) } pub fn load_activities_by_type( - pool: &Pool>, - typ: &Option, - position: u64, - max_records: u64, -) -> Result<(impl Iterator, u64, u64), ChronicleArrowError> { - let mut connection = pool.get().map_err(ChronicleArrowError::PoolError)?; - - let activities_and_namespaces: Vec<(Activity, Namespace)> = match typ { - Some(typ_value) => activity::table - .inner_join(namespace::table.on(activity::namespace_id.eq(namespace::id))) - .filter(activity::domaintype.eq(typ_value.external_id_part())) - .order(activity::id) - .select((Activity::as_select(), Namespace::as_select())) - .offset(position as i64) - .limit(max_records as i64) - .load(&mut connection)?, - None => activity::table - .inner_join(namespace::table.on(activity::namespace_id.eq(namespace::id))) - .filter(activity::domaintype.is_null()) - .order(activity::id) - .select((Activity::as_select(), Namespace::as_select())) - .offset(position as i64) - .limit(max_records as i64) - .load(&mut connection)?, - }; - - let (activities, namespaces): (Vec, Vec) = - activities_and_namespaces.into_iter().unzip(); - - let mut was_informed_by_map: HashMap> = - WasInformedBy::belonging_to(&activities) - .inner_join(activity::table.on(wasinformedby::informing_activity_id.eq(activity::id))) - .select((wasinformedby::activity_id, activity::external_id)) - .load::<(i32, String)>(&mut connection)? - .into_iter() - .fold(HashMap::new(), |mut acc: HashMap>, (id, external_id)| { - acc.entry(id).or_default().push(external_id); - acc - }); - - let mut used_map: HashMap> = Usage::belonging_to(&activities) - .inner_join(entity::table.on(usage::entity_id.eq(entity::id))) - .select((usage::activity_id, entity::external_id)) - .load::<(i32, String)>(&mut connection)? - .into_iter() - .fold(HashMap::new(), |mut acc: HashMap>, (id, external_id)| { - acc.entry(id).or_default().push(external_id); - acc - }); - - let mut generated_map: HashMap> = Generation::belonging_to(&activities) - .inner_join(entity::table.on(generation::generated_entity_id.eq(entity::id))) - .select((generation::activity_id, entity::external_id)) - .load::<(i32, String)>(&mut connection)? - .into_iter() - .fold(HashMap::new(), |mut acc: HashMap>, (id, external_id)| { - acc.entry(id).or_default().push(external_id); - acc - }); - - let associations_map: HashMap> = - Association::belonging_to(&activities) - .inner_join(agent::table.on(association::agent_id.eq(agent::id))) - .select((association::activity_id, (agent::id, agent::external_id, association::role))) - .load::<(i32, (i32, String, String))>(&mut connection)? - .into_iter() - .fold( - HashMap::new(), - |mut acc: HashMap>, - (activity_id, (agent_id, agent_external_id, role_external_id))| { - acc.entry(activity_id) - .or_default() - .insert(agent_id, (agent_external_id, role_external_id)); - acc - }, - ); - - let delegations_map: HashMap> = - Delegation::belonging_to(&activities) - .inner_join(agent::table.on(delegation::delegate_id.eq(agent::id))) - .select(( - delegation::activity_id, - (delegation::responsible_id, agent::external_id, delegation::role), - )) - .load::<(i32, (i32, String, String))>(&mut connection)? - .into_iter() - .fold( - HashMap::new(), - |mut acc: HashMap>, - (activity_id, (agent_id, agent_external_id, role_external_id))| { - acc.entry(activity_id) - .or_default() - .insert(agent_id, (agent_external_id, role_external_id)); - acc - }, - ); - - let mut activity_associations: HashMap> = HashMap::new(); - - for (activity_id, agent_map) in associations_map.into_iter() { - let mut association_refs = Vec::new(); - for (agent_id, (agent_external_id, role_external_id)) in agent_map.into_iter() { - let mut delegated_agents = Vec::new(); - if let Some(delegations) = delegations_map.get(&activity_id) { - if let Some((delegated_agent_external_id, delegated_role_external_id)) = - delegations.get(&agent_id) - { - delegated_agents.push(AgentInteraction { - agent: delegated_agent_external_id.clone(), - role: Some(delegated_role_external_id.clone()), - }); - } - } - association_refs.push(ActivityAssociationRef { - responsible: AgentInteraction { - agent: agent_external_id, - role: Some(role_external_id), - }, - delegated: delegated_agents, - }); - } - activity_associations.insert(activity_id, association_refs); - } - let fetched_records = activities.len() as u64; - - let mut activities_and_references = vec![]; - - for (activity, ns) in activities.into_iter().zip(namespaces) { - activities_and_references.push(ActivityAndReferences { - id: activity.external_id, - namespace_name: ns.external_id, - namespace_uuid: Uuid::parse_str(&ns.uuid)?.into_bytes(), - attributes: Attributes::new( - activity.domaintype.map(DomaintypeId::from_external_id), - vec![], - ), // Placeholder for attribute loading logic - started: activity.started.map(|dt| dt.and_utc()), - ended: activity.ended.map(|dt| dt.and_utc()), - was_informed_by: was_informed_by_map.remove(&activity.id).unwrap_or_default(), - used: used_map.remove(&activity.id).unwrap_or_default(), - generated: generated_map.remove(&activity.id).unwrap_or_default(), - was_associated_with: activity_associations.remove(&activity.id).unwrap_or_default(), - }); - } - Ok((activities_and_references.into_iter(), fetched_records, fetched_records)) + pool: &Pool>, + typ: &Option, + position: u64, + max_records: u64, +) -> Result<(impl Iterator, u64, u64), ChronicleArrowError> { + let mut connection = pool.get().map_err(ChronicleArrowError::PoolError)?; + + let activities_and_namespaces: Vec<(Activity, Namespace)> = match typ { + Some(typ_value) => activity::table + .inner_join(namespace::table.on(activity::namespace_id.eq(namespace::id))) + .filter(activity::domaintype.eq(typ_value.external_id_part())) + .order(activity::id) + .select((Activity::as_select(), Namespace::as_select())) + .offset(position as i64) + .limit(max_records as i64) + .load(&mut connection)?, + None => activity::table + .inner_join(namespace::table.on(activity::namespace_id.eq(namespace::id))) + .filter(activity::domaintype.is_null()) + .order(activity::id) + .select((Activity::as_select(), Namespace::as_select())) + .offset(position as i64) + .limit(max_records as i64) + .load(&mut connection)?, + }; + + let (activities, namespaces): (Vec, Vec) = + activities_and_namespaces.into_iter().unzip(); + + let mut was_informed_by_map: HashMap> = + WasInformedBy::belonging_to(&activities) + .inner_join(activity::table.on(wasinformedby::informing_activity_id.eq(activity::id))) + .select((wasinformedby::activity_id, activity::external_id)) + .load::<(i32, String)>(&mut connection)? + .into_iter() + .fold(HashMap::new(), |mut acc: HashMap>, (id, external_id)| { + acc.entry(id).or_default().push(external_id); + acc + }); + + let mut used_map: HashMap> = Usage::belonging_to(&activities) + .inner_join(entity::table.on(usage::entity_id.eq(entity::id))) + .select((usage::activity_id, entity::external_id)) + .load::<(i32, String)>(&mut connection)? + .into_iter() + .fold(HashMap::new(), |mut acc: HashMap>, (id, external_id)| { + acc.entry(id).or_default().push(external_id); + acc + }); + + let mut generated_map: HashMap> = Generation::belonging_to(&activities) + .inner_join(entity::table.on(generation::generated_entity_id.eq(entity::id))) + .select((generation::activity_id, entity::external_id)) + .load::<(i32, String)>(&mut connection)? + .into_iter() + .fold(HashMap::new(), |mut acc: HashMap>, (id, external_id)| { + acc.entry(id).or_default().push(external_id); + acc + }); + + let associations_map: HashMap> = + Association::belonging_to(&activities) + .inner_join(agent::table.on(association::agent_id.eq(agent::id))) + .select((association::activity_id, (agent::id, agent::external_id, association::role))) + .load::<(i32, (i32, String, String))>(&mut connection)? + .into_iter() + .fold( + HashMap::new(), + |mut acc: HashMap>, + (activity_id, (agent_id, agent_external_id, role_external_id))| { + acc.entry(activity_id) + .or_default() + .insert(agent_id, (agent_external_id, role_external_id)); + acc + }, + ); + + let delegations_map: HashMap> = + Delegation::belonging_to(&activities) + .inner_join(agent::table.on(delegation::delegate_id.eq(agent::id))) + .select(( + delegation::activity_id, + (delegation::responsible_id, agent::external_id, delegation::role), + )) + .load::<(i32, (i32, String, String))>(&mut connection)? + .into_iter() + .fold( + HashMap::new(), + |mut acc: HashMap>, + (activity_id, (agent_id, agent_external_id, role_external_id))| { + acc.entry(activity_id) + .or_default() + .insert(agent_id, (agent_external_id, role_external_id)); + acc + }, + ); + + let mut activity_associations: HashMap> = HashMap::new(); + + for (activity_id, agent_map) in associations_map.into_iter() { + let mut association_refs = Vec::new(); + for (agent_id, (agent_external_id, role_external_id)) in agent_map.into_iter() { + let mut delegated_agents = Vec::new(); + if let Some(delegations) = delegations_map.get(&activity_id) { + if let Some((delegated_agent_external_id, delegated_role_external_id)) = + delegations.get(&agent_id) + { + delegated_agents.push(AgentInteraction { + agent: delegated_agent_external_id.clone(), + role: Some(delegated_role_external_id.clone()), + }); + } + } + association_refs.push(ActivityAssociationRef { + responsible: AgentInteraction { + agent: agent_external_id, + role: Some(role_external_id), + }, + delegated: delegated_agents, + }); + } + activity_associations.insert(activity_id, association_refs); + } + let fetched_records = activities.len() as u64; + + let mut activities_and_references = vec![]; + + for (activity, ns) in activities.into_iter().zip(namespaces) { + activities_and_references.push(ActivityAndReferences { + id: activity.external_id, + namespace_name: ns.external_id, + namespace_uuid: Uuid::parse_str(&ns.uuid)?.into_bytes(), + attributes: Attributes::new( + activity.domaintype.map(DomaintypeId::from_external_id), + vec![], + ), // Placeholder for attribute loading logic + started: activity.started.map(|dt| dt.and_utc()), + ended: activity.ended.map(|dt| dt.and_utc()), + was_informed_by: was_informed_by_map.remove(&activity.id).unwrap_or_default(), + used: used_map.remove(&activity.id).unwrap_or_default(), + generated: generated_map.remove(&activity.id).unwrap_or_default(), + was_associated_with: activity_associations.remove(&activity.id).unwrap_or_default(), + }); + } + Ok((activities_and_references.into_iter(), fetched_records, fetched_records)) } #[cfg(test)] mod test { - use super::*; - - #[test] - fn test_associations_to_list_array_empty() { - let associations = Vec::new(); - let result = associations_to_list_array(associations); - assert!(result.is_ok()); - let array = result.unwrap(); - assert_eq!(array.len(), 0); - } - - #[test] - fn test_associations_to_list_array_single() { - let associations = vec![ActivityAssociationRef { - responsible: AgentInteraction { - agent: "agent1".to_string(), - role: Some("role1".to_string()), - }, - delegated: vec![AgentInteraction { - agent: "delegated1".to_string(), - role: Some("role3".to_string()), - }], - }]; - let result = associations_to_list_array(vec![associations]).unwrap(); - - let json = arrow::json::writer::array_to_json_array(&result).unwrap(); - - insta::assert_debug_snapshot!(&json, @r###" + use super::*; + + #[test] + fn test_associations_to_list_array_empty() { + let associations = Vec::new(); + let result = associations_to_list_array(associations); + assert!(result.is_ok()); + let array = result.unwrap(); + assert_eq!(array.len(), 0); + } + + #[test] + fn test_associations_to_list_array_single() { + let associations = vec![ActivityAssociationRef { + responsible: AgentInteraction { + agent: "agent1".to_string(), + role: Some("role1".to_string()), + }, + delegated: vec![AgentInteraction { + agent: "delegated1".to_string(), + role: Some("role3".to_string()), + }], + }]; + let result = associations_to_list_array(vec![associations]).unwrap(); + + let json = arrow::json::writer::array_to_json_array(&result).unwrap(); + + insta::assert_debug_snapshot!(&json, @r###" [ Array [ Object { @@ -477,40 +478,40 @@ mod test { ], ] "### ); - } - - #[test] - fn test_associations_to_list_array_multiple() { - let associations = vec![ - ActivityAssociationRef { - responsible: AgentInteraction { - agent: "agent1".to_string(), - role: Some("role1".to_string()), - }, - delegated: vec![], - }, - ActivityAssociationRef { - responsible: AgentInteraction { - agent: "agent2".to_string(), - role: Some("role2".to_string()), - }, - delegated: vec![ - AgentInteraction { - agent: "delegated1".to_string(), - role: Some("role3".to_string()), - }, - AgentInteraction { - agent: "delegated2".to_string(), - role: Some("role3".to_string()), - }, - ], - }, - ]; - let result = associations_to_list_array(vec![associations]).unwrap(); - - let json = arrow::json::writer::array_to_json_array(&result).unwrap(); - - insta::assert_debug_snapshot!(&json, @r###" + } + + #[test] + fn test_associations_to_list_array_multiple() { + let associations = vec![ + ActivityAssociationRef { + responsible: AgentInteraction { + agent: "agent1".to_string(), + role: Some("role1".to_string()), + }, + delegated: vec![], + }, + ActivityAssociationRef { + responsible: AgentInteraction { + agent: "agent2".to_string(), + role: Some("role2".to_string()), + }, + delegated: vec![ + AgentInteraction { + agent: "delegated1".to_string(), + role: Some("role3".to_string()), + }, + AgentInteraction { + agent: "delegated2".to_string(), + role: Some("role3".to_string()), + }, + ], + }, + ]; + let result = associations_to_list_array(vec![associations]).unwrap(); + + let json = arrow::json::writer::array_to_json_array(&result).unwrap(); + + insta::assert_debug_snapshot!(&json, @r###" [ Array [ Object { @@ -539,5 +540,5 @@ mod test { ], ] "### ); - } + } } diff --git a/crates/chronicle-arrow/src/query/agent.rs b/crates/chronicle-arrow/src/query/agent.rs index e38c47a0c..6ef00782a 100644 --- a/crates/chronicle-arrow/src/query/agent.rs +++ b/crates/chronicle-arrow/src/query/agent.rs @@ -1,377 +1,380 @@ use std::{collections::HashMap, sync::Arc}; -use crate::{ - meta::{agent_attribution_struct, agent_delegation_struct}, - ChronicleArrowError, DomainTypeMeta, -}; use arrow::array::{ArrayBuilder, StringBuilder, StructBuilder}; use arrow_array::{Array, BooleanArray, Int64Array, ListArray, RecordBatch, StringArray}; use arrow_buffer::{Buffer, ToByteSlice}; use arrow_data::ArrayData; use arrow_schema::{DataType, Field}; +use diesel::{ + pg::PgConnection, + prelude::*, + r2d2::{ConnectionManager, Pool}, +}; +use uuid::Uuid; + use chronicle_persistence::{ - query::{Agent, Attribution, Delegation, Namespace}, - schema::{activity, agent, attribution, delegation, entity, namespace}, + query::{Agent, Attribution, Delegation, Namespace}, + schema::{activity, agent, attribution, delegation, entity, namespace}, }; use common::{ - attributes::Attributes, - domain::PrimitiveType, - prov::{DomaintypeId, ExternalIdPart, Role}, + attributes::Attributes, + domain::PrimitiveType, + prov::{DomaintypeId, ExternalIdPart, Role}, }; -use diesel::{ - pg::PgConnection, - prelude::*, - r2d2::{ConnectionManager, Pool}, + +use crate::{ + ChronicleArrowError, + DomainTypeMeta, meta::{agent_attribution_struct, agent_delegation_struct}, }; -use uuid::Uuid; + #[tracing::instrument(skip(pool))] pub fn agent_count_by_type( - pool: &Pool>, - typ: Vec<&str>, + pool: &Pool>, + typ: Vec<&str>, ) -> Result { - let mut connection = pool.get()?; - let count = agent::table - .filter(agent::domaintype.eq_any(typ)) - .count() - .get_result(&mut connection)?; - Ok(count) + let mut connection = pool.get()?; + let count = agent::table + .filter(agent::domaintype.eq_any(typ)) + .count() + .get_result(&mut connection)?; + Ok(count) } #[derive(Default)] pub struct ActedOnBehalfOfRef { - pub(crate) agent: String, - pub(crate) role: Option, - pub(crate) activity: String, + pub(crate) agent: String, + pub(crate) role: Option, + pub(crate) activity: String, } #[derive(Default)] pub struct AgentAttributionRef { - pub(crate) entity: String, - pub(crate) role: Option, + pub(crate) entity: String, + pub(crate) role: Option, } #[derive(Default)] pub struct AgentAndReferences { - pub(crate) id: String, - pub(crate) namespace_name: String, - pub(crate) namespace_uuid: [u8; 16], - pub(crate) attributes: Attributes, - pub(crate) acted_on_behalf_of: Vec, - pub(crate) was_attributed_to: Vec, + pub(crate) id: String, + pub(crate) namespace_name: String, + pub(crate) namespace_uuid: [u8; 16], + pub(crate) attributes: Attributes, + pub(crate) acted_on_behalf_of: Vec, + pub(crate) was_attributed_to: Vec, } impl AgentAndReferences { - #[tracing::instrument(skip(items, meta))] - pub fn to_record_batch( - items: impl Iterator, - meta: &DomainTypeMeta, - ) -> Result { - let mut attributes_map: HashMap>)> = - HashMap::new(); - - for (attribute_name, primitive_type) in meta.attributes.iter() { - attributes_map.insert(attribute_name.to_string(), (*primitive_type, vec![])); - } - - let mut id_vec = Vec::new(); - let mut namespace_name_vec = Vec::new(); - let mut namespace_uuid_vec = Vec::new(); - let mut acted_on_behalf_of_vec = Vec::new(); - let mut was_attributed_to_vec = Vec::new(); - - for item in items { - id_vec.push(item.id); - namespace_name_vec.push(item.namespace_name); - - namespace_uuid_vec.push(Uuid::from_bytes(item.namespace_uuid).to_string()); - acted_on_behalf_of_vec.push(item.acted_on_behalf_of); - was_attributed_to_vec.push(item.was_attributed_to); - - for (key, (_primitive_type, values)) in attributes_map.iter_mut() { - if let Some(attribute) = item.attributes.get_attribute(key) { - values.push(Some(attribute.value.clone().into())); - } else { - values.push(None); - } - } - } - - let acted_on_behalf_of_array = - agent_acted_on_behalf_of_to_list_array(acted_on_behalf_of_vec)?; - let was_attributed_to_array = agent_attributions_to_list_array(was_attributed_to_vec)?; - - let mut fields = vec![ - ( - "namespace_name".to_string(), - Arc::new(StringArray::from(namespace_name_vec)) as Arc, - ), - ( - "namespace_uuid".to_string(), - Arc::new(StringArray::from(namespace_uuid_vec)) as Arc, - ), - ("id".to_string(), Arc::new(StringArray::from(id_vec)) as Arc), - ]; - - // Dynamically generate fields for attribute key/values based on their primitive type - for (key, (primitive_type, values)) in attributes_map { - let array: Arc = match primitive_type { - PrimitiveType::String => { - tracing::debug!("Converting String attribute values for key: {}", key); - Arc::new(StringArray::from_iter( - values.iter().map(|v| v.as_ref().map(|v| v.as_str()).unwrap_or_default()), - )) as Arc - }, - PrimitiveType::Int => { - tracing::debug!("Converting Int attribute values for key: {}", key); - Arc::new(Int64Array::from_iter( - values.iter().map(|v| v.as_ref().map(|v| v.as_i64()).unwrap_or_default()), - )) as Arc - }, - PrimitiveType::Bool => { - tracing::debug!("Converting Bool attribute values for key: {}", key); - Arc::new(BooleanArray::from_iter( - values.iter().map(|v| v.as_ref().map(|v| v.as_bool()).unwrap_or_default()), - )) as Arc - }, - _ => { - tracing::warn!("Unsupported attribute primitive type for key: {}", key); - continue; - }, - }; - fields.push((key, array as Arc)); - } - - fields.extend(vec![ - ( - "acted_on_behalf_of".to_string(), - Arc::new(acted_on_behalf_of_array) as Arc, - ), - ( - "was_attributed_to".to_string(), - Arc::new(was_attributed_to_array) as Arc, - ), - ]); - - let hashed_fields = fields.into_iter().collect::>(); - - let mut columns = Vec::new(); - for field in meta.schema.fields() { - let field_name = field.name(); - match hashed_fields.get(field_name) { - Some(array) => columns.push(array.clone()), - None => - return Err(ChronicleArrowError::SchemaFieldNotFound(field_name.to_string())), - } - } - - RecordBatch::try_new(meta.schema.clone(), columns).map_err(ChronicleArrowError::from) - } + #[tracing::instrument(skip(items, meta))] + pub fn to_record_batch( + items: impl Iterator, + meta: &DomainTypeMeta, + ) -> Result { + let mut attributes_map: HashMap>)> = + HashMap::new(); + + for (attribute_name, primitive_type) in meta.attributes.iter() { + attributes_map.insert(attribute_name.to_string(), (*primitive_type, vec![])); + } + + let mut id_vec = Vec::new(); + let mut namespace_name_vec = Vec::new(); + let mut namespace_uuid_vec = Vec::new(); + let mut acted_on_behalf_of_vec = Vec::new(); + let mut was_attributed_to_vec = Vec::new(); + + for item in items { + id_vec.push(item.id); + namespace_name_vec.push(item.namespace_name); + + namespace_uuid_vec.push(Uuid::from_bytes(item.namespace_uuid).to_string()); + acted_on_behalf_of_vec.push(item.acted_on_behalf_of); + was_attributed_to_vec.push(item.was_attributed_to); + + for (key, (_primitive_type, values)) in attributes_map.iter_mut() { + if let Some(attribute) = item.attributes.get_attribute(key) { + values.push(Some(attribute.value.clone().into())); + } else { + values.push(None); + } + } + } + + let acted_on_behalf_of_array = + agent_acted_on_behalf_of_to_list_array(acted_on_behalf_of_vec)?; + let was_attributed_to_array = agent_attributions_to_list_array(was_attributed_to_vec)?; + + let mut fields = vec![ + ( + "namespace_name".to_string(), + Arc::new(StringArray::from(namespace_name_vec)) as Arc, + ), + ( + "namespace_uuid".to_string(), + Arc::new(StringArray::from(namespace_uuid_vec)) as Arc, + ), + ("id".to_string(), Arc::new(StringArray::from(id_vec)) as Arc), + ]; + + // Dynamically generate fields for attribute key/values based on their primitive type + for (key, (primitive_type, values)) in attributes_map { + let array: Arc = match primitive_type { + PrimitiveType::String => { + tracing::debug!("Converting String attribute values for key: {}", key); + Arc::new(StringArray::from_iter( + values.iter().map(|v| v.as_ref().map(|v| v.as_str()).unwrap_or_default()), + )) as Arc + } + PrimitiveType::Int => { + tracing::debug!("Converting Int attribute values for key: {}", key); + Arc::new(Int64Array::from_iter( + values.iter().map(|v| v.as_ref().map(|v| v.as_i64()).unwrap_or_default()), + )) as Arc + } + PrimitiveType::Bool => { + tracing::debug!("Converting Bool attribute values for key: {}", key); + Arc::new(BooleanArray::from_iter( + values.iter().map(|v| v.as_ref().map(|v| v.as_bool()).unwrap_or_default()), + )) as Arc + } + _ => { + tracing::warn!("Unsupported attribute primitive type for key: {}", key); + continue; + } + }; + fields.push((key, array as Arc)); + } + + fields.extend(vec![ + ( + "acted_on_behalf_of".to_string(), + Arc::new(acted_on_behalf_of_array) as Arc, + ), + ( + "was_attributed_to".to_string(), + Arc::new(was_attributed_to_array) as Arc, + ), + ]); + + let hashed_fields = fields.into_iter().collect::>(); + + let mut columns = Vec::new(); + for field in meta.schema.fields() { + let field_name = field.name(); + match hashed_fields.get(field_name) { + Some(array) => columns.push(array.clone()), + None => + return Err(ChronicleArrowError::SchemaFieldNotFound(field_name.to_string())), + } + } + + RecordBatch::try_new(meta.schema.clone(), columns).map_err(ChronicleArrowError::from) + } } fn agent_acted_on_behalf_of_to_list_array( - agent_attributions: Vec>, + agent_attributions: Vec>, ) -> Result { - let offsets: Vec = std::iter::once(0) - .chain(agent_attributions.iter().map(|v| v.len() as i32)) - .scan(0, |state, len| { - *state += len; - Some(*state) - }) - .collect(); - - let agent_builder = StringBuilder::new(); - let role_builder = StringBuilder::new(); - let activity_builder = StringBuilder::new(); - - let fields = vec![ - Field::new("agent", DataType::Utf8, false), - Field::new("activity", DataType::Utf8, false), - Field::new("role", DataType::Utf8, true), - ]; - let field_builders = vec![ - Box::new(agent_builder) as Box, - Box::new(activity_builder) as Box, - Box::new(role_builder) as Box, - ]; - - let mut builder = StructBuilder::new(fields, field_builders); - - for acted_on_behalf_of in agent_attributions.into_iter().flatten() { - builder - .field_builder::(0) - .expect("Failed to get agent field builder") - .append_value(&acted_on_behalf_of.agent); - builder - .field_builder::(1) - .expect("Failed to get activity field builder") - .append_value(acted_on_behalf_of.activity); - builder - .field_builder::(2) - .expect("Failed to get role field builder") - .append_option(acted_on_behalf_of.role.as_deref()); - - builder.append(true); - } - - let values_array = builder.finish(); - - let data_type = DataType::new_list(agent_delegation_struct(), false); - let offsets_buffer = Buffer::from(offsets.to_byte_slice()); - - let list_array = ListArray::from( - ArrayData::builder(data_type) - .add_child_data(values_array.to_data()) - .len(offsets.len() - 1) - .null_count(0) - .add_buffer(offsets_buffer) - .build()?, - ); - - Ok(list_array) + let offsets: Vec = std::iter::once(0) + .chain(agent_attributions.iter().map(|v| v.len() as i32)) + .scan(0, |state, len| { + *state += len; + Some(*state) + }) + .collect(); + + let agent_builder = StringBuilder::new(); + let role_builder = StringBuilder::new(); + let activity_builder = StringBuilder::new(); + + let fields = vec![ + Field::new("agent", DataType::Utf8, false), + Field::new("activity", DataType::Utf8, false), + Field::new("role", DataType::Utf8, true), + ]; + let field_builders = vec![ + Box::new(agent_builder) as Box, + Box::new(activity_builder) as Box, + Box::new(role_builder) as Box, + ]; + + let mut builder = StructBuilder::new(fields, field_builders); + + for acted_on_behalf_of in agent_attributions.into_iter().flatten() { + builder + .field_builder::(0) + .expect("Failed to get agent field builder") + .append_value(&acted_on_behalf_of.agent); + builder + .field_builder::(1) + .expect("Failed to get activity field builder") + .append_value(acted_on_behalf_of.activity); + builder + .field_builder::(2) + .expect("Failed to get role field builder") + .append_option(acted_on_behalf_of.role.as_deref()); + + builder.append(true); + } + + let values_array = builder.finish(); + + let data_type = DataType::new_list(agent_delegation_struct(), false); + let offsets_buffer = Buffer::from(offsets.to_byte_slice()); + + let list_array = ListArray::from( + ArrayData::builder(data_type) + .add_child_data(values_array.to_data()) + .len(offsets.len() - 1) + .null_count(0) + .add_buffer(offsets_buffer) + .build()?, + ); + + Ok(list_array) } fn agent_attributions_to_list_array( - agent_attributions: Vec>, + agent_attributions: Vec>, ) -> Result { - let offsets: Vec = std::iter::once(0) - .chain(agent_attributions.iter().map(|v| v.len() as i32)) - .scan(0, |state, len| { - *state += len; - Some(*state) - }) - .collect(); - - let entity_builder = StringBuilder::new(); - let role_builder = StringBuilder::new(); - - let fields = - vec![Field::new("entity", DataType::Utf8, false), Field::new("role", DataType::Utf8, true)]; - let field_builders = vec![ - Box::new(entity_builder) as Box, - Box::new(role_builder) as Box, - ]; - - let mut builder = StructBuilder::new(fields, field_builders); - - for agent_attribution in agent_attributions.into_iter().flatten() { - builder - .field_builder::(0) - .unwrap() - .append_value(agent_attribution.entity); - builder - .field_builder::(1) - .unwrap() - .append_option(agent_attribution.role.map(|r| r.to_string())); - - builder.append(true); - } - - let values_array = builder.finish(); - - let data_type = DataType::new_list(agent_attribution_struct(), false); - let offsets_buffer = Buffer::from(offsets.to_byte_slice()); - - let list_array = ListArray::from( - ArrayData::builder(data_type) - .add_child_data(values_array.to_data()) - .len(offsets.len() - 1) - .null_count(0) - .add_buffer(offsets_buffer) - .build()?, - ); - - Ok(list_array) + let offsets: Vec = std::iter::once(0) + .chain(agent_attributions.iter().map(|v| v.len() as i32)) + .scan(0, |state, len| { + *state += len; + Some(*state) + }) + .collect(); + + let entity_builder = StringBuilder::new(); + let role_builder = StringBuilder::new(); + + let fields = + vec![Field::new("entity", DataType::Utf8, false), Field::new("role", DataType::Utf8, true)]; + let field_builders = vec![ + Box::new(entity_builder) as Box, + Box::new(role_builder) as Box, + ]; + + let mut builder = StructBuilder::new(fields, field_builders); + + for agent_attribution in agent_attributions.into_iter().flatten() { + builder + .field_builder::(0) + .unwrap() + .append_value(agent_attribution.entity); + builder + .field_builder::(1) + .unwrap() + .append_option(agent_attribution.role.map(|r| r.to_string())); + + builder.append(true); + } + + let values_array = builder.finish(); + + let data_type = DataType::new_list(agent_attribution_struct(), false); + let offsets_buffer = Buffer::from(offsets.to_byte_slice()); + + let list_array = ListArray::from( + ArrayData::builder(data_type) + .add_child_data(values_array.to_data()) + .len(offsets.len() - 1) + .null_count(0) + .add_buffer(offsets_buffer) + .build()?, + ); + + Ok(list_array) } #[tracing::instrument(skip(pool))] pub fn load_agents_by_type( - pool: &Pool>, - typ: &Option, - position: u64, - max_records: u64, -) -> Result<(impl Iterator, u64, u64), ChronicleArrowError> { - let mut connection = pool.get().map_err(ChronicleArrowError::PoolError)?; - - let agents_and_namespaces: Vec<(Agent, Namespace)> = match typ { - Some(typ_value) => agent::table - .inner_join(namespace::table.on(agent::namespace_id.eq(namespace::id))) - .filter(agent::domaintype.eq(typ_value.external_id_part())) - .order(agent::id) - .select((Agent::as_select(), Namespace::as_select())) - .offset(position as i64) - .limit(max_records as i64) - .load(&mut connection)?, - None => agent::table - .inner_join(namespace::table.on(agent::namespace_id.eq(namespace::id))) - .filter(agent::domaintype.is_null()) - .order(agent::id) - .select((Agent::as_select(), Namespace::as_select())) - .offset(position as i64) - .limit(max_records as i64) - .load(&mut connection)?, - }; - - let total_records = agents_and_namespaces.len() as u64; - - let (agents, namespaces): (Vec, Vec) = - agents_and_namespaces.into_iter().unzip(); - - let mut attributions_map: HashMap> = - Attribution::belonging_to(&agents) - .inner_join(entity::table.on(attribution::entity_id.eq(entity::id))) - .select((attribution::agent_id, attribution::role, entity::external_id)) - .load::<(i32, Role, String)>(&mut connection)? - .into_iter() - .fold( - HashMap::new(), - |mut acc: HashMap>, (id, role, external_id)| { - acc.entry(id).or_default().push(AgentAttributionRef { - entity: external_id, - role: Some(role.to_string()), - }); - acc - }, - ); - - let mut delegations_map: HashMap> = - Delegation::belonging_to(&agents) - .inner_join(activity::table.on(delegation::activity_id.eq(activity::id))) - .inner_join(agent::table.on(delegation::delegate_id.eq(agent::id))) - .select(( - delegation::responsible_id, - delegation::role, - activity::external_id, - agent::external_id, - )) - .load::<(i32, Role, String, String)>(&mut connection)? - .into_iter() - .fold( - HashMap::new(), - |mut acc: HashMap>, (id, role, activity, delegate)| { - acc.entry(id).or_default().push(ActedOnBehalfOfRef { - agent: delegate, - activity, - role: Some(role.to_string()), - }); - acc - }, - ); - - let mut agents_and_references = vec![]; - - for (agent, ns) in agents.into_iter().zip(namespaces) { - agents_and_references.push(AgentAndReferences { - id: agent.external_id, - namespace_name: ns.external_id, - namespace_uuid: Uuid::parse_str(&ns.uuid)?.into_bytes(), - attributes: Attributes::new( - agent.domaintype.map(DomaintypeId::from_external_id), - vec![], - ), - was_attributed_to: attributions_map.remove(&agent.id).unwrap_or_default(), - acted_on_behalf_of: delegations_map.remove(&agent.id).unwrap_or_default(), - }); - } - - Ok((agents_and_references.into_iter(), total_records, total_records)) + pool: &Pool>, + typ: &Option, + position: u64, + max_records: u64, +) -> Result<(impl Iterator, u64, u64), ChronicleArrowError> { + let mut connection = pool.get().map_err(ChronicleArrowError::PoolError)?; + + let agents_and_namespaces: Vec<(Agent, Namespace)> = match typ { + Some(typ_value) => agent::table + .inner_join(namespace::table.on(agent::namespace_id.eq(namespace::id))) + .filter(agent::domaintype.eq(typ_value.external_id_part())) + .order(agent::id) + .select((Agent::as_select(), Namespace::as_select())) + .offset(position as i64) + .limit(max_records as i64) + .load(&mut connection)?, + None => agent::table + .inner_join(namespace::table.on(agent::namespace_id.eq(namespace::id))) + .filter(agent::domaintype.is_null()) + .order(agent::id) + .select((Agent::as_select(), Namespace::as_select())) + .offset(position as i64) + .limit(max_records as i64) + .load(&mut connection)?, + }; + + let total_records = agents_and_namespaces.len() as u64; + + let (agents, namespaces): (Vec, Vec) = + agents_and_namespaces.into_iter().unzip(); + + let mut attributions_map: HashMap> = + Attribution::belonging_to(&agents) + .inner_join(entity::table.on(attribution::entity_id.eq(entity::id))) + .select((attribution::agent_id, attribution::role, entity::external_id)) + .load::<(i32, Role, String)>(&mut connection)? + .into_iter() + .fold( + HashMap::new(), + |mut acc: HashMap>, (id, role, external_id)| { + acc.entry(id).or_default().push(AgentAttributionRef { + entity: external_id, + role: Some(role.to_string()), + }); + acc + }, + ); + + let mut delegations_map: HashMap> = + Delegation::belonging_to(&agents) + .inner_join(activity::table.on(delegation::activity_id.eq(activity::id))) + .inner_join(agent::table.on(delegation::delegate_id.eq(agent::id))) + .select(( + delegation::responsible_id, + delegation::role, + activity::external_id, + agent::external_id, + )) + .load::<(i32, Role, String, String)>(&mut connection)? + .into_iter() + .fold( + HashMap::new(), + |mut acc: HashMap>, (id, role, activity, delegate)| { + acc.entry(id).or_default().push(ActedOnBehalfOfRef { + agent: delegate, + activity, + role: Some(role.to_string()), + }); + acc + }, + ); + + let mut agents_and_references = vec![]; + + for (agent, ns) in agents.into_iter().zip(namespaces) { + agents_and_references.push(AgentAndReferences { + id: agent.external_id, + namespace_name: ns.external_id, + namespace_uuid: Uuid::parse_str(&ns.uuid)?.into_bytes(), + attributes: Attributes::new( + agent.domaintype.map(DomaintypeId::from_external_id), + vec![], + ), + was_attributed_to: attributions_map.remove(&agent.id).unwrap_or_default(), + acted_on_behalf_of: delegations_map.remove(&agent.id).unwrap_or_default(), + }); + } + + Ok((agents_and_references.into_iter(), total_records, total_records)) } diff --git a/crates/chronicle-arrow/src/query/entity.rs b/crates/chronicle-arrow/src/query/entity.rs index 8dfd0a2ad..bd3de62f4 100644 --- a/crates/chronicle-arrow/src/query/entity.rs +++ b/crates/chronicle-arrow/src/query/entity.rs @@ -1,31 +1,33 @@ use std::{collections::HashMap, sync::Arc}; -use crate::{ - meta::{attribution_struct, derivation_struct}, - ChronicleArrowError, DomainTypeMeta, -}; use arrow::array::{ArrayBuilder, StringBuilder, StructBuilder}; use arrow_array::{Array, BooleanArray, Int64Array, ListArray, RecordBatch, StringArray}; use arrow_buffer::{Buffer, ToByteSlice}; use arrow_data::ArrayData; use arrow_schema::{DataType, Field}; +use diesel::{ + pg::PgConnection, + prelude::*, + r2d2::{ConnectionManager, Pool}, +}; +use uuid::Uuid; + use chronicle_persistence::{ - query::{Attribution, Derivation, Entity, Generation, Namespace}, - schema::{ - activity, agent, attribution, derivation, entity, entity_attribute, generation, namespace, - }, + query::{Attribution, Derivation, Entity, Generation, Namespace}, + schema::{ + activity, agent, attribution, derivation, entity, entity_attribute, generation, namespace, + }, }; use common::{ - attributes::{Attribute, Attributes}, - domain::PrimitiveType, - prov::{operations::DerivationType, DomaintypeId, ExternalIdPart}, + attributes::{Attribute, Attributes}, + domain::PrimitiveType, + prov::{DomaintypeId, ExternalIdPart, operations::DerivationType}, }; -use diesel::{ - pg::PgConnection, - prelude::*, - r2d2::{ConnectionManager, Pool}, + +use crate::{ + ChronicleArrowError, + DomainTypeMeta, meta::{attribution_struct, derivation_struct}, }; -use uuid::Uuid; use super::vec_vec_string_to_list_array; @@ -33,446 +35,446 @@ use super::vec_vec_string_to_list_array; // may no longer be present in the domain definition #[tracing::instrument(skip(pool))] pub fn term_types( - pool: &Pool>, + pool: &Pool>, ) -> Result, ChronicleArrowError> { - let mut connection = pool.get()?; - let types = entity::table - .select(entity::domaintype) - .distinct() - .union(agent::table.select(agent::domaintype).distinct()) - .union(activity::table.select(activity::domaintype).distinct()) - .load::>(&mut connection)?; - - let mut unique_types = types.into_iter().collect::>(); - unique_types.sort(); - unique_types.dedup(); - - Ok(unique_types - .into_iter() - .filter_map(|x| x.map(DomaintypeId::from_external_id)) - .collect()) + let mut connection = pool.get()?; + let types = entity::table + .select(entity::domaintype) + .distinct() + .union(agent::table.select(agent::domaintype).distinct()) + .union(activity::table.select(activity::domaintype).distinct()) + .load::>(&mut connection)?; + + let mut unique_types = types.into_iter().collect::>(); + unique_types.sort(); + unique_types.dedup(); + + Ok(unique_types + .into_iter() + .filter_map(|x| x.map(DomaintypeId::from_external_id)) + .collect()) } pub fn entity_count_by_type( - pool: &Pool>, - typ: Vec<&str>, + pool: &Pool>, + typ: Vec<&str>, ) -> Result { - let mut connection = pool.get()?; - let count = entity::table - .filter(entity::domaintype.eq_any(typ)) - .count() - .get_result(&mut connection)?; - Ok(count) + let mut connection = pool.get()?; + let count = entity::table + .filter(entity::domaintype.eq_any(typ)) + .count() + .get_result(&mut connection)?; + Ok(count) } #[derive(Default, Debug)] pub struct DerivationRef { - pub source: String, - pub activity: String, + pub source: String, + pub activity: String, } #[derive(Default, Debug)] pub struct EntityAttributionRef { - pub agent: String, - pub role: Option, + pub agent: String, + pub role: Option, } #[derive(Default, Debug)] pub struct EntityAndReferences { - pub(crate) id: String, - pub(crate) namespace_name: String, - pub(crate) namespace_uuid: [u8; 16], - pub(crate) attributes: Attributes, - pub(crate) was_generated_by: Vec, - pub(crate) was_attributed_to: Vec, - pub(crate) was_derived_from: Vec, - pub(crate) had_primary_source: Vec, - pub(crate) was_quoted_from: Vec, - pub(crate) was_revision_of: Vec, + pub(crate) id: String, + pub(crate) namespace_name: String, + pub(crate) namespace_uuid: [u8; 16], + pub(crate) attributes: Attributes, + pub(crate) was_generated_by: Vec, + pub(crate) was_attributed_to: Vec, + pub(crate) was_derived_from: Vec, + pub(crate) had_primary_source: Vec, + pub(crate) was_quoted_from: Vec, + pub(crate) was_revision_of: Vec, } impl EntityAndReferences { - #[tracing::instrument(skip(items, meta))] - pub fn to_record_batch( - items: impl Iterator, - meta: &DomainTypeMeta, - ) -> Result { - let mut attributes_map: HashMap>)> = - HashMap::new(); - - for (attribute_name, primitive_type) in meta.attributes.iter() { - attributes_map.insert(attribute_name.clone(), (*primitive_type, vec![])); - } - - let mut id_vec = Vec::new(); - let mut namespace_name_vec = Vec::new(); - let mut namespace_uuid_vec = Vec::new(); - let mut was_generated_by_vec = Vec::new(); - let mut was_attributed_to_vec = Vec::new(); - let mut was_derived_from_vec = Vec::new(); - let mut had_primary_source_vec = Vec::new(); - let mut was_quoted_from_vec = Vec::new(); - let mut was_revision_of_vec = Vec::new(); - - for item in items { - id_vec.push(item.id); - namespace_name_vec.push(item.namespace_name); - namespace_uuid_vec.push(Uuid::from_bytes(item.namespace_uuid).to_string()); - was_generated_by_vec.push(item.was_generated_by); - was_attributed_to_vec.push(item.was_attributed_to); - was_derived_from_vec.push(item.was_derived_from); - had_primary_source_vec.push(item.had_primary_source); - was_quoted_from_vec.push(item.was_quoted_from); - was_revision_of_vec.push(item.was_revision_of); - for (key, (_primitive_type, values)) in attributes_map.iter_mut() { - if let Some(attribute) = item.attributes.get_attribute(key) { - values.push(Some(attribute.value.clone().into())); - } else { - values.push(None); - } - } - } - - let was_generated_by_array = vec_vec_string_to_list_array(was_generated_by_vec)?; - let was_attributed_to_array = attributions_to_list_array(was_attributed_to_vec)?; - let was_derived_from_array = derivations_to_list_array(was_derived_from_vec)?; - let had_primary_source_array = derivations_to_list_array(had_primary_source_vec)?; - let was_quoted_from_array = derivations_to_list_array(was_quoted_from_vec)?; - let was_revision_of_array = derivations_to_list_array(was_revision_of_vec)?; - - let mut fields = vec![ - ( - "namespace_name".to_string(), - Arc::new(StringArray::from(namespace_name_vec)) as Arc, - ), - ( - "namespace_uuid".to_string(), - Arc::new(StringArray::from(namespace_uuid_vec)) as Arc, - ), - ("id".to_string(), Arc::new(StringArray::from(id_vec)) as Arc), - ]; - // Dynamically generate fields for attribute key/values based on their primitive type - for (key, (primitive_type, values)) in attributes_map { - tracing::trace!("Key: {}, Primitive Type: {:?}", key, primitive_type); - let array: Arc = match primitive_type { - PrimitiveType::String => { - tracing::debug!("Converting String attribute values for key: {}", key); - Arc::new(StringArray::from_iter( - values.iter().map(|v| v.as_ref().map(|v| v.as_str()).unwrap_or_default()), - )) as Arc - }, - PrimitiveType::Int => { - tracing::debug!("Converting Int attribute values for key: {}", key); - Arc::new(Int64Array::from_iter( - values.iter().map(|v| v.as_ref().map(|v| v.as_i64()).unwrap_or_default()), - )) as Arc - }, - PrimitiveType::Bool => { - tracing::debug!("Converting Bool attribute values for key: {}", key); - Arc::new(BooleanArray::from_iter( - values.iter().map(|v| v.as_ref().map(|v| v.as_bool()).unwrap_or_default()), - )) as Arc - }, - _ => { - tracing::warn!("Unsupported attribute primitive type for key: {}", key); - continue; - }, - }; - fields.push((key, array as Arc)); - } - - fields.extend(vec![ - ( - "was_generated_by".to_string(), - Arc::new(was_generated_by_array) as Arc, - ), - ( - "was_attributed_to".to_string(), - Arc::new(was_attributed_to_array) as Arc, - ), - ( - "was_derived_from".to_string(), - Arc::new(was_derived_from_array) as Arc, - ), - ( - "had_primary_source".to_string(), - Arc::new(had_primary_source_array) as Arc, - ), - ( - "was_quoted_from".to_string(), - Arc::new(was_quoted_from_array) as Arc, - ), - ( - "was_revision_of".to_string(), - Arc::new(was_revision_of_array) as Arc, - ), - ]); - - let hashed_fields = fields.into_iter().collect::>(); - - let mut columns = Vec::new(); - - for field in meta.schema.fields() { - let field_name = field.name(); - match hashed_fields.get(field_name) { - Some(array) => columns.push(array.clone()), - None => - return Err(ChronicleArrowError::SchemaFieldNotFound(field_name.to_string())), - } - } - - RecordBatch::try_new(meta.schema.clone(), columns).map_err(ChronicleArrowError::from) - } + #[tracing::instrument(skip(items, meta))] + pub fn to_record_batch( + items: impl Iterator, + meta: &DomainTypeMeta, + ) -> Result { + let mut attributes_map: HashMap>)> = + HashMap::new(); + + for (attribute_name, primitive_type) in meta.attributes.iter() { + attributes_map.insert(attribute_name.clone(), (*primitive_type, vec![])); + } + + let mut id_vec = Vec::new(); + let mut namespace_name_vec = Vec::new(); + let mut namespace_uuid_vec = Vec::new(); + let mut was_generated_by_vec = Vec::new(); + let mut was_attributed_to_vec = Vec::new(); + let mut was_derived_from_vec = Vec::new(); + let mut had_primary_source_vec = Vec::new(); + let mut was_quoted_from_vec = Vec::new(); + let mut was_revision_of_vec = Vec::new(); + + for item in items { + id_vec.push(item.id); + namespace_name_vec.push(item.namespace_name); + namespace_uuid_vec.push(Uuid::from_bytes(item.namespace_uuid).to_string()); + was_generated_by_vec.push(item.was_generated_by); + was_attributed_to_vec.push(item.was_attributed_to); + was_derived_from_vec.push(item.was_derived_from); + had_primary_source_vec.push(item.had_primary_source); + was_quoted_from_vec.push(item.was_quoted_from); + was_revision_of_vec.push(item.was_revision_of); + for (key, (_primitive_type, values)) in attributes_map.iter_mut() { + if let Some(attribute) = item.attributes.get_attribute(key) { + values.push(Some(attribute.value.clone().into())); + } else { + values.push(None); + } + } + } + + let was_generated_by_array = vec_vec_string_to_list_array(was_generated_by_vec)?; + let was_attributed_to_array = attributions_to_list_array(was_attributed_to_vec)?; + let was_derived_from_array = derivations_to_list_array(was_derived_from_vec)?; + let had_primary_source_array = derivations_to_list_array(had_primary_source_vec)?; + let was_quoted_from_array = derivations_to_list_array(was_quoted_from_vec)?; + let was_revision_of_array = derivations_to_list_array(was_revision_of_vec)?; + + let mut fields = vec![ + ( + "namespace_name".to_string(), + Arc::new(StringArray::from(namespace_name_vec)) as Arc, + ), + ( + "namespace_uuid".to_string(), + Arc::new(StringArray::from(namespace_uuid_vec)) as Arc, + ), + ("id".to_string(), Arc::new(StringArray::from(id_vec)) as Arc), + ]; + // Dynamically generate fields for attribute key/values based on their primitive type + for (key, (primitive_type, values)) in attributes_map { + tracing::trace!("Key: {}, Primitive Type: {:?}", key, primitive_type); + let array: Arc = match primitive_type { + PrimitiveType::String => { + tracing::debug!("Converting String attribute values for key: {}", key); + Arc::new(StringArray::from_iter( + values.iter().map(|v| v.as_ref().map(|v| v.as_str()).unwrap_or_default()), + )) as Arc + } + PrimitiveType::Int => { + tracing::debug!("Converting Int attribute values for key: {}", key); + Arc::new(Int64Array::from_iter( + values.iter().map(|v| v.as_ref().map(|v| v.as_i64()).unwrap_or_default()), + )) as Arc + } + PrimitiveType::Bool => { + tracing::debug!("Converting Bool attribute values for key: {}", key); + Arc::new(BooleanArray::from_iter( + values.iter().map(|v| v.as_ref().map(|v| v.as_bool()).unwrap_or_default()), + )) as Arc + } + _ => { + tracing::warn!("Unsupported attribute primitive type for key: {}", key); + continue; + } + }; + fields.push((key, array as Arc)); + } + + fields.extend(vec![ + ( + "was_generated_by".to_string(), + Arc::new(was_generated_by_array) as Arc, + ), + ( + "was_attributed_to".to_string(), + Arc::new(was_attributed_to_array) as Arc, + ), + ( + "was_derived_from".to_string(), + Arc::new(was_derived_from_array) as Arc, + ), + ( + "had_primary_source".to_string(), + Arc::new(had_primary_source_array) as Arc, + ), + ( + "was_quoted_from".to_string(), + Arc::new(was_quoted_from_array) as Arc, + ), + ( + "was_revision_of".to_string(), + Arc::new(was_revision_of_array) as Arc, + ), + ]); + + let hashed_fields = fields.into_iter().collect::>(); + + let mut columns = Vec::new(); + + for field in meta.schema.fields() { + let field_name = field.name(); + match hashed_fields.get(field_name) { + Some(array) => columns.push(array.clone()), + None => + return Err(ChronicleArrowError::SchemaFieldNotFound(field_name.to_string())), + } + } + + RecordBatch::try_new(meta.schema.clone(), columns).map_err(ChronicleArrowError::from) + } } fn derivations_to_list_array( - derivations: Vec>, + derivations: Vec>, ) -> Result { - let offsets: Vec = std::iter::once(0) - .chain(derivations.iter().map(|v| v.len() as i32)) - .scan(0, |state, len| { - *state += len; - Some(*state) - }) - .collect(); - - let fields = vec![ - Field::new("source", DataType::Utf8, false), - Field::new("activity", DataType::Utf8, false), - ]; - let field_builders = vec![ - Box::new(StringBuilder::new()) as Box, - Box::new(StringBuilder::new()) as Box, - ]; - - let mut builder = StructBuilder::new(fields, field_builders); - - for derivation in derivations.into_iter().flatten() { - builder - .field_builder::(0) - .unwrap() - .append_value(derivation.source); - builder - .field_builder::(1) - .unwrap() - .append_value(derivation.activity); - - builder.append(true) - } - - let values_array = builder.finish(); - - let data_type = DataType::new_list(derivation_struct(), false); - let offsets_buffer = Buffer::from(offsets.to_byte_slice()); - - let list_array = ListArray::from( - ArrayData::builder(data_type) - .add_child_data(values_array.to_data()) - .len(offsets.len() - 1) - .null_count(0) - .add_buffer(offsets_buffer) - .build()?, - ); - - Ok(list_array) + let offsets: Vec = std::iter::once(0) + .chain(derivations.iter().map(|v| v.len() as i32)) + .scan(0, |state, len| { + *state += len; + Some(*state) + }) + .collect(); + + let fields = vec![ + Field::new("source", DataType::Utf8, false), + Field::new("activity", DataType::Utf8, false), + ]; + let field_builders = vec![ + Box::new(StringBuilder::new()) as Box, + Box::new(StringBuilder::new()) as Box, + ]; + + let mut builder = StructBuilder::new(fields, field_builders); + + for derivation in derivations.into_iter().flatten() { + builder + .field_builder::(0) + .unwrap() + .append_value(derivation.source); + builder + .field_builder::(1) + .unwrap() + .append_value(derivation.activity); + + builder.append(true) + } + + let values_array = builder.finish(); + + let data_type = DataType::new_list(derivation_struct(), false); + let offsets_buffer = Buffer::from(offsets.to_byte_slice()); + + let list_array = ListArray::from( + ArrayData::builder(data_type) + .add_child_data(values_array.to_data()) + .len(offsets.len() - 1) + .null_count(0) + .add_buffer(offsets_buffer) + .build()?, + ); + + Ok(list_array) } fn attributions_to_list_array( - attributions: Vec>, + attributions: Vec>, ) -> Result { - let offsets: Vec = std::iter::once(0) - .chain(attributions.iter().map(|v| v.len() as i32)) - .scan(0, |state, len| { - *state += len; - Some(*state) - }) - .collect(); - - let agent_builder = StringBuilder::new(); - let role_builder = StringBuilder::new(); - - let fields = - vec![Field::new("agent", DataType::Utf8, false), Field::new("role", DataType::Utf8, true)]; - let field_builders = vec![ - Box::new(agent_builder) as Box, - Box::new(role_builder) as Box, - ]; - - let mut builder = StructBuilder::new(fields, field_builders); - - for attribution in attributions.into_iter().flatten() { - builder - .field_builder::(0) - .unwrap() - .append_value(attribution.agent); - builder - .field_builder::(1) - .unwrap() - .append_option(attribution.role); - - builder.append(true) - } - - let values_array = builder.finish(); - - let data_type = DataType::new_list(attribution_struct(), false); - let offsets_buffer = Buffer::from(offsets.to_byte_slice()); - - let list_array = ListArray::from( - ArrayData::builder(data_type) - .add_child_data(values_array.to_data()) - .len(offsets.len() - 1) - .null_count(0) - .add_buffer(offsets_buffer) - .build()?, - ); - - Ok(list_array) + let offsets: Vec = std::iter::once(0) + .chain(attributions.iter().map(|v| v.len() as i32)) + .scan(0, |state, len| { + *state += len; + Some(*state) + }) + .collect(); + + let agent_builder = StringBuilder::new(); + let role_builder = StringBuilder::new(); + + let fields = + vec![Field::new("agent", DataType::Utf8, false), Field::new("role", DataType::Utf8, true)]; + let field_builders = vec![ + Box::new(agent_builder) as Box, + Box::new(role_builder) as Box, + ]; + + let mut builder = StructBuilder::new(fields, field_builders); + + for attribution in attributions.into_iter().flatten() { + builder + .field_builder::(0) + .unwrap() + .append_value(attribution.agent); + builder + .field_builder::(1) + .unwrap() + .append_option(attribution.role); + + builder.append(true) + } + + let values_array = builder.finish(); + + let data_type = DataType::new_list(attribution_struct(), false); + let offsets_buffer = Buffer::from(offsets.to_byte_slice()); + + let list_array = ListArray::from( + ArrayData::builder(data_type) + .add_child_data(values_array.to_data()) + .len(offsets.len() - 1) + .null_count(0) + .add_buffer(offsets_buffer) + .build()?, + ); + + Ok(list_array) } // Returns a tuple of an iterator over entities of the specified domain types and their relations, // the number of returned records and the total number of records #[tracing::instrument(skip(pool))] pub fn load_entities_by_type( - pool: &Pool>, - typ: &Option, - attributes: &Vec<(String, PrimitiveType)>, - position: u64, - max_records: u64, -) -> Result<(impl Iterator, u64, u64), ChronicleArrowError> { - let mut connection = pool.get()?; - - let mut entities_and_references = Vec::new(); - - let entities_and_namespaces: Vec<(Entity, Namespace)> = if let Some(typ_value) = typ { - entity::table - .inner_join(namespace::table.on(entity::namespace_id.eq(namespace::id))) - .filter(entity::domaintype.eq(typ_value.external_id_part())) - .order(entity::id) - .select((Entity::as_select(), Namespace::as_select())) - .offset(position as i64) - .limit(max_records as i64) - .load::<(Entity, Namespace)>(&mut connection)? - } else { - entity::table - .inner_join(namespace::table.on(entity::namespace_id.eq(namespace::id))) - .filter(entity::domaintype.is_null()) - .order(entity::id) - .select((Entity::as_select(), Namespace::as_select())) - .offset(position as i64) - .limit(max_records as i64) - .load::<(Entity, Namespace)>(&mut connection)? - }; - - let (entities, namespaces): (Vec, Vec) = - entities_and_namespaces.into_iter().unzip(); - - let entity_ids: Vec = entities.iter().map(|entity| entity.id).collect(); - let attribute_names: Vec = attributes.iter().map(|(name, _)| name.clone()).collect(); - - let loaded_attributes: Vec<(i32, String, serde_json::Value)> = entity_attribute::table - .filter(entity_attribute::entity_id.eq_any(&entity_ids)) - .filter(entity_attribute::typename.eq_any(&attribute_names)) - .select((entity_attribute::entity_id, entity_attribute::typename, entity_attribute::value)) - .load::<(i32, String, String)>(&mut connection)? - .into_iter() - .map(|(entity_id, typename, value)| { - let parsed_value: serde_json::Value = serde_json::from_str(&value).unwrap_or_default(); - (entity_id, typename, parsed_value) - }) - .collect(); - - let mut attributes_map: HashMap> = HashMap::new(); - for (entity_id, typename, value) in loaded_attributes { - let attribute = Attribute::new(&typename, value); - attributes_map.entry(entity_id).or_default().push(attribute); - } - - let fetched_records: u64 = entities.len() as u64; - // Load generations - let mut generation_map: HashMap> = Generation::belonging_to(&entities) - .inner_join(activity::table) - .select((generation::generated_entity_id, activity::external_id)) - .load::<(i32, String)>(&mut connection)? - .into_iter() - .fold(HashMap::new(), |mut acc: HashMap>, (id, external_id)| { - acc.entry(id).or_default().push(external_id); - acc - }); - - let mut attribution_map: HashMap> = Attribution::belonging_to(&entities) - .inner_join(agent::table) - .select((attribution::agent_id, agent::external_id, attribution::role.nullable())) - .load::<(i32, String, Option)>(&mut connection)? - .into_iter() - .fold(HashMap::new(), |mut acc: HashMap>, (id, external_id, role)| { - acc.entry(id) - .or_default() - .push(EntityAttributionRef { agent: external_id, role }); - acc - }); - - let mut derivation_map: HashMap<(i32, DerivationType), Vec<_>> = - Derivation::belonging_to(&entities) - .inner_join(activity::table.on(derivation::activity_id.eq(activity::id))) - .inner_join(entity::table.on(derivation::used_entity_id.eq(entity::id))) - .select(( - derivation::used_entity_id, - activity::external_id, - entity::external_id, - derivation::typ, - )) - .load::<(i32, String, String, i32)>(&mut connection)? - .into_iter() - .map(|(entity_id, activity_external_id, entity_external_id, derivation_type)| { - DerivationType::try_from(derivation_type) - .map(|derivation_type| { - (entity_id, activity_external_id, entity_external_id, derivation_type) - }) - .map_err(|e| ChronicleArrowError::InvalidValue(e.to_string())) - }) - .collect::, ChronicleArrowError>>()? - .into_iter() - .fold( - HashMap::new(), - |mut acc: HashMap<(i32, DerivationType), Vec<_>>, - (entity_id, activity_external_id, entity_external_id, derivation_type)| { - acc.entry((entity_id, derivation_type)).or_default().push(DerivationRef { - activity: activity_external_id, - source: entity_external_id, - }); - acc - }, - ); - - for (entity, ns) in entities.into_iter().zip(namespaces) { - let entity_id = entity.id; - entities_and_references.push(EntityAndReferences { - id: entity.external_id, - namespace_name: ns.external_id, - namespace_uuid: Uuid::parse_str(&ns.uuid)?.into_bytes(), - attributes: Attributes::new( - entity.domaintype.map(DomaintypeId::from_external_id), - attributes_map.remove(&entity_id).unwrap_or_default(), - ), - was_generated_by: generation_map.remove(&entity_id).unwrap_or_default(), - was_attributed_to: attribution_map.remove(&entity_id).unwrap_or_default(), - was_derived_from: derivation_map - .remove(&(entity_id, DerivationType::None)) - .unwrap_or_default(), - was_quoted_from: derivation_map - .remove(&(entity_id, DerivationType::Quotation)) - .unwrap_or_default(), - had_primary_source: derivation_map - .remove(&(entity_id, DerivationType::PrimarySource)) - .unwrap_or_default(), - was_revision_of: derivation_map - .remove(&(entity_id, DerivationType::Revision)) - .unwrap_or_default(), - }); - } - - tracing::debug!(?fetched_records); - - Ok((entities_and_references.into_iter(), fetched_records, fetched_records)) + pool: &Pool>, + typ: &Option, + attributes: &Vec<(String, PrimitiveType)>, + position: u64, + max_records: u64, +) -> Result<(impl Iterator, u64, u64), ChronicleArrowError> { + let mut connection = pool.get()?; + + let mut entities_and_references = Vec::new(); + + let entities_and_namespaces: Vec<(Entity, Namespace)> = if let Some(typ_value) = typ { + entity::table + .inner_join(namespace::table.on(entity::namespace_id.eq(namespace::id))) + .filter(entity::domaintype.eq(typ_value.external_id_part())) + .order(entity::id) + .select((Entity::as_select(), Namespace::as_select())) + .offset(position as i64) + .limit(max_records as i64) + .load::<(Entity, Namespace)>(&mut connection)? + } else { + entity::table + .inner_join(namespace::table.on(entity::namespace_id.eq(namespace::id))) + .filter(entity::domaintype.is_null()) + .order(entity::id) + .select((Entity::as_select(), Namespace::as_select())) + .offset(position as i64) + .limit(max_records as i64) + .load::<(Entity, Namespace)>(&mut connection)? + }; + + let (entities, namespaces): (Vec, Vec) = + entities_and_namespaces.into_iter().unzip(); + + let entity_ids: Vec = entities.iter().map(|entity| entity.id).collect(); + let attribute_names: Vec = attributes.iter().map(|(name, _)| name.clone()).collect(); + + let loaded_attributes: Vec<(i32, String, serde_json::Value)> = entity_attribute::table + .filter(entity_attribute::entity_id.eq_any(&entity_ids)) + .filter(entity_attribute::typename.eq_any(&attribute_names)) + .select((entity_attribute::entity_id, entity_attribute::typename, entity_attribute::value)) + .load::<(i32, String, String)>(&mut connection)? + .into_iter() + .map(|(entity_id, typename, value)| { + let parsed_value: serde_json::Value = serde_json::from_str(&value).unwrap_or_default(); + (entity_id, typename, parsed_value) + }) + .collect(); + + let mut attributes_map: HashMap> = HashMap::new(); + for (entity_id, typename, value) in loaded_attributes { + let attribute = Attribute::new(&typename, value); + attributes_map.entry(entity_id).or_default().push(attribute); + } + + let fetched_records: u64 = entities.len() as u64; + // Load generations + let mut generation_map: HashMap> = Generation::belonging_to(&entities) + .inner_join(activity::table) + .select((generation::generated_entity_id, activity::external_id)) + .load::<(i32, String)>(&mut connection)? + .into_iter() + .fold(HashMap::new(), |mut acc: HashMap>, (id, external_id)| { + acc.entry(id).or_default().push(external_id); + acc + }); + + let mut attribution_map: HashMap> = Attribution::belonging_to(&entities) + .inner_join(agent::table) + .select((attribution::agent_id, agent::external_id, attribution::role.nullable())) + .load::<(i32, String, Option)>(&mut connection)? + .into_iter() + .fold(HashMap::new(), |mut acc: HashMap>, (id, external_id, role)| { + acc.entry(id) + .or_default() + .push(EntityAttributionRef { agent: external_id, role }); + acc + }); + + let mut derivation_map: HashMap<(i32, DerivationType), Vec<_>> = + Derivation::belonging_to(&entities) + .inner_join(activity::table.on(derivation::activity_id.eq(activity::id))) + .inner_join(entity::table.on(derivation::used_entity_id.eq(entity::id))) + .select(( + derivation::used_entity_id, + activity::external_id, + entity::external_id, + derivation::typ, + )) + .load::<(i32, String, String, i32)>(&mut connection)? + .into_iter() + .map(|(entity_id, activity_external_id, entity_external_id, derivation_type)| { + DerivationType::try_from(derivation_type) + .map(|derivation_type| { + (entity_id, activity_external_id, entity_external_id, derivation_type) + }) + .map_err(|e| ChronicleArrowError::InvalidValue(e.to_string())) + }) + .collect::, ChronicleArrowError>>()? + .into_iter() + .fold( + HashMap::new(), + |mut acc: HashMap<(i32, DerivationType), Vec<_>>, + (entity_id, activity_external_id, entity_external_id, derivation_type)| { + acc.entry((entity_id, derivation_type)).or_default().push(DerivationRef { + activity: activity_external_id, + source: entity_external_id, + }); + acc + }, + ); + + for (entity, ns) in entities.into_iter().zip(namespaces) { + let entity_id = entity.id; + entities_and_references.push(EntityAndReferences { + id: entity.external_id, + namespace_name: ns.external_id, + namespace_uuid: Uuid::parse_str(&ns.uuid)?.into_bytes(), + attributes: Attributes::new( + entity.domaintype.map(DomaintypeId::from_external_id), + attributes_map.remove(&entity_id).unwrap_or_default(), + ), + was_generated_by: generation_map.remove(&entity_id).unwrap_or_default(), + was_attributed_to: attribution_map.remove(&entity_id).unwrap_or_default(), + was_derived_from: derivation_map + .remove(&(entity_id, DerivationType::None)) + .unwrap_or_default(), + was_quoted_from: derivation_map + .remove(&(entity_id, DerivationType::Quotation)) + .unwrap_or_default(), + had_primary_source: derivation_map + .remove(&(entity_id, DerivationType::PrimarySource)) + .unwrap_or_default(), + was_revision_of: derivation_map + .remove(&(entity_id, DerivationType::Revision)) + .unwrap_or_default(), + }); + } + + tracing::debug!(?fetched_records); + + Ok((entities_and_references.into_iter(), fetched_records, fetched_records)) } diff --git a/crates/chronicle-arrow/src/query/mod.rs b/crates/chronicle-arrow/src/query/mod.rs index d7d170027..ddb573221 100644 --- a/crates/chronicle-arrow/src/query/mod.rs +++ b/crates/chronicle-arrow/src/query/mod.rs @@ -1,43 +1,45 @@ -mod activity; -mod agent; -mod entity; -pub use activity::*; -pub use agent::*; -pub use entity::*; - use std::sync::Arc; -use crate::ChronicleArrowError; use arrow_array::{Array, ListArray, StringArray}; use arrow_buffer::{Buffer, ToByteSlice}; use arrow_data::ArrayData; use arrow_schema::DataType; +pub use activity::*; +pub use agent::*; +pub use entity::*; + +use crate::ChronicleArrowError; + +mod activity; +mod agent; +mod entity; + // For simple id only relations, we can just reuse this mapping fn vec_vec_string_to_list_array( - vec_vec_string: Vec>, + vec_vec_string: Vec>, ) -> Result { - let offsets: Vec = std::iter::once(0) - .chain(vec_vec_string.iter().map(|v| v.len() as i32)) - .scan(0, |state, len| { - *state += len; - Some(*state) - }) - .collect(); - let values: Vec = vec_vec_string.into_iter().flatten().collect(); + let offsets: Vec = std::iter::once(0) + .chain(vec_vec_string.iter().map(|v| v.len() as i32)) + .scan(0, |state, len| { + *state += len; + Some(*state) + }) + .collect(); + let values: Vec = vec_vec_string.into_iter().flatten().collect(); - let values_array = Arc::new(StringArray::from(values)) as Arc; - // Create an OffsetBuffer from the offsets - let offsets_buffer = Buffer::from(offsets.to_byte_slice()); - let data_type = DataType::new_list(DataType::Utf8, false); - let list_array = ListArray::from( - ArrayData::builder(data_type) - .add_child_data(values_array.to_data()) - .len(offsets.len() - 1) - .null_count(0) - .add_buffer(offsets_buffer) - .build()?, - ); + let values_array = Arc::new(StringArray::from(values)) as Arc; + // Create an OffsetBuffer from the offsets + let offsets_buffer = Buffer::from(offsets.to_byte_slice()); + let data_type = DataType::new_list(DataType::Utf8, false); + let list_array = ListArray::from( + ArrayData::builder(data_type) + .add_child_data(values_array.to_data()) + .len(offsets.len() - 1) + .null_count(0) + .add_buffer(offsets_buffer) + .build()?, + ); - Ok(list_array) + Ok(list_array) } diff --git a/crates/chronicle-arrow/tracing-flamegraph.svg b/crates/chronicle-arrow/tracing-flamegraph.svg index a19606892..49416e02e 100644 --- a/crates/chronicle-arrow/tracing-flamegraph.svg +++ b/crates/chronicle-arrow/tracing-flamegraph.svg @@ -1 +1,6 @@ -ERROR: No valid input provided to flamegraph \ No newline at end of file + + + ERROR: No valid input provided to flamegraph + \ No newline at end of file diff --git a/crates/chronicle-data/Cargo.toml b/crates/chronicle-data/Cargo.toml index 8d640d61f..da124234a 100644 --- a/crates/chronicle-data/Cargo.toml +++ b/crates/chronicle-data/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "chronicle-data" +name = "chronicle-data" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -11,11 +11,10 @@ arrow-data = { version = "50" } arrow-flight = { version = "50" } arrow-ipc = { version = "50" } arrow-schema = { version = "50" } -clap = { workspace = true } -clap_complete = { workspace = true } +clap = { version = "^4" } prettytable-rs = "^0.10" tokio = { workspace = true } tonic = { version = "0.10.2", default-features = false, features = [ - "transport", - "prost", + "transport", + "prost", ] } diff --git a/crates/chronicle-data/src/cli.rs b/crates/chronicle-data/src/cli.rs index 47a6ab3ec..256d9d624 100644 --- a/crates/chronicle-data/src/cli.rs +++ b/crates/chronicle-data/src/cli.rs @@ -1,39 +1,35 @@ -use clap::{Arg, Command}; -fn in_subcommand() -> Command<'static> { - Command::new("in").about("Handles incoming data operations") -} +use clap::{Parser, Subcommand}; + +#[derive(Parser)] +#[clap(name = "chronicle-data", about = "CLI for Chronicle Data operations")] +pub struct Cli { + #[arg(long, help = "The Chronicle server URL", global = true, required = true)] + pub chronicle: String, + + #[arg(long, help = "Authentication token", global = true, required = false)] + pub auth: Option, -fn out_subcommand() -> Command<'static> { - Command::new("out").about("Handles outgoing data operations") + #[clap(subcommand)] + pub command: Commands, } -fn describe_subcommand() -> Command<'static> { - Command::new("describe") - .about("Describes the data schema and operations") - .subcommand(Command::new("schema").about("Describes the data schema")) - .subcommand(Command::new("flights").about("List the available flights")) +#[derive(Subcommand)] +pub enum Commands { + #[clap(about = "Describes the data schema and operations")] + Describe { + #[clap(subcommand)] + subcommand: DescribeSubcommands, + }, + #[clap(about = "Handles incoming data operations")] + In, + #[clap(about = "Handles outgoing data operations")] + Out, } -pub fn build_cli() -> Command<'static> { - Command::new("chronicle-data") - .about("CLI for Chronicle Data operations") - .arg( - Arg::new("chronicle") - .long("chronicle") - .help("The Chronicle server URL") - .takes_value(true) - .global(true) - .required(true), - ) - .arg( - Arg::new("auth") - .long("auth") - .help("Authentication token") - .takes_value(true) - .global(true) - .required(false), - ) - .subcommand(describe_subcommand()) - .subcommand(in_subcommand()) - .subcommand(out_subcommand()) +#[derive(Subcommand)] +pub enum DescribeSubcommands { + #[clap(about = "Describes the data schema")] + Schema, + #[clap(about = "List the available flights")] + Flights, } diff --git a/crates/chronicle-data/src/main.rs b/crates/chronicle-data/src/main.rs index 2506ffbd7..d831c7979 100644 --- a/crates/chronicle-data/src/main.rs +++ b/crates/chronicle-data/src/main.rs @@ -1,87 +1,80 @@ -mod cli; - use arrow_flight::flight_service_client::FlightServiceClient; +use arrow_flight::FlightInfo; +use arrow_schema::Schema; +use clap::Parser; +use cli::{Cli, Commands, DescribeSubcommands}; +use prettytable::{Cell, format, row, Row, Table}; use tonic::transport::Channel; +mod cli; + async fn init_flight_client( - matches: &clap::ArgMatches, + cli: &Cli, ) -> Result, Box> { - let chronicle_url = matches - .value_of("chronicle") - .expect("Chronicle server URL is required") - .to_string(); - let channel = Channel::from_shared(chronicle_url)?.connect().await?; + let chronicle_url = &cli.chronicle; + let channel = Channel::from_shared(chronicle_url.clone())?.connect().await?; - Ok(FlightServiceClient::new(channel)) + Ok(FlightServiceClient::new(channel)) } -use arrow_schema::Schema; -use prettytable::{format, row, Cell, Row, Table}; - fn format_schema_as_table(schema: &Schema) -> String { - let mut table = Table::new(); - table.add_row(row!["Field Name", "Data Type", "Nullable"]); - for field in schema.fields() { - table.add_row(Row::new(vec![ - Cell::new(field.name()), - Cell::new(&format!("{:?}", field.data_type())), - Cell::new(&format!("{}", field.is_nullable())), - ])); - } - table.to_string() + let mut table = Table::new(); + table.add_row(row!["Field Name", "Data Type", "Nullable"]); + for field in schema.fields() { + table.add_row(Row::new(vec![ + Cell::new(field.name()), + Cell::new(&format!("{:?}", field.data_type())), + Cell::new(&format!("{}", field.is_nullable())), + ])); + } + table.to_string() } -use arrow_flight::FlightInfo; - -fn format_flight_info_as_table(flight_infos: Vec) -> String { - let mut table = Table::new(); - table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE); - - table.set_titles(row!["Descriptor", "Endpoints", "Summary"]); +fn format_flight_info_as_table(_flight_infos: Vec) -> String { + let mut table = Table::new(); + table.set_format(*format::consts::FORMAT_NO_LINESEP_WITH_TITLE); - let grouped_by_descriptor: std::collections::HashMap> = - std::collections::HashMap::new(); + table.set_titles(row!["Descriptor", "Endpoints", "Summary"]); - table.to_string() + table.to_string() } async fn list_flights( - client: &mut FlightServiceClient, + client: &mut FlightServiceClient, ) -> Result, Box> { - let request = tonic::Request::new(arrow_flight::Criteria::default()); - let response = client.list_flights(request).await?; + let request = tonic::Request::new(arrow_flight::Criteria::default()); + let response = client.list_flights(request).await?; - let mut flights_info = Vec::new(); - let mut stream = response.into_inner(); - while let Some(flight_info) = stream.message().await? { - flights_info.push(flight_info); - } + let mut flights_info = Vec::new(); + let mut stream = response.into_inner(); + while let Some(flight_info) = stream.message().await? { + flights_info.push(flight_info); + } - Ok(flights_info) + Ok(flights_info) } #[tokio::main] async fn main() { - let matches = cli::build_cli().get_matches(); - let client = init_flight_client(&matches) - .await - .expect("Failed to initialize the Flight client"); + let cli = Cli::parse(); + let _client = init_flight_client(&cli) + .await + .expect("Failed to initialize the Flight client"); - if let Some(subcommand) = matches.subcommand() { - match subcommand { - ("describe", sub_matches) => - if sub_matches.subcommand_matches("schema").is_some() { - println!("Describing the data schema..."); - } else if sub_matches.subcommand_matches("flights").is_some() { - println!("Listing available flights..."); - }, - ("in", _) => { - println!("Handling incoming data operations..."); - }, - ("out", _) => { - println!("Handling outgoing data operations..."); - }, - _ => unreachable!(), - } - } + match &cli.command { + Commands::Describe { subcommand } => match subcommand { + DescribeSubcommands::Schema => { + println!("Describing the data schema..."); + } + DescribeSubcommands::Flights => { + println!("Listing available flights..."); + } + }, + Commands::In => { + println!("Handling incoming data operations..."); + } + Commands::Out => { + println!("Handling outgoing data operations..."); + } + } } diff --git a/crates/chronicle-domain-lint/Cargo.toml b/crates/chronicle-domain-lint/Cargo.toml index 4261e6d58..c68daf36b 100644 --- a/crates/chronicle-domain-lint/Cargo.toml +++ b/crates/chronicle-domain-lint/Cargo.toml @@ -1,9 +1,9 @@ [package] -build = "build.rs" +build = "build.rs" edition = "2021" -name = "chronicle-domain-lint" +name = "chronicle-domain-lint" version = "0.7.6" [dependencies] chronicle = { path = "../chronicle" } -clap = { workspace = true } +clap = { workspace = true } diff --git a/crates/chronicle-domain-lint/build.rs b/crates/chronicle-domain-lint/build.rs index afb2c9546..5a1d86bbe 100644 --- a/crates/chronicle-domain-lint/build.rs +++ b/crates/chronicle-domain-lint/build.rs @@ -1,8 +1,8 @@ fn main() { - //Create a .VERSION file containing 'local' if it does not exist + //Create a .VERSION file containing 'local' if it does not exist - let version_file = std::path::Path::new("../../.VERSION"); - if !version_file.exists() { - std::fs::write(version_file, "local").expect("Unable to write file"); - } + let version_file = std::path::Path::new("../../.VERSION"); + if !version_file.exists() { + std::fs::write(version_file, "local").expect("Unable to write file"); + } } diff --git a/crates/chronicle-domain-lint/src/main.rs b/crates/chronicle-domain-lint/src/main.rs index 35086d199..ac3628b7f 100644 --- a/crates/chronicle-domain-lint/src/main.rs +++ b/crates/chronicle-domain-lint/src/main.rs @@ -2,21 +2,21 @@ use chronicle::codegen::linter::check_files; use clap::{Arg, Command, ValueHint}; fn main() { - let version = env!("CARGO_PKG_VERSION"); - let cli = Command::new("chronicle-domain-lint") - .version(version) - .author("Blockchain Technology Partners") - .arg( - Arg::new("filenames") - .value_hint(ValueHint::FilePath) - .required(true) - .multiple_values(true) - .min_values(1) - .help("domain definition files for linting"), - ); + let version = env!("CARGO_PKG_VERSION"); + let cli = Command::new("chronicle-domain-lint") + .version(version) + .author("Blockchain Technology Partners") + .arg( + Arg::new("filenames") + .value_hint(ValueHint::FilePath) + .required(true) + .multiple_values(true) + .min_values(1) + .help("domain definition files for linting"), + ); - let matches = cli.get_matches(); - let filenames = matches.values_of("filenames").unwrap().collect(); - check_files(filenames); - println!("successful: no domain definition errors detected"); + let matches = cli.get_matches(); + let filenames = matches.values_of("filenames").unwrap().collect(); + check_files(filenames); + println!("successful: no domain definition errors detected"); } diff --git a/crates/chronicle-domain-test/Cargo.toml b/crates/chronicle-domain-test/Cargo.toml index b1a3cf205..2e422f2b0 100644 --- a/crates/chronicle-domain-test/Cargo.toml +++ b/crates/chronicle-domain-test/Cargo.toml @@ -1,7 +1,7 @@ [package] -build = "build.rs" +build = "build.rs" edition = "2021" -name = "chronicle-example" +name = "chronicle-example" version = "0.7.5" [[bin]] @@ -11,12 +11,12 @@ path = "src/test.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -chronicle = { path = "../chronicle" } -chronicle-signing = { path = "../chronicle-signing" } +chronicle = { path = "../chronicle" } +chronicle-signing = { path = "../chronicle-signing" } chronicle-telemetry = { path = "../chronicle-telemetry" } -tracing = { workspace = true } -tracing-log = { workspace = true } -uuid = { workspace = true } +tracing = { workspace = true } +tracing-log = { workspace = true } +uuid = { workspace = true } [build-dependencies] chronicle = { path = "../chronicle" } @@ -28,13 +28,13 @@ devmode = ["chronicle/devmode"] [dev-dependencies] chronicle-test-infrastructure = { path = "../chronicle-test-infrastructure" } -common = { path = "../common", features = ["std"] } -embedded-substrate = { path = "../embedded-substrate" } -futures = { workspace = true } -hex = { workspace = true } -insta = { workspace = true, features = ["json"] } -protocol-substrate = { path = "../protocol-substrate" } -protocol-substrate-chronicle = { path = "../protocol-substrate-chronicle" } -protocol-substrate-opa = { path = "../protocol-substrate-opa" } -tempfile = { workspace = true } -tokio = { workspace = true } +common = { path = "../common", features = ["std"] } +embedded-substrate = { path = "../embedded-substrate" } +futures = { workspace = true } +hex = { workspace = true } +insta = { workspace = true, features = ["json"] } +protocol-substrate = { path = "../protocol-substrate" } +protocol-substrate-chronicle = { path = "../protocol-substrate-chronicle" } +protocol-substrate-opa = { path = "../protocol-substrate-opa" } +tempfile = { workspace = true } +tokio = { workspace = true } diff --git a/crates/chronicle-domain-test/src/test.rs b/crates/chronicle-domain-test/src/test.rs index 86bcf7582..10e6b7387 100644 --- a/crates/chronicle-domain-test/src/test.rs +++ b/crates/chronicle-domain-test/src/test.rs @@ -66,7 +66,7 @@ mod test { use chronicle::{ api::{ chronicle_graphql::{construct_schema, OpaCheck, Subscription}, - Api, Store, UuidGen, + Store, }, async_graphql::{Request, Response, Schema}, bootstrap::opa::CliPolicyLoader, @@ -83,6 +83,7 @@ mod test { use super::{Mutation, Query}; + use chronicle::api::{Api, UuidGen}; use core::future::Future; use std::time::Duration; @@ -121,7 +122,7 @@ mod test { async fn test_schema_with_opa<'a>( opa_executor: ExecutorContext, ) -> (Schema, TemporaryDatabase<'a>) { - chronicle_telemetry::telemetry(None, chronicle_telemetry::ConsoleLogging::Pretty); + chronicle_telemetry::telemetry(false, chronicle_telemetry::ConsoleLogging::Pretty); let secrets = ChronicleSigning::new( chronicle_secret_names(), @@ -2976,16 +2977,16 @@ mod test { let (schema, _database) = test_schema().await; let res = schema - .execute(Request::new( - r#" + .execute(Request::new( + r#" mutation { defineContractorAgent(externalId:"testagent1", attributes: { locationAttribute: "testlocation" }) { context } } "#, - )) - .await; + )) + .await; assert_eq!(res.errors, vec![]); @@ -3014,16 +3015,16 @@ mod test { tokio::time::sleep(Duration::from_millis(1000)).await; let res = schema - .execute(Request::new( - r#" + .execute(Request::new( + r#" mutation { defineCertificateEntity(externalId:"testentity1", attributes: { certIdAttribute: "testcertid" }) { context } } "#, - )) - .await; + )) + .await; assert_eq!(res.errors, vec![]); diff --git a/crates/chronicle-domain/Cargo.toml b/crates/chronicle-domain/Cargo.toml index fec4c69ae..1fb0321d3 100644 --- a/crates/chronicle-domain/Cargo.toml +++ b/crates/chronicle-domain/Cargo.toml @@ -1,7 +1,7 @@ [package] -build = "build.rs" +build = "build.rs" edition = "2021" -name = "chronicle-domain" +name = "chronicle-domain" version = "0.7.5" [[bin]] @@ -21,7 +21,7 @@ chronicle = { path = "../chronicle" } [features] devmode = ["chronicle/devmode"] -strict = [] +strict = [] [dev-dependencies] tempfile = { workspace = true } diff --git a/crates/chronicle-domain/domain.yaml b/crates/chronicle-domain/domain.yaml index 41037fb80..8cf1de07a 100644 --- a/crates/chronicle-domain/domain.yaml +++ b/crates/chronicle-domain/domain.yaml @@ -24,7 +24,7 @@ entities: - PartID activities: ItemCertified: - attributes: [] + attributes: [ ] ItemManufactured: attributes: - BatchID diff --git a/crates/chronicle-persistence/Cargo.toml b/crates/chronicle-persistence/Cargo.toml index 72fc6e7e3..031170bce 100644 --- a/crates/chronicle-persistence/Cargo.toml +++ b/crates/chronicle-persistence/Cargo.toml @@ -1,16 +1,16 @@ [package] edition = "2021" -name = "chronicle-persistence" +name = "chronicle-persistence" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] async-graphql = { workspace = true, features = [ - "chrono", - "unblock", - "default", - "uuid", + "chrono", + "unblock", + "default", + "uuid", ] } async-trait = { workspace = true } chrono = { workspace = true } @@ -25,5 +25,5 @@ tracing = { workspace = true } uuid = { workspace = true } #local dependencies -common = { path = "../common", features = ["diesel-bindings", "std"] } +common = { path = "../common", features = ["diesel-bindings", "std"] } protocol-substrate-chronicle = { path = "../protocol-substrate-chronicle" } diff --git a/crates/chronicle-persistence/migrations/2022-01-18-144301_ledger_sync/up.sql b/crates/chronicle-persistence/migrations/2022-01-18-144301_ledger_sync/up.sql index 6193ae6ee..780fa1179 100644 --- a/crates/chronicle-persistence/migrations/2022-01-18-144301_ledger_sync/up.sql +++ b/crates/chronicle-persistence/migrations/2022-01-18-144301_ledger_sync/up.sql @@ -1,185 +1,204 @@ -create table namespace ( - id serial primary key, +create table namespace +( + id serial primary key, external_id text not null, - uuid text not null, - unique(external_id) + uuid text not null, + unique (external_id) ); -create unique index namespace_idx on namespace(external_id,uuid); +create unique index namespace_idx on namespace (external_id, uuid); -create table ledgersync ( - tx_id text primary key, +create table ledgersync +( + tx_id text primary key, bc_offset text, sync_time timestamp ); -create index ledger_index on ledgersync(sync_time,bc_offset); +create index ledger_index on ledgersync (sync_time, bc_offset); -create table identity ( - id serial primary key, +create table identity +( + id serial primary key, namespace_id integer not null, - public_key text not null, - foreign key(namespace_id) references namespace(id) + public_key text not null, + foreign key (namespace_id) references namespace (id) ); -create index identity_public_key_idx on identity(public_key); +create index identity_public_key_idx on identity (public_key); -create table agent ( - id serial primary key, - external_id text not null, +create table agent +( + id serial primary key, + external_id text not null, namespace_id integer not null, - domaintype text, - current integer not null, - identity_id integer, - foreign key(identity_id) references identity(id), - foreign key(namespace_id) references namespace(id), - unique(external_id,namespace_id) + domaintype text, + current integer not null, + identity_id integer, + foreign key (identity_id) references identity (id), + foreign key (namespace_id) references namespace (id), + unique (external_id, namespace_id) ); -create index agent_external_id_idx on agent(external_id,namespace_id); +create index agent_external_id_idx on agent (external_id, namespace_id); -create table attachment ( - id serial primary key, - namespace_id integer not null, +create table attachment +( + id serial primary key, + namespace_id integer not null, signature_time timestamp not null, - signature text not null, - signer_id integer not null, - locator text, - foreign key(namespace_id) references namespace(id), - foreign key(signer_id) references identity(id) + signature text not null, + signer_id integer not null, + locator text, + foreign key (namespace_id) references namespace (id), + foreign key (signer_id) references identity (id) ); -create index attachment_signature_idx on attachment(signature); +create index attachment_signature_idx on attachment (signature); -create table activity ( - id serial primary key, - external_id text not null, - namespace_id integer not null, - domaintype text, - started timestamp, - ended timestamp, - foreign key(namespace_id) references namespace(id), - unique(external_id,namespace_id) -); - -create table entity ( - id serial primary key, - external_id text not null, +create table activity +( + id serial primary key, + external_id text not null, namespace_id integer not null, - domaintype text, + domaintype text, + started timestamp, + ended timestamp, + foreign key (namespace_id) references namespace (id), + unique (external_id, namespace_id) +); + +create table entity +( + id serial primary key, + external_id text not null, + namespace_id integer not null, + domaintype text, attachment_id integer, - foreign key(attachment_id) references attachment(id), - foreign key(namespace_id) references namespace(id), - unique(external_id,namespace_id) + foreign key (attachment_id) references attachment (id), + foreign key (namespace_id) references namespace (id), + unique (external_id, namespace_id) ); -create table delegation ( - delegate_id integer not null, +create table delegation +( + delegate_id integer not null, responsible_id integer not null, - activity_id integer not null default -1, - role text not null default '', - foreign key(delegate_id) references agent(id), - foreign key(responsible_id) references agent(id), - foreign key(activity_id) references activity(id), - primary key(responsible_id,delegate_id,activity_id,role) + activity_id integer not null default -1, + role text not null default '', + foreign key (delegate_id) references agent (id), + foreign key (responsible_id) references agent (id), + foreign key (activity_id) references activity (id), + primary key (responsible_id, delegate_id, activity_id, role) ); -create table derivation ( - activity_id integer, +create table derivation +( + activity_id integer, generated_entity_id integer not null, - used_entity_id integer not null, - typ integer not null default -1, - foreign key(activity_id) references activity(id), - foreign key(generated_entity_id) references entity(id), - foreign key(used_entity_id) references entity(id), - primary key(activity_id,used_entity_id,generated_entity_id,typ) + used_entity_id integer not null, + typ integer not null default -1, + foreign key (activity_id) references activity (id), + foreign key (generated_entity_id) references entity (id), + foreign key (used_entity_id) references entity (id), + primary key (activity_id, used_entity_id, generated_entity_id, typ) ); -create table generation ( - activity_id integer not null, +create table generation +( + activity_id integer not null, generated_entity_id integer not null, - typ text, - foreign key(activity_id) references activity(id), - foreign key(generated_entity_id) references entity(id), - primary key(activity_id,generated_entity_id) + typ text, + foreign key (activity_id) references activity (id), + foreign key (generated_entity_id) references entity (id), + primary key (activity_id, generated_entity_id) ); -create table association ( - agent_id integer not null, +create table association +( + agent_id integer not null, activity_id integer not null, - role text not null default '', - foreign key(agent_id) references agent(id), - foreign key(activity_id) references activity(id), - primary key(agent_id, activity_id, role) + role text not null default '', + foreign key (agent_id) references agent (id), + foreign key (activity_id) references activity (id), + primary key (agent_id, activity_id, role) ); -create table usage ( +create table usage +( activity_id integer not null, - entity_id integer not null, - foreign key(entity_id) references entity(id), - foreign key(activity_id) references activity(id), - primary key(activity_id,entity_id) + entity_id integer not null, + foreign key (entity_id) references entity (id), + foreign key (activity_id) references activity (id), + primary key (activity_id, entity_id) ); -create table wasinformedby ( - activity_id integer not null, +create table wasinformedby +( + activity_id integer not null, informing_activity_id integer not null, - foreign key(activity_id) references activity(id), - foreign key(informing_activity_id) references activity(id), - primary key(activity_id,informing_activity_id) + foreign key (activity_id) references activity (id), + foreign key (informing_activity_id) references activity (id), + primary key (activity_id, informing_activity_id) ); -create table attribution ( - agent_id integer not null, +create table attribution +( + agent_id integer not null, entity_id integer not null, - role text not null default '', - foreign key(agent_id) references agent(id), - foreign key(entity_id) references entity(id), - primary key(agent_id, entity_id, role) + role text not null default '', + foreign key (agent_id) references agent (id), + foreign key (entity_id) references entity (id), + primary key (agent_id, entity_id, role) ); -create table hadidentity ( - agent_id integer not null, +create table hadidentity +( + agent_id integer not null, identity_id integer not null, - foreign key(agent_id) references agent(id), - foreign key(identity_id) references identity(id), - primary key(agent_id,identity_id) + foreign key (agent_id) references agent (id), + foreign key (identity_id) references identity (id), + primary key (agent_id, identity_id) ); -create table hadattachment ( - entity_id integer not null, +create table hadattachment +( + entity_id integer not null, attachment_id integer not null, - foreign key(entity_id) references entity(id), - foreign key(attachment_id) references attachment(id), - primary key(entity_id,attachment_id) + foreign key (entity_id) references entity (id), + foreign key (attachment_id) references attachment (id), + primary key (entity_id, attachment_id) ); -create table entity_attribute ( +create table entity_attribute +( entity_id integer not null, - typename text not null, - value text not null, - foreign key(entity_id) references entity(id), - primary key(entity_id,typename) + typename text not null, + value text not null, + foreign key (entity_id) references entity (id), + primary key (entity_id, typename) ); -create table agent_attribute ( +create table agent_attribute +( agent_id integer not null, - typename text not null, - value text not null, - foreign key(agent_id) references agent(id), - primary key(agent_id,typename) + typename text not null, + value text not null, + foreign key (agent_id) references agent (id), + primary key (agent_id, typename) ); -create table activity_attribute ( +create table activity_attribute +( activity_id integer not null, - typename text not null, - value text not null, - foreign key(activity_id) references activity(id), - primary key(activity_id,typename) + typename text not null, + value text not null, + foreign key (activity_id) references activity (id), + primary key (activity_id, typename) ); insert into namespace(id, external_id, uuid) - values (-1, 'hidden entry for Option None', '00000000-0000-0000-0000-000000000000'); +values (-1, 'hidden entry for Option None', '00000000-0000-0000-0000-000000000000'); insert into activity(id, external_id, namespace_id) - values (-1, 'hidden entry for Option None', -1); +values (-1, 'hidden entry for Option None', -1); diff --git a/crates/chronicle-persistence/migrations/2023-04-11-111125_generation/up.sql b/crates/chronicle-persistence/migrations/2023-04-11-111125_generation/up.sql index b972108d8..c2da8943d 100644 --- a/crates/chronicle-persistence/migrations/2023-04-11-111125_generation/up.sql +++ b/crates/chronicle-persistence/migrations/2023-04-11-111125_generation/up.sql @@ -1,2 +1,3 @@ alter table generation - drop typ; +drop +typ; diff --git a/crates/chronicle-persistence/migrations/2023-06-16-145625_attribution_fix/up.sql b/crates/chronicle-persistence/migrations/2023-06-16-145625_attribution_fix/up.sql index 0a1ddecb8..1ca336f23 100644 --- a/crates/chronicle-persistence/migrations/2023-06-16-145625_attribution_fix/up.sql +++ b/crates/chronicle-persistence/migrations/2023-06-16-145625_attribution_fix/up.sql @@ -1,8 +1,38 @@ -create table if not exists attribution ( - agent_id integer not null, - entity_id integer not null, - role text not null default '', - foreign key(agent_id) references agent(id), - foreign key(entity_id) references entity(id), - primary key(agent_id, entity_id, role) -); +create table if not exists attribution +( + agent_id + integer + not + null, + entity_id + integer + not + null, + role + text + not + null + default + '', + foreign + key +( + agent_id +) references agent +( + id +), + foreign key +( + entity_id +) references entity +( + id +), + primary key +( + agent_id, + entity_id, + role +) + ); diff --git a/crates/chronicle-persistence/migrations/2023-07-12-123150_attachment/down.sql b/crates/chronicle-persistence/migrations/2023-07-12-123150_attachment/down.sql index 6ad3885eb..9ebe4c85e 100644 --- a/crates/chronicle-persistence/migrations/2023-07-12-123150_attachment/down.sql +++ b/crates/chronicle-persistence/migrations/2023-07-12-123150_attachment/down.sql @@ -1,24 +1,26 @@ -- This file should undo anything in `up.sql` -create table attachment ( - id serial primary key, - namespace_id integer not null, +create table attachment +( + id serial primary key, + namespace_id integer not null, signature_time timestamp not null, - signature text not null, - signer_id integer not null, - locator text, - foreign key(namespace_id) references namespace(id), - foreign key(signer_id) references identity(id) + signature text not null, + signer_id integer not null, + locator text, + foreign key (namespace_id) references namespace (id), + foreign key (signer_id) references identity (id) ); -create index attachment_signature_idx on attachment(signature); +create index attachment_signature_idx on attachment (signature); -create table hadattachment ( - entity_id integer not null, +create table hadattachment +( + entity_id integer not null, attachment_id integer not null, - foreign key(entity_id) references entity(id), - foreign key(attachment_id) references attachment(id), - primary key(entity_id,attachment_id) + foreign key (entity_id) references entity (id), + foreign key (attachment_id) references attachment (id), + primary key (entity_id, attachment_id) ); alter table entity diff --git a/crates/chronicle-persistence/migrations/2023-07-12-123150_attachment/up.sql b/crates/chronicle-persistence/migrations/2023-07-12-123150_attachment/up.sql index 330fe787d..10cabdba3 100644 --- a/crates/chronicle-persistence/migrations/2023-07-12-123150_attachment/up.sql +++ b/crates/chronicle-persistence/migrations/2023-07-12-123150_attachment/up.sql @@ -1,5 +1,6 @@ alter table entity - drop column attachment_id; +drop +column attachment_id; drop table hadattachment; diff --git a/crates/chronicle-persistence/src/cursor.rs b/crates/chronicle-persistence/src/cursor.rs index 9a90f746b..64f7224b8 100644 --- a/crates/chronicle-persistence/src/cursor.rs +++ b/crates/chronicle-persistence/src/cursor.rs @@ -1,9 +1,9 @@ use diesel::{ - pg::Pg, - prelude::*, - query_builder::*, - r2d2::{ConnectionManager, PooledConnection}, - sql_types::BigInt, + pg::Pg, + prelude::*, + query_builder::*, + r2d2::{ConnectionManager, PooledConnection}, + sql_types::BigInt, }; type Conn = PooledConnection>; @@ -12,58 +12,59 @@ const DEFAULT_PAGE_SIZE: i32 = 10; #[derive(QueryId)] pub struct CursorPosition { - query: T, - pub start: i64, - pub limit: i64, + query: T, + pub start: i64, + pub limit: i64, } + pub trait Cursorize: Sized { - fn cursor( - self, - after: Option, - before: Option, - first: Option, - last: Option, - ) -> CursorPosition; + fn cursor( + self, + after: Option, + before: Option, + first: Option, + last: Option, + ) -> CursorPosition; } impl Cursorize for T { - fn cursor( - self, - after: Option, - before: Option, - first: Option, - last: Option, - ) -> CursorPosition { - let mut start = after.map(|after| after + 1).unwrap_or(0) as usize; - let mut end = before.unwrap_or(DEFAULT_PAGE_SIZE) as usize; - if let Some(first) = first { - end = start + first - } - if let Some(last) = last { - start = if last > end - start { end } else { end - last }; - }; + fn cursor( + self, + after: Option, + before: Option, + first: Option, + last: Option, + ) -> CursorPosition { + let mut start = after.map(|after| after + 1).unwrap_or(0) as usize; + let mut end = before.unwrap_or(DEFAULT_PAGE_SIZE) as usize; + if let Some(first) = first { + end = start + first + } + if let Some(last) = last { + start = if last > end - start { end } else { end - last }; + }; - CursorPosition { query: self, start: start as _, limit: (end - start) as _ } - } + CursorPosition { query: self, start: start as _, limit: (end - start) as _ } + } } impl QueryFragment for CursorPosition -where - T: QueryFragment, + where + T: QueryFragment, { - fn walk_ast<'a>(&'a self, mut out: AstPass<'_, 'a, Pg>) -> QueryResult<()> { - out.push_sql("SELECT *, COUNT(*) OVER () FROM ("); - self.query.walk_ast(out.reborrow())?; - out.push_sql(") t LIMIT "); - out.push_bind_param::(&(self.limit))?; - out.push_sql(" OFFSET "); - out.push_bind_param::(&self.start)?; - Ok(()) - } + fn walk_ast<'a>(&'a self, mut out: AstPass<'_, 'a, Pg>) -> QueryResult<()> { + out.push_sql("SELECT *, COUNT(*) OVER () FROM ("); + self.query.walk_ast(out.reborrow())?; + out.push_sql(") t LIMIT "); + out.push_bind_param::(&(self.limit))?; + out.push_sql(" OFFSET "); + out.push_bind_param::(&self.start)?; + Ok(()) + } } impl Query for CursorPosition { - type SqlType = (T::SqlType, BigInt); + type SqlType = (T::SqlType, BigInt); } impl RunQueryDsl for CursorPosition {} diff --git a/crates/chronicle-persistence/src/database.rs b/crates/chronicle-persistence/src/database.rs index 5f700cac7..e2fe7859c 100644 --- a/crates/chronicle-persistence/src/database.rs +++ b/crates/chronicle-persistence/src/database.rs @@ -5,26 +5,26 @@ use std::{fmt::Display, time::Duration}; #[async_trait::async_trait] pub trait DatabaseConnector { - async fn try_connect(&self) -> Result<(X, Pool>), E>; - fn should_retry(&self, error: &E) -> bool; + async fn try_connect(&self) -> Result<(X, Pool>), E>; + fn should_retry(&self, error: &E) -> bool; } pub async fn get_connection_with_retry( - connector: impl DatabaseConnector, + connector: impl DatabaseConnector, ) -> Result<(X, Pool>), E> { - let mut i = 1; - let mut j = 1; - loop { - let connection = connector.try_connect().await; - if let Err(source) = &connection { - tracing::warn!("database connection failed: {source}"); - if i < 20 && connector.should_retry(source) { - tracing::info!("waiting to retry database connection..."); - std::thread::sleep(Duration::from_secs(i)); - (i, j) = (i + j, i); - continue; - } - } - return connection; - } + let mut i = 1; + let mut j = 1; + loop { + let connection = connector.try_connect().await; + if let Err(source) = &connection { + tracing::warn!("database connection failed: {source}"); + if i < 20 && connector.should_retry(source) { + tracing::info!("waiting to retry database connection..."); + std::thread::sleep(Duration::from_secs(i)); + (i, j) = (i + j, i); + continue; + } + } + return connection; + } } diff --git a/crates/chronicle-persistence/src/lib.rs b/crates/chronicle-persistence/src/lib.rs index 60bb33e99..340eadc2b 100644 --- a/crates/chronicle-persistence/src/lib.rs +++ b/crates/chronicle-persistence/src/lib.rs @@ -2,1285 +2,1302 @@ use std::{collections::BTreeMap, str::FromStr, sync::Arc, time::Duration}; use chrono::{TimeZone, Utc}; use common::{ - attributes::Attribute, - prov::{ - operations::DerivationType, Activity, ActivityId, Agent, AgentId, Association, Attribution, - ChronicleTransactionId, ChronicleTransactionIdError, Delegation, Derivation, DomaintypeId, - Entity, EntityId, ExternalId, ExternalIdPart, Generation, Namespace, NamespaceId, - ProvModel, Role, Usage, - }, + attributes::Attribute, + prov::{ + operations::DerivationType, Activity, ActivityId, Agent, AgentId, Association, Attribution, + ChronicleTransactionId, ChronicleTransactionIdError, Delegation, Derivation, DomaintypeId, + Entity, EntityId, ExternalId, ExternalIdPart, Generation, Namespace, NamespaceId, + ProvModel, Role, Usage, + }, }; use diesel::{ - prelude::*, - r2d2::{ConnectionManager, Pool, PooledConnection}, - PgConnection, + prelude::*, + r2d2::{ConnectionManager, Pool, PooledConnection}, + PgConnection, }; use diesel_migrations::{embed_migrations, EmbeddedMigrations}; use protocol_substrate_chronicle::protocol::BlockId; use thiserror::Error; use tracing::{debug, instrument, warn}; use uuid::Uuid; + pub mod database; pub mod cursor; pub mod query; pub mod queryable; pub mod schema; + pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!(); #[derive(Error, Debug)] pub enum StoreError { - #[error("Database operation failed: {0}")] - Db( - #[from] - #[source] - diesel::result::Error, - ), - - #[error("Database connection failed (maybe check PGPASSWORD): {0}")] - DbConnection( - #[from] - #[source] - diesel::ConnectionError, - ), - - #[error("Database migration failed: {0}")] - DbMigration( - #[from] - #[source] - Box, - ), - - #[error("Connection pool error: {0}")] - DbPool( - #[from] - #[source] - r2d2::Error, - ), - - #[error("Infallible")] - Infallible(#[from] std::convert::Infallible), - - #[error( - "Integer returned from database was an unrecognized 'DerivationType' enum variant: {0}" - )] - InvalidDerivationTypeRecord(i32), - - #[error("Could not find namespace {0}")] - InvalidNamespace(NamespaceId), - - #[error("Unreadable Attribute: {0}")] - Json( - #[from] - #[source] - serde_json::Error, - ), - - #[error("Parse blockid: {0}")] - ParseBlockId( - #[from] - #[source] - protocol_substrate_chronicle::protocol::BlockIdError, - ), - - #[error("Invalid transaction ID: {0}")] - TransactionId( - #[from] - #[source] - ChronicleTransactionIdError, - ), - - #[error("Could not locate record in store")] - RecordNotFound, - - #[error("Invalid UUID: {0}")] - Uuid( - #[from] - #[source] - uuid::Error, - ), - - #[error("Serialization error: {0}")] - SerializationError(String), + #[error("Database operation failed: {0}")] + Db( + #[from] + #[source] + diesel::result::Error, + ), + + #[error("Database connection failed (maybe check PGPASSWORD): {0}")] + DbConnection( + #[from] + #[source] + diesel::ConnectionError, + ), + + #[error("Database migration failed: {0}")] + DbMigration( + #[from] + #[source] + Box, + ), + + #[error("Connection pool error: {0}")] + DbPool( + #[from] + #[source] + r2d2::Error, + ), + + #[error("Infallible")] + Infallible(#[from] std::convert::Infallible), + + #[error( + "Integer returned from database was an unrecognized 'DerivationType' enum variant: {0}" + )] + InvalidDerivationTypeRecord(i32), + + #[error("Could not find namespace {0}")] + InvalidNamespace(NamespaceId), + + #[error("Unreadable Attribute: {0}")] + Json( + #[from] + #[source] + serde_json::Error, + ), + + #[error("Parse blockid: {0}")] + ParseBlockId( + #[from] + #[source] + protocol_substrate_chronicle::protocol::BlockIdError, + ), + + #[error("Invalid transaction ID: {0}")] + TransactionId( + #[from] + #[source] + ChronicleTransactionIdError, + ), + + #[error("Could not locate record in store")] + RecordNotFound, + + #[error("Invalid UUID: {0}")] + Uuid( + #[from] + #[source] + uuid::Error, + ), + + #[error("Serialization error: {0}")] + SerializationError(String), } #[derive(Debug)] pub struct ConnectionOptions { - pub enable_wal: bool, - pub enable_foreign_keys: bool, - pub busy_timeout: Option, + pub enable_wal: bool, + pub enable_foreign_keys: bool, + pub busy_timeout: Option, } #[derive(Clone)] pub struct Store { - pool: Pool>, + pool: Pool>, } + type Generations = Vec; + type Usages = Vec; + type WasInformedBys = Vec; + type Associations = Vec<(String, String)>; impl Store { - #[instrument(name = "Bind namespace", skip(self))] - pub fn namespace_binding(&self, external_id: &str, uuid: Uuid) -> Result<(), StoreError> { - use schema::namespace::dsl; - - let uuid = uuid.to_string(); - self.connection()?.build_transaction().run(|conn| { - diesel::insert_into(dsl::namespace) - .values((dsl::external_id.eq(external_id), dsl::uuid.eq(&uuid))) - .on_conflict(dsl::external_id) - .do_update() - .set(dsl::uuid.eq(&uuid)) - .execute(conn) - })?; - - Ok(()) - } - - /// Fetch the activity record for the IRI - fn activity_by_activity_external_id_and_namespace( - &self, - connection: &mut PgConnection, - external_id: &ExternalId, - namespace_id: &NamespaceId, - ) -> Result { - let (_namespaceid, nsid) = - self.namespace_by_external_id(connection, namespace_id.external_id_part())?; - use schema::activity::dsl; - - Ok(schema::activity::table - .filter(dsl::external_id.eq(external_id).and(dsl::namespace_id.eq(nsid))) - .first::(connection)?) - } - - /// Fetch the entity record for the IRI - fn entity_by_entity_external_id_and_namespace( - &self, - connection: &mut PgConnection, - external_id: &ExternalId, - namespace_id: &NamespaceId, - ) -> Result { - let (_, ns_id) = - self.namespace_by_external_id(connection, namespace_id.external_id_part())?; - use schema::entity::dsl; - - Ok(schema::entity::table - .filter(dsl::external_id.eq(external_id).and(dsl::namespace_id.eq(ns_id))) - .first::(connection)?) - } - - /// Fetch the agent record for the IRI - pub fn agent_by_agent_external_id_and_namespace( - &self, - connection: &mut PgConnection, - external_id: &ExternalId, - namespace_id: &NamespaceId, - ) -> Result { - let (_namespaceid, nsid) = - self.namespace_by_external_id(connection, namespace_id.external_id_part())?; - use schema::agent::dsl; - - Ok(schema::agent::table - .filter(dsl::external_id.eq(external_id).and(dsl::namespace_id.eq(nsid))) - .first::(connection)?) - } - - /// Apply an activity to persistent storage, name + namespace are a key, so we update times + - /// domaintype on conflict - #[instrument(level = "trace", skip(self, connection), ret(Debug))] - fn apply_activity( - &self, - connection: &mut PgConnection, - Activity { - ref external_id, namespace_id, started, ended, domaintype_id, attributes, .. - }: &Activity, - ns: &BTreeMap>, - ) -> Result<(), StoreError> { - use schema::activity as dsl; - let (_, nsid) = - self.namespace_by_external_id(connection, namespace_id.external_id_part())?; - - let existing = self - .activity_by_activity_external_id_and_namespace(connection, external_id, namespace_id) - .ok(); - - let resolved_domain_type = - domaintype_id.as_ref().map(|x| x.external_id_part().clone()).or_else(|| { - existing.as_ref().and_then(|x| x.domaintype.as_ref().map(ExternalId::from)) - }); - - let resolved_started = started - .map(|x| x.naive_utc()) - .or_else(|| existing.as_ref().and_then(|x| x.started)); - - let resolved_ended = - ended.map(|x| x.naive_utc()).or_else(|| existing.as_ref().and_then(|x| x.ended)); - - diesel::insert_into(schema::activity::table) - .values(( - dsl::external_id.eq(external_id), - dsl::namespace_id.eq(nsid), - dsl::started.eq(started.map(|t| t.naive_utc())), - dsl::ended.eq(ended.map(|t| t.naive_utc())), - dsl::domaintype.eq(domaintype_id.as_ref().map(|x| x.external_id_part())), - )) - .on_conflict((dsl::external_id, dsl::namespace_id)) - .do_update() - .set(( - dsl::domaintype.eq(resolved_domain_type), - dsl::started.eq(resolved_started), - dsl::ended.eq(resolved_ended), - )) - .execute(connection)?; - - let query::Activity { id, .. } = self.activity_by_activity_external_id_and_namespace( - connection, - external_id, - namespace_id, - )?; - - diesel::insert_into(schema::activity_attribute::table) - .values( - attributes - .iter() - .map(|Attribute { typ, value, .. }| query::ActivityAttribute { - activity_id: id, - typename: typ.to_owned(), - value: value.to_string(), - }) - .collect::>(), - ) - .on_conflict_do_nothing() - .execute(connection)?; - - Ok(()) - } - - /// Apply an agent to persistent storage, external_id + namespace are a key, so we update - /// publickey + domaintype on conflict current is a special case, only relevant to local CLI - /// context. A possibly improved design would be to store this in another table given its scope - #[instrument(level = "trace", skip(self, connection), ret(Debug))] - fn apply_agent( - &self, - connection: &mut PgConnection, - Agent { ref external_id, namespaceid, domaintypeid, attributes, .. }: &Agent, - ns: &BTreeMap>, - ) -> Result<(), StoreError> { - use schema::agent::dsl; - let (_, nsid) = - self.namespace_by_external_id(connection, namespaceid.external_id_part())?; - - let existing = self - .agent_by_agent_external_id_and_namespace(connection, external_id, namespaceid) - .ok(); - - let resolved_domain_type = - domaintypeid.as_ref().map(|x| x.external_id_part().clone()).or_else(|| { - existing.as_ref().and_then(|x| x.domaintype.as_ref().map(ExternalId::from)) - }); - - diesel::insert_into(schema::agent::table) - .values(( - dsl::external_id.eq(external_id), - dsl::namespace_id.eq(nsid), - dsl::current.eq(0), - dsl::domaintype.eq(domaintypeid.as_ref().map(|x| x.external_id_part())), - )) - .on_conflict((dsl::namespace_id, dsl::external_id)) - .do_update() - .set(dsl::domaintype.eq(resolved_domain_type)) - .execute(connection)?; - - let query::Agent { id, .. } = - self.agent_by_agent_external_id_and_namespace(connection, external_id, namespaceid)?; - - diesel::insert_into(schema::agent_attribute::table) - .values( - attributes - .iter() - .map(|Attribute { typ, value, .. }| query::AgentAttribute { - agent_id: id, - typename: typ.to_owned(), - value: value.to_string(), - }) - .collect::>(), - ) - .on_conflict_do_nothing() - .execute(connection)?; - - Ok(()) - } - - #[instrument(level = "trace", skip(self, connection), ret(Debug))] - fn apply_entity( - &self, - connection: &mut PgConnection, - Entity { namespace_id, id, external_id, domaintypeid, attributes }: &Entity, - ns: &BTreeMap>, - ) -> Result<(), StoreError> { - use schema::entity::dsl; - let (_, nsid) = - self.namespace_by_external_id(connection, namespace_id.external_id_part())?; - - let existing = self - .entity_by_entity_external_id_and_namespace(connection, external_id, namespace_id) - .ok(); - - let resolved_domain_type = - domaintypeid.as_ref().map(|x| x.external_id_part().clone()).or_else(|| { - existing.as_ref().and_then(|x| x.domaintype.as_ref().map(ExternalId::from)) - }); - - diesel::insert_into(schema::entity::table) - .values(( - dsl::external_id.eq(&external_id), - dsl::namespace_id.eq(nsid), - dsl::domaintype.eq(domaintypeid.as_ref().map(|x| x.external_id_part())), - )) - .on_conflict((dsl::namespace_id, dsl::external_id)) - .do_update() - .set(dsl::domaintype.eq(resolved_domain_type)) - .execute(connection)?; - - let query::Entity { id, .. } = - self.entity_by_entity_external_id_and_namespace(connection, external_id, namespace_id)?; - - diesel::insert_into(schema::entity_attribute::table) - .values( - attributes - .iter() - .map(|Attribute { typ, value, .. }| query::EntityAttribute { - entity_id: id, - typename: typ.to_owned(), - value: value.to_string(), - }) - .collect::>(), - ) - .on_conflict_do_nothing() - .execute(connection)?; - - Ok(()) - } - - fn apply_model( - &self, - connection: &mut PgConnection, - model: &ProvModel, - ) -> Result<(), StoreError> { - for (_, ns) in model.namespaces.iter() { - self.apply_namespace(connection, ns)? - } - for (_, agent) in model.agents.iter() { - self.apply_agent(connection, agent, &model.namespaces)? - } - for (_, activity) in model.activities.iter() { - self.apply_activity(connection, activity, &model.namespaces)? - } - for (_, entity) in model.entities.iter() { - self.apply_entity(connection, entity, &model.namespaces)? - } - - for ((namespaceid, _), association) in model.association.iter() { - for association in association.iter() { - self.apply_was_associated_with(connection, namespaceid, association)?; - } - } - - for ((namespaceid, _), usage) in model.usage.iter() { - for usage in usage.iter() { - self.apply_used(connection, namespaceid, usage)?; - } - } - - for ((namespaceid, activity_id), was_informed_by) in model.was_informed_by.iter() { - for (_, informing_activity_id) in was_informed_by.iter() { - self.apply_was_informed_by( - connection, - namespaceid, - activity_id, - informing_activity_id, - )?; - } - } - - for ((namespaceid, _), generation) in model.generation.iter() { - for generation in generation.iter() { - self.apply_was_generated_by(connection, namespaceid, generation)?; - } - } - - for ((namespaceid, _), derivation) in model.derivation.iter() { - for derivation in derivation.iter() { - self.apply_derivation(connection, namespaceid, derivation)?; - } - } - - for ((namespaceid, _), delegation) in model.delegation.iter() { - for delegation in delegation.iter() { - self.apply_delegation(connection, namespaceid, delegation)?; - } - } - - for ((namespace_id, _), attribution) in model.attribution.iter() { - for attribution in attribution.iter() { - self.apply_was_attributed_to(connection, namespace_id, attribution)?; - } - } - - Ok(()) - } - - #[instrument(level = "trace", skip(self, connection), ret(Debug))] - fn apply_namespace( - &self, - connection: &mut PgConnection, - Namespace { ref external_id, ref uuid, .. }: &Namespace, - ) -> Result<(), StoreError> { - use schema::namespace::dsl; - diesel::insert_into(schema::namespace::table) - .values((dsl::external_id.eq(external_id), dsl::uuid.eq(hex::encode(uuid)))) - .on_conflict_do_nothing() - .execute(connection)?; - - Ok(()) - } - - pub fn apply_prov(&self, prov: &ProvModel) -> Result<(), StoreError> { - self.connection()? - .build_transaction() - .run(|connection| self.apply_model(connection, prov))?; - - Ok(()) - } - - #[instrument(skip_all)] - fn apply_used( - &self, - connection: &mut PgConnection, - namespace: &NamespaceId, - usage: &Usage, - ) -> Result<(), StoreError> { - let storedactivity = self.activity_by_activity_external_id_and_namespace( - connection, - usage.activity_id.external_id_part(), - namespace, - )?; - - let storedentity = self.entity_by_entity_external_id_and_namespace( - connection, - usage.entity_id.external_id_part(), - namespace, - )?; - - use schema::usage::dsl as link; - diesel::insert_into(schema::usage::table) - .values(( - &link::activity_id.eq(storedactivity.id), - &link::entity_id.eq(storedentity.id), - )) - .on_conflict_do_nothing() - .execute(connection)?; - - Ok(()) - } - - #[instrument(skip_all)] - fn apply_was_informed_by( - &self, - connection: &mut PgConnection, - namespace: &NamespaceId, - activity_id: &ActivityId, - informing_activity_id: &ActivityId, - ) -> Result<(), StoreError> { - let storedactivity = self.activity_by_activity_external_id_and_namespace( - connection, - activity_id.external_id_part(), - namespace, - )?; - - let storedinformingactivity = self.activity_by_activity_external_id_and_namespace( - connection, - informing_activity_id.external_id_part(), - namespace, - )?; - - use schema::wasinformedby::dsl as link; - diesel::insert_into(schema::wasinformedby::table) - .values(( - &link::activity_id.eq(storedactivity.id), - &link::informing_activity_id.eq(storedinformingactivity.id), - )) - .on_conflict_do_nothing() - .execute(connection)?; - - Ok(()) - } - - #[instrument(skip(self, connection))] - fn apply_was_associated_with( - &self, - connection: &mut PgConnection, - namespaceid: &common::prov::NamespaceId, - association: &Association, - ) -> Result<(), StoreError> { - let storedactivity = self.activity_by_activity_external_id_and_namespace( - connection, - association.activity_id.external_id_part(), - namespaceid, - )?; - - let storedagent = self.agent_by_agent_external_id_and_namespace( - connection, - association.agent_id.external_id_part(), - namespaceid, - )?; - - use schema::association::dsl as asoc; - let no_role = common::prov::Role("".to_string()); - diesel::insert_into(schema::association::table) - .values(( - &asoc::activity_id.eq(storedactivity.id), - &asoc::agent_id.eq(storedagent.id), - &asoc::role.eq(association.role.as_ref().unwrap_or(&no_role)), - )) - .on_conflict_do_nothing() - .execute(connection)?; - - Ok(()) - } - - #[instrument(skip(self, connection, namespace))] - fn apply_delegation( - &self, - connection: &mut PgConnection, - namespace: &common::prov::NamespaceId, - delegation: &Delegation, - ) -> Result<(), StoreError> { - let responsible = self.agent_by_agent_external_id_and_namespace( - connection, - delegation.responsible_id.external_id_part(), - namespace, - )?; - - let delegate = self.agent_by_agent_external_id_and_namespace( - connection, - delegation.delegate_id.external_id_part(), - namespace, - )?; - - let activity = { - if let Some(ref activity_id) = delegation.activity_id { - Some( - self.activity_by_activity_external_id_and_namespace( - connection, - activity_id.external_id_part(), - namespace, - )? - .id, - ) - } else { - None - } - }; - - use schema::delegation::dsl as link; - let no_role = common::prov::Role("".to_string()); - diesel::insert_into(schema::delegation::table) - .values(( - &link::responsible_id.eq(responsible.id), - &link::delegate_id.eq(delegate.id), - &link::activity_id.eq(activity.unwrap_or(-1)), - &link::role.eq(delegation.role.as_ref().unwrap_or(&no_role)), - )) - .on_conflict_do_nothing() - .execute(connection)?; - - Ok(()) - } - - #[instrument(skip(self, connection, namespace))] - fn apply_derivation( - &self, - connection: &mut PgConnection, - namespace: &common::prov::NamespaceId, - derivation: &Derivation, - ) -> Result<(), StoreError> { - let stored_generated = self.entity_by_entity_external_id_and_namespace( - connection, - derivation.generated_id.external_id_part(), - namespace, - )?; - - let stored_used = self.entity_by_entity_external_id_and_namespace( - connection, - derivation.used_id.external_id_part(), - namespace, - )?; - - let stored_activity = derivation - .activity_id - .as_ref() - .map(|activity_id| { - self.activity_by_activity_external_id_and_namespace( - connection, - activity_id.external_id_part(), - namespace, - ) - }) - .transpose()?; - - use schema::derivation::dsl as link; - diesel::insert_into(schema::derivation::table) - .values(( - &link::used_entity_id.eq(stored_used.id), - &link::generated_entity_id.eq(stored_generated.id), - &link::typ.eq(derivation.typ), - &link::activity_id.eq(stored_activity.map_or(-1, |activity| activity.id)), - )) - .on_conflict_do_nothing() - .execute(connection)?; - - Ok(()) - } - - #[instrument(skip_all)] - fn apply_was_generated_by( - &self, - connection: &mut PgConnection, - namespace: &common::prov::NamespaceId, - generation: &Generation, - ) -> Result<(), StoreError> { - let storedactivity = self.activity_by_activity_external_id_and_namespace( - connection, - generation.activity_id.external_id_part(), - namespace, - )?; - - let storedentity = self.entity_by_entity_external_id_and_namespace( - connection, - generation.generated_id.external_id_part(), - namespace, - )?; - - use schema::generation::dsl as link; - diesel::insert_into(schema::generation::table) - .values(( - &link::activity_id.eq(storedactivity.id), - &link::generated_entity_id.eq(storedentity.id), - )) - .on_conflict_do_nothing() - .execute(connection)?; - - Ok(()) - } - - #[instrument(skip(self, connection))] - fn apply_was_attributed_to( - &self, - connection: &mut PgConnection, - namespace_id: &common::prov::NamespaceId, - attribution: &Attribution, - ) -> Result<(), StoreError> { - let stored_entity = self.entity_by_entity_external_id_and_namespace( - connection, - attribution.entity_id.external_id_part(), - namespace_id, - )?; - - let stored_agent = self.agent_by_agent_external_id_and_namespace( - connection, - attribution.agent_id.external_id_part(), - namespace_id, - )?; - - use schema::attribution::dsl as attr; - let no_role = common::prov::Role("".to_string()); - diesel::insert_into(schema::attribution::table) - .values(( - &attr::entity_id.eq(stored_entity.id), - &attr::agent_id.eq(stored_agent.id), - &attr::role.eq(attribution.role.as_ref().unwrap_or(&no_role)), - )) - .on_conflict_do_nothing() - .execute(connection)?; - - Ok(()) - } - - pub fn connection( - &self, - ) -> Result>, StoreError> { - self.pool.get().map_err(StoreError::DbPool) - } - - #[instrument(skip_all)] - pub fn get_current_agent( - &self, - connection: &mut PgConnection, - ) -> Result { - use schema::agent::dsl; - Ok(schema::agent::table - .filter(dsl::current.ne(0)) - .first::(connection)?) - } - - /// Get the last fully synchronized offset - #[instrument(skip_all)] - pub fn get_last_block_id(&self) -> Result, StoreError> { - use schema::ledgersync::dsl; - self.connection()?.build_transaction().run(|connection| { - let block_id_and_tx = schema::ledgersync::table - .order_by(dsl::sync_time) - .select((dsl::bc_offset, dsl::tx_id)) - .first::<(Option, String)>(connection) - .map_err(StoreError::from)?; - - if let Some(block_id) = block_id_and_tx.0 { - Ok(Some(BlockId::try_from(&*block_id)?)) - } else { - Ok(None) - } - }) - } - - #[instrument(skip_all)] - pub fn namespace_by_external_id( - &self, - connection: &mut PgConnection, - namespace: &ExternalId, - ) -> Result<(NamespaceId, i32), StoreError> { - use self::schema::namespace::dsl; - - let ns = dsl::namespace - .filter(dsl::external_id.eq(namespace)) - .select((dsl::id, dsl::external_id, dsl::uuid)) - .first::<(i32, String, String)>(connection) - .optional()? - .ok_or(StoreError::RecordNotFound {})?; - - Ok((NamespaceId::from_external_id(ns.1, Uuid::from_str(&ns.2)?), ns.0)) - } - - #[instrument(skip_all)] - pub fn new(pool: Pool>) -> Result { - Ok(Store { pool }) - } - -#[instrument(skip_all)] - pub fn prov_model_for_agent( - &self, - agent: query::Agent, - namespaceid: &NamespaceId, - model: &mut ProvModel, - connection: &mut PgConnection, - ) -> Result<(), StoreError> { - debug!(?agent, "Map agent to prov"); - - let attributes = schema::agent_attribute::table - .filter(schema::agent_attribute::agent_id.eq(&agent.id)) - .load::(connection)?; - - let agentid: AgentId = AgentId::from_external_id(&agent.external_id); - model.agents.insert( - (namespaceid.clone(), agentid.clone()), - Agent { - id: agentid, - namespaceid: namespaceid.clone(), - external_id: ExternalId::from(&agent.external_id), - domaintypeid: agent.domaintype.map(DomaintypeId::from_external_id), - attributes: attributes - .iter() - .map(|attr| { - serde_json::from_str(&attr.value) - .map_err(|e| StoreError::SerializationError(e.to_string())) - .map(|value| Attribute { typ: attr.typename.clone(), value }) - }) - .collect::, StoreError>>()?, - } - .into(), - ); - - for (responsible, activity, role) in schema::delegation::table - .filter(schema::delegation::delegate_id.eq(agent.id)) - .inner_join( - schema::agent::table.on(schema::delegation::responsible_id.eq(schema::agent::id)), - ) - .inner_join( - schema::activity::table - .on(schema::delegation::activity_id.eq(schema::activity::id)), - ) - .order(schema::agent::external_id) - .select(( - schema::agent::external_id, - schema::activity::external_id, - schema::delegation::role, - )) - .load::<(String, String, String)>(connection)? - { - model.qualified_delegation( - namespaceid, - &AgentId::from_external_id(responsible), - &AgentId::from_external_id(&agent.external_id), - { - if activity.contains("hidden entry for Option None") { - None - } else { - Some(ActivityId::from_external_id(activity)) - } - }, - { - if role.is_empty() { - None - } else { - Some(Role(role)) - } - }, - ); - } - - Ok(()) - } - -#[instrument(skip_all)] - pub fn prov_model_for_activity( - &self, - activity: query::Activity, - namespaceid: &NamespaceId, - model: &mut ProvModel, - connection: &mut PgConnection, - ) -> Result<(), StoreError> { - let attributes = schema::activity_attribute::table - .filter(schema::activity_attribute::activity_id.eq(&activity.id)) - .load::(connection)?; - - let id: ActivityId = ActivityId::from_external_id(&activity.external_id); - model.activities.insert( - (namespaceid.clone(), id.clone()), - Activity { - id: id.clone(), - namespace_id: namespaceid.clone(), - external_id: activity.external_id.into(), - started: activity.started.map(|x| Utc.from_utc_datetime(&x).into()), - ended: activity.ended.map(|x| Utc.from_utc_datetime(&x).into()), - domaintype_id: activity.domaintype.map(DomaintypeId::from_external_id), - attributes: attributes - .iter() - .map(|attr| { - serde_json::from_str(&attr.value) - .map_err(|e| StoreError::SerializationError(e.to_string())) - .map(|value| Attribute { typ: attr.typename.clone(), value }) - }) - .collect::, StoreError>>()?, - } - .into(), - ); - - for generation in schema::generation::table - .filter(schema::generation::activity_id.eq(activity.id)) - .order(schema::generation::activity_id.asc()) - .inner_join(schema::entity::table) - .select(schema::entity::external_id) - .load::(connection)? - { - model.was_generated_by( - namespaceid.clone(), - &EntityId::from_external_id(generation), - &id, - ); - } - - for used in schema::usage::table - .filter(schema::usage::activity_id.eq(activity.id)) - .order(schema::usage::activity_id.asc()) - .inner_join(schema::entity::table) - .select(schema::entity::external_id) - .load::(connection)? - { - model.used(namespaceid.clone(), &id, &EntityId::from_external_id(used)); - } - - for wasinformedby in schema::wasinformedby::table - .filter(schema::wasinformedby::activity_id.eq(activity.id)) - .inner_join( - schema::activity::table - .on(schema::wasinformedby::informing_activity_id.eq(schema::activity::id)), - ) - .select(schema::activity::external_id) - .load::(connection)? - { - model.was_informed_by( - namespaceid.clone(), - &id, - &ActivityId::from_external_id(wasinformedby), - ); - } - - for (agent, role) in schema::association::table - .filter(schema::association::activity_id.eq(activity.id)) - .order(schema::association::activity_id.asc()) - .inner_join(schema::agent::table) - .select((schema::agent::external_id, schema::association::role)) - .load::<(String, String)>(connection)? - { - model.qualified_association(namespaceid, &id, &AgentId::from_external_id(agent), { - if role.is_empty() { - None - } else { - Some(Role(role)) - } - }); - } - - Ok(()) - } - -#[instrument(skip_all)] - pub fn prov_model_for_entity( - &self, - entity: query::Entity, - namespace_id: &NamespaceId, - model: &mut ProvModel, - connection: &mut PgConnection, - ) -> Result<(), StoreError> { - debug!(?entity, "Map entity to prov"); - - let query::Entity { id, namespace_id: _, domaintype, external_id } = entity; - - let entity_id = EntityId::from_external_id(&external_id); - - for (agent, role) in schema::attribution::table - .filter(schema::attribution::entity_id.eq(&id)) - .order(schema::attribution::entity_id.asc()) - .inner_join(schema::agent::table) - .select((schema::agent::external_id, schema::attribution::role)) - .load::<(String, String)>(connection)? - { - model.qualified_attribution( - namespace_id, - &entity_id, - &AgentId::from_external_id(agent), - { - if role.is_empty() { - None - } else { - Some(Role(role)) - } - }, - ); - } - - let attributes = schema::entity_attribute::table - .filter(schema::entity_attribute::entity_id.eq(&id)) - .load::(connection)?; - - model.entities.insert( - (namespace_id.clone(), entity_id.clone()), - Entity { - id: entity_id.clone(), - namespace_id: namespace_id.clone(), - external_id: external_id.into(), - domaintypeid: domaintype.map(DomaintypeId::from_external_id), - attributes: attributes - .iter() - .map(|attr| { - serde_json::from_str(&attr.value) - .map_err(|e| StoreError::SerializationError(e.to_string())) - .map(|value| Attribute { typ: attr.typename.clone(), value }) - }) - .collect::, StoreError>>()?, - } - .into(), - ); - - for (activity_id, activity_external_id, used_entity_id, typ) in schema::derivation::table - .filter(schema::derivation::generated_entity_id.eq(&id)) - .order(schema::derivation::generated_entity_id.asc()) - .inner_join( - schema::activity::table - .on(schema::derivation::activity_id.eq(schema::activity::id)), - ) - .inner_join( - schema::entity::table.on(schema::derivation::used_entity_id.eq(schema::entity::id)), - ) - .select(( - schema::derivation::activity_id, - schema::activity::external_id, - schema::entity::external_id, - schema::derivation::typ, - )) - .load::<(i32, String, String, i32)>(connection)? - { - let typ = DerivationType::try_from(typ) - .map_err(|_| StoreError::InvalidDerivationTypeRecord(typ))?; - - model.was_derived_from( - namespace_id.clone(), - typ, - EntityId::from_external_id(used_entity_id), - entity_id.clone(), - { - match activity_id { - -1 => None, - _ => Some(ActivityId::from_external_id(activity_external_id)), - } - }, - ); - } - - Ok(()) - } - -#[instrument(skip_all)] - pub fn prov_model_for_namespace( - &self, - connection: &mut PgConnection, - namespace: &NamespaceId, - ) -> Result { - let mut model = ProvModel::default(); - let (namespaceid, nsid) = - self.namespace_by_external_id(connection, namespace.external_id_part())?; - - let agents = schema::agent::table - .filter(schema::agent::namespace_id.eq(&nsid)) - .load::(connection)?; - - for agent in agents { - self.prov_model_for_agent(agent, &namespaceid, &mut model, connection)?; - } - - let activities = schema::activity::table - .filter(schema::activity::namespace_id.eq(nsid)) - .load::(connection)?; - - for activity in activities { - self.prov_model_for_activity(activity, &namespaceid, &mut model, connection)?; - } - - let entities = schema::entity::table - .filter(schema::entity::namespace_id.eq(nsid)) - .load::(connection)?; - - for entity in entities { - self.prov_model_for_entity(entity, &namespaceid, &mut model, connection)?; - } - - Ok(model) - } - - /// Set the last fully synchronized offset - #[instrument(skip(self),level = "info")] - pub fn set_last_block_id( - &self, - block_id: &BlockId, - tx_id: ChronicleTransactionId, - ) -> Result<(), StoreError> { - use schema::ledgersync as dsl; - - Ok(self.connection()?.build_transaction().run(|connection| { - diesel::insert_into(dsl::table) - .values(( - dsl::bc_offset.eq(block_id.to_string()), - dsl::tx_id.eq(&*tx_id.to_string()), - (dsl::sync_time.eq(Utc::now().naive_utc())), - )) - .on_conflict(dsl::tx_id) - .do_update() - .set(dsl::sync_time.eq(Utc::now().naive_utc())) - .execute(connection) - .map(|_| ()) - })?) - } - -#[instrument(skip_all)] - pub fn use_agent( - &self, - connection: &mut PgConnection, - external_id: &ExternalId, - namespace: &ExternalId, - ) -> Result<(), StoreError> { - let (_, nsid) = self.namespace_by_external_id(connection, namespace)?; - use schema::agent::dsl; - - diesel::update(schema::agent::table.filter(dsl::current.ne(0))) - .set(dsl::current.eq(0)) - .execute(connection)?; - - diesel::update( - schema::agent::table - .filter(dsl::external_id.eq(external_id).and(dsl::namespace_id.eq(nsid))), - ) - .set(dsl::current.eq(1)) - .execute(connection)?; - - Ok(()) - } - -#[instrument(skip_all)] - pub fn prov_model_for_agent_id( - &self, - connection: &mut PgConnection, - id: &AgentId, - ns: &ExternalId, - ) -> Result { - let agent = schema::agent::table - .inner_join(schema::namespace::dsl::namespace) - .filter(schema::agent::external_id.eq(id.external_id_part())) - .filter(schema::namespace::external_id.eq(ns)) - .select(query::Agent::as_select()) - .first(connection)?; - - let namespace = self.namespace_by_external_id(connection, ns)?.0; - - let mut model = ProvModel::default(); - self.prov_model_for_agent(agent, &namespace, &mut model, connection)?; - Ok(model) - } - -#[instrument(skip_all)] - pub fn apply_prov_model_for_agent_id( - &self, - connection: &mut PgConnection, - mut model: ProvModel, - id: &AgentId, - ns: &ExternalId, - ) -> Result { - if let Some(agent) = schema::agent::table - .inner_join(schema::namespace::dsl::namespace) - .filter(schema::agent::external_id.eq(id.external_id_part())) - .filter(schema::namespace::external_id.eq(ns)) - .select(query::Agent::as_select()) - .first(connection) - .optional()? - { - let namespace = self.namespace_by_external_id(connection, ns)?.0; - self.prov_model_for_agent(agent, &namespace, &mut model, connection)?; - } - Ok(model) - } - -#[instrument(skip_all)] - pub fn prov_model_for_activity_id( - &self, - connection: &mut PgConnection, - id: &ActivityId, - ns: &ExternalId, - ) -> Result { - let activity = schema::activity::table - .inner_join(schema::namespace::dsl::namespace) - .filter(schema::activity::external_id.eq(id.external_id_part())) - .filter(schema::namespace::external_id.eq(ns)) - .select(query::Activity::as_select()) - .first(connection)?; - - let namespace = self.namespace_by_external_id(connection, ns)?.0; - - let mut model = ProvModel::default(); - self.prov_model_for_activity(activity, &namespace, &mut model, connection)?; - Ok(model) - } - -#[instrument(skip_all)] - pub fn apply_prov_model_for_activity_id( - &self, - connection: &mut PgConnection, - mut model: ProvModel, - id: &ActivityId, - ns: &ExternalId, - ) -> Result { - if let Some(activity) = schema::activity::table - .inner_join(schema::namespace::dsl::namespace) - .filter(schema::activity::external_id.eq(id.external_id_part())) - .filter(schema::namespace::external_id.eq(ns)) - .select(query::Activity::as_select()) - .first(connection) - .optional()? - { - let namespace = self.namespace_by_external_id(connection, ns)?.0; - self.prov_model_for_activity(activity, &namespace, &mut model, connection)?; - } - Ok(model) - } - -#[instrument(skip_all)] - pub fn prov_model_for_entity_id( - &self, - connection: &mut PgConnection, - id: &EntityId, - ns: &ExternalId, - ) -> Result { - let entity = schema::entity::table - .inner_join(schema::namespace::dsl::namespace) - .filter(schema::entity::external_id.eq(id.external_id_part())) - .filter(schema::namespace::external_id.eq(ns)) - .select(query::Entity::as_select()) - .first(connection)?; - - let namespace = self.namespace_by_external_id(connection, ns)?.0; - - let mut model = ProvModel::default(); - self.prov_model_for_entity(entity, &namespace, &mut model, connection)?; - Ok(model) - } - -#[instrument(skip_all)] - pub fn apply_prov_model_for_entity_id( - &self, - connection: &mut PgConnection, - mut model: ProvModel, - id: &EntityId, - ns: &ExternalId, - ) -> Result { - if let Some(entity) = schema::entity::table - .inner_join(schema::namespace::dsl::namespace) - .filter(schema::entity::external_id.eq(id.external_id_part())) - .filter(schema::namespace::external_id.eq(ns)) - .select(query::Entity::as_select()) - .first(connection) - .optional()? - { - let namespace = self.namespace_by_external_id(connection, ns)?.0; - self.prov_model_for_entity(entity, &namespace, &mut model, connection)?; - } - Ok(model) - } - -#[instrument(skip_all)] - pub fn prov_model_for_usage( - &self, - connection: &mut PgConnection, - mut model: ProvModel, - id: &EntityId, - activity_id: &ActivityId, - ns: &ExternalId, - ) -> Result { - if let Some(entity) = schema::entity::table - .inner_join(schema::namespace::dsl::namespace) - .filter(schema::entity::external_id.eq(id.external_id_part())) - .filter(schema::namespace::external_id.eq(ns)) - .select(query::Entity::as_select()) - .first(connection) - .optional()? - { - if let Some(activity) = schema::activity::table - .inner_join(schema::namespace::dsl::namespace) - .filter(schema::activity::external_id.eq(id.external_id_part())) - .filter(schema::namespace::external_id.eq(ns)) - .select(query::Activity::as_select()) - .first(connection) - .optional()? - { - let namespace = self.namespace_by_external_id(connection, ns)?.0; - for used in schema::usage::table - .filter(schema::usage::activity_id.eq(activity.id)) - .order(schema::usage::activity_id.asc()) - .inner_join(schema::entity::table) - .select(schema::entity::external_id) - .load::(connection)? - { - model.used(namespace.clone(), activity_id, &EntityId::from_external_id(used)); - } - self.prov_model_for_entity(entity, &namespace, &mut model, connection)?; - self.prov_model_for_activity(activity, &namespace, &mut model, connection)?; - } - } - Ok(model) - } + + + #[instrument(name = "Bind namespace", skip(self))] + pub fn namespace_binding(&self, external_id: &str, uuid: Uuid) -> Result<(), StoreError> { + use schema::namespace::dsl; + + let uuid = uuid.to_string(); + self.connection()?.build_transaction().run(|conn| { + diesel::insert_into(dsl::namespace) + .values((dsl::external_id.eq(external_id), dsl::uuid.eq(&uuid))) + .on_conflict(dsl::external_id) + .do_update() + .set(dsl::uuid.eq(&uuid)) + .execute(conn) + })?; + + Ok(()) + } + + /// Fetch the activity record for the IRI + fn activity_by_activity_external_id_and_namespace( + &self, + connection: &mut PgConnection, + external_id: &ExternalId, + namespace_id: &NamespaceId, + ) -> Result { + let (_namespaceid, nsid) = + self.namespace_by_external_id(connection, namespace_id.external_id_part())?; + use schema::activity::dsl; + + Ok(schema::activity::table + .filter(dsl::external_id.eq(external_id).and(dsl::namespace_id.eq(nsid))) + .first::(connection)?) + } + + /// Fetch the entity record for the IRI + fn entity_by_entity_external_id_and_namespace( + &self, + connection: &mut PgConnection, + external_id: &ExternalId, + namespace_id: &NamespaceId, + ) -> Result { + let (_, ns_id) = + self.namespace_by_external_id(connection, namespace_id.external_id_part())?; + use schema::entity::dsl; + + Ok(schema::entity::table + .filter(dsl::external_id.eq(external_id).and(dsl::namespace_id.eq(ns_id))) + .first::(connection)?) + } + + /// Fetch the agent record for the IRI + pub fn agent_by_agent_external_id_and_namespace( + &self, + connection: &mut PgConnection, + external_id: &ExternalId, + namespace_id: &NamespaceId, + ) -> Result { + let (_namespaceid, nsid) = + self.namespace_by_external_id(connection, namespace_id.external_id_part())?; + use schema::agent::dsl; + + Ok(schema::agent::table + .filter(dsl::external_id.eq(external_id).and(dsl::namespace_id.eq(nsid))) + .first::(connection)?) + } + + /// Apply an activity to persistent storage, name + namespace are a key, so we update times + + /// domaintype on conflict + #[instrument(level = "trace", skip(self, connection), ret(Debug))] + fn apply_activity( + &self, + connection: &mut PgConnection, + Activity { + ref external_id, namespace_id, started, ended, domaintype_id, attributes, .. + }: &Activity, + ) -> Result<(), StoreError> { + use schema::activity as dsl; + let (_, nsid) = + self.namespace_by_external_id(connection, namespace_id.external_id_part())?; + + let existing = self + .activity_by_activity_external_id_and_namespace(connection, external_id, namespace_id) + .ok(); + + let resolved_domain_type = + domaintype_id.as_ref().map(|x| x.external_id_part().clone()).or_else(|| { + existing.as_ref().and_then(|x| x.domaintype.as_ref().map(ExternalId::from)) + }); + + let resolved_started = started + .map(|x| x.naive_utc()) + .or_else(|| existing.as_ref().and_then(|x| x.started)); + + let resolved_ended = + ended.map(|x| x.naive_utc()).or_else(|| existing.as_ref().and_then(|x| x.ended)); + + diesel::insert_into(schema::activity::table) + .values(( + dsl::external_id.eq(external_id), + dsl::namespace_id.eq(nsid), + dsl::started.eq(started.map(|t| t.naive_utc())), + dsl::ended.eq(ended.map(|t| t.naive_utc())), + dsl::domaintype.eq(domaintype_id.as_ref().map(|x| x.external_id_part())), + )) + .on_conflict((dsl::external_id, dsl::namespace_id)) + .do_update() + .set(( + dsl::domaintype.eq(resolved_domain_type), + dsl::started.eq(resolved_started), + dsl::ended.eq(resolved_ended), + )) + .execute(connection)?; + + let query::Activity { id, .. } = self.activity_by_activity_external_id_and_namespace( + connection, + external_id, + namespace_id, + )?; + + diesel::insert_into(schema::activity_attribute::table) + .values( + attributes + .iter() + .map(|Attribute { typ, value, .. }| query::ActivityAttribute { + activity_id: id, + typename: typ.to_owned(), + value: value.to_string(), + }) + .collect::>(), + ) + .on_conflict_do_nothing() + .execute(connection)?; + + Ok(()) + } + + /// Apply an agent to persistent storage, external_id + namespace are a key, so we update + /// publickey + domaintype on conflict current is a special case, only relevant to local CLI + /// context. A possibly improved design would be to store this in another table given its scope + #[instrument(level = "trace", skip(self, connection), ret(Debug))] + fn apply_agent( + &self, + connection: &mut PgConnection, + Agent { ref external_id, namespaceid, domaintypeid, attributes, .. }: &Agent, + ) -> Result<(), StoreError> { + use schema::agent::dsl; + let (_, nsid) = + self.namespace_by_external_id(connection, namespaceid.external_id_part())?; + + let existing = self + .agent_by_agent_external_id_and_namespace(connection, external_id, namespaceid) + .ok(); + + let resolved_domain_type = + domaintypeid.as_ref().map(|x| x.external_id_part().clone()).or_else(|| { + existing.as_ref().and_then(|x| x.domaintype.as_ref().map(ExternalId::from)) + }); + + diesel::insert_into(schema::agent::table) + .values(( + dsl::external_id.eq(external_id), + dsl::namespace_id.eq(nsid), + dsl::current.eq(0), + dsl::domaintype.eq(domaintypeid.as_ref().map(|x| x.external_id_part())), + )) + .on_conflict((dsl::namespace_id, dsl::external_id)) + .do_update() + .set(dsl::domaintype.eq(resolved_domain_type)) + .execute(connection)?; + + let query::Agent { id, .. } = + self.agent_by_agent_external_id_and_namespace(connection, external_id, namespaceid)?; + + diesel::insert_into(schema::agent_attribute::table) + .values( + attributes + .iter() + .map(|Attribute { typ, value, .. }| query::AgentAttribute { + agent_id: id, + typename: typ.to_owned(), + value: value.to_string(), + }) + .collect::>(), + ) + .on_conflict_do_nothing() + .execute(connection)?; + + Ok(()) + } + + #[instrument(level = "trace", skip(self, connection), ret(Debug))] + fn apply_entity( + &self, + connection: &mut PgConnection, + Entity { namespace_id, external_id, domaintypeid, attributes, .. }: &Entity, + ) -> Result<(), StoreError> { + use schema::entity::dsl; + let (_, nsid) = + self.namespace_by_external_id(connection, namespace_id.external_id_part())?; + + let existing = self + .entity_by_entity_external_id_and_namespace(connection, external_id, namespace_id) + .ok(); + + let resolved_domain_type = + domaintypeid.as_ref().map(|x| x.external_id_part().clone()).or_else(|| { + existing.as_ref().and_then(|x| x.domaintype.as_ref().map(ExternalId::from)) + }); + + diesel::insert_into(schema::entity::table) + .values(( + dsl::external_id.eq(&external_id), + dsl::namespace_id.eq(nsid), + dsl::domaintype.eq(domaintypeid.as_ref().map(|x| x.external_id_part())), + )) + .on_conflict((dsl::namespace_id, dsl::external_id)) + .do_update() + .set(dsl::domaintype.eq(resolved_domain_type)) + .execute(connection)?; + + let query::Entity { id, .. } = + self.entity_by_entity_external_id_and_namespace(connection, external_id, namespace_id)?; + + diesel::insert_into(schema::entity_attribute::table) + .values( + attributes + .iter() + .map(|Attribute { typ, value, .. }| query::EntityAttribute { + entity_id: id, + typename: typ.to_owned(), + value: value.to_string(), + }) + .collect::>(), + ) + .on_conflict_do_nothing() + .execute(connection)?; + + Ok(()) + } + + fn apply_model( + &self, + connection: &mut PgConnection, + model: &ProvModel, + ) -> Result<(), StoreError> { + for (_, ns) in model.namespaces.iter() { + self.apply_namespace(connection, ns)? + } + for (_, agent) in model.agents.iter() { + self.apply_agent(connection, agent)? + } + for (_, activity) in model.activities.iter() { + self.apply_activity(connection, activity)? + } + for (_, entity) in model.entities.iter() { + self.apply_entity(connection, entity)? + } + + for ((namespaceid, _), association) in model.association.iter() { + for association in association.iter() { + self.apply_was_associated_with(connection, namespaceid, association)?; + } + } + + for ((namespaceid, _), usage) in model.usage.iter() { + for usage in usage.iter() { + self.apply_used(connection, namespaceid, usage)?; + } + } + + for ((namespaceid, activity_id), was_informed_by) in model.was_informed_by.iter() { + for (_, informing_activity_id) in was_informed_by.iter() { + self.apply_was_informed_by( + connection, + namespaceid, + activity_id, + informing_activity_id, + )?; + } + } + + for ((namespaceid, _), generation) in model.generation.iter() { + for generation in generation.iter() { + self.apply_was_generated_by(connection, namespaceid, generation)?; + } + } + + for ((namespaceid, _), derivation) in model.derivation.iter() { + for derivation in derivation.iter() { + self.apply_derivation(connection, namespaceid, derivation)?; + } + } + + for ((namespaceid, _), delegation) in model.delegation.iter() { + for delegation in delegation.iter() { + self.apply_delegation(connection, namespaceid, delegation)?; + } + } + + for ((namespace_id, _), attribution) in model.attribution.iter() { + for attribution in attribution.iter() { + self.apply_was_attributed_to(connection, namespace_id, attribution)?; + } + } + + Ok(()) + } + + #[instrument(level = "trace", skip(self, connection), ret(Debug))] + fn apply_namespace( + &self, + connection: &mut PgConnection, + Namespace { ref external_id, ref uuid, .. }: &Namespace, + ) -> Result<(), StoreError> { + use schema::namespace::dsl; + diesel::insert_into(schema::namespace::table) + .values((dsl::external_id.eq(external_id), dsl::uuid.eq(hex::encode(uuid)))) + .on_conflict_do_nothing() + .execute(connection)?; + + Ok(()) + } + + pub fn apply_prov(&self, prov: &ProvModel) -> Result<(), StoreError> { + self.connection()? + .build_transaction() + .run(|connection| self.apply_model(connection, prov))?; + + Ok(()) + } + + #[instrument(skip_all)] + fn apply_used( + &self, + connection: &mut PgConnection, + namespace: &NamespaceId, + usage: &Usage, + ) -> Result<(), StoreError> { + let storedactivity = self.activity_by_activity_external_id_and_namespace( + connection, + usage.activity_id.external_id_part(), + namespace, + )?; + + let storedentity = self.entity_by_entity_external_id_and_namespace( + connection, + usage.entity_id.external_id_part(), + namespace, + )?; + + use schema::usage::dsl as link; + diesel::insert_into(schema::usage::table) + .values(( + &link::activity_id.eq(storedactivity.id), + &link::entity_id.eq(storedentity.id), + )) + .on_conflict_do_nothing() + .execute(connection)?; + + Ok(()) + } + + #[instrument(skip_all)] + fn apply_was_informed_by( + &self, + connection: &mut PgConnection, + namespace: &NamespaceId, + activity_id: &ActivityId, + informing_activity_id: &ActivityId, + ) -> Result<(), StoreError> { + let storedactivity = self.activity_by_activity_external_id_and_namespace( + connection, + activity_id.external_id_part(), + namespace, + )?; + + let storedinformingactivity = self.activity_by_activity_external_id_and_namespace( + connection, + informing_activity_id.external_id_part(), + namespace, + )?; + + use schema::wasinformedby::dsl as link; + diesel::insert_into(schema::wasinformedby::table) + .values(( + &link::activity_id.eq(storedactivity.id), + &link::informing_activity_id.eq(storedinformingactivity.id), + )) + .on_conflict_do_nothing() + .execute(connection)?; + + Ok(()) + } + + #[instrument(skip(self, connection))] + fn apply_was_associated_with( + &self, + connection: &mut PgConnection, + namespaceid: &common::prov::NamespaceId, + association: &Association, + ) -> Result<(), StoreError> { + let storedactivity = self.activity_by_activity_external_id_and_namespace( + connection, + association.activity_id.external_id_part(), + namespaceid, + )?; + + let storedagent = self.agent_by_agent_external_id_and_namespace( + connection, + association.agent_id.external_id_part(), + namespaceid, + )?; + + use schema::association::dsl as asoc; + let no_role = common::prov::Role("".to_string()); + diesel::insert_into(schema::association::table) + .values(( + &asoc::activity_id.eq(storedactivity.id), + &asoc::agent_id.eq(storedagent.id), + &asoc::role.eq(association.role.as_ref().unwrap_or(&no_role)), + )) + .on_conflict_do_nothing() + .execute(connection)?; + + Ok(()) + } + + #[instrument(skip(self, connection, namespace))] + fn apply_delegation( + &self, + connection: &mut PgConnection, + namespace: &common::prov::NamespaceId, + delegation: &Delegation, + ) -> Result<(), StoreError> { + let responsible = self.agent_by_agent_external_id_and_namespace( + connection, + delegation.responsible_id.external_id_part(), + namespace, + )?; + + let delegate = self.agent_by_agent_external_id_and_namespace( + connection, + delegation.delegate_id.external_id_part(), + namespace, + )?; + + let activity = { + if let Some(ref activity_id) = delegation.activity_id { + Some( + self.activity_by_activity_external_id_and_namespace( + connection, + activity_id.external_id_part(), + namespace, + )? + .id, + ) + } else { + None + } + }; + + use schema::delegation::dsl as link; + let no_role = common::prov::Role("".to_string()); + diesel::insert_into(schema::delegation::table) + .values(( + &link::responsible_id.eq(responsible.id), + &link::delegate_id.eq(delegate.id), + &link::activity_id.eq(activity.unwrap_or(-1)), + &link::role.eq(delegation.role.as_ref().unwrap_or(&no_role)), + )) + .on_conflict_do_nothing() + .execute(connection)?; + + Ok(()) + } + + #[instrument(skip(self, connection, namespace))] + fn apply_derivation( + &self, + connection: &mut PgConnection, + namespace: &common::prov::NamespaceId, + derivation: &Derivation, + ) -> Result<(), StoreError> { + let stored_generated = self.entity_by_entity_external_id_and_namespace( + connection, + derivation.generated_id.external_id_part(), + namespace, + )?; + + let stored_used = self.entity_by_entity_external_id_and_namespace( + connection, + derivation.used_id.external_id_part(), + namespace, + )?; + + let stored_activity = derivation + .activity_id + .as_ref() + .map(|activity_id| { + self.activity_by_activity_external_id_and_namespace( + connection, + activity_id.external_id_part(), + namespace, + ) + }) + .transpose()?; + + use schema::derivation::dsl as link; + diesel::insert_into(schema::derivation::table) + .values(( + &link::used_entity_id.eq(stored_used.id), + &link::generated_entity_id.eq(stored_generated.id), + &link::typ.eq(derivation.typ), + &link::activity_id.eq(stored_activity.map_or(-1, |activity| activity.id)), + )) + .on_conflict_do_nothing() + .execute(connection)?; + + Ok(()) + } + + #[instrument(skip_all)] + fn apply_was_generated_by( + &self, + connection: &mut PgConnection, + namespace: &common::prov::NamespaceId, + generation: &Generation, + ) -> Result<(), StoreError> { + let storedactivity = self.activity_by_activity_external_id_and_namespace( + connection, + generation.activity_id.external_id_part(), + namespace, + )?; + + let storedentity = self.entity_by_entity_external_id_and_namespace( + connection, + generation.generated_id.external_id_part(), + namespace, + )?; + + use schema::generation::dsl as link; + diesel::insert_into(schema::generation::table) + .values(( + &link::activity_id.eq(storedactivity.id), + &link::generated_entity_id.eq(storedentity.id), + )) + .on_conflict_do_nothing() + .execute(connection)?; + + Ok(()) + } + + #[instrument(skip(self, connection))] + fn apply_was_attributed_to( + &self, + connection: &mut PgConnection, + namespace_id: &common::prov::NamespaceId, + attribution: &Attribution, + ) -> Result<(), StoreError> { + let stored_entity = self.entity_by_entity_external_id_and_namespace( + connection, + attribution.entity_id.external_id_part(), + namespace_id, + )?; + + let stored_agent = self.agent_by_agent_external_id_and_namespace( + connection, + attribution.agent_id.external_id_part(), + namespace_id, + )?; + + use schema::attribution::dsl as attr; + let no_role = common::prov::Role("".to_string()); + diesel::insert_into(schema::attribution::table) + .values(( + &attr::entity_id.eq(stored_entity.id), + &attr::agent_id.eq(stored_agent.id), + &attr::role.eq(attribution.role.as_ref().unwrap_or(&no_role)), + )) + .on_conflict_do_nothing() + .execute(connection)?; + + Ok(()) + } + + pub fn connection( + &self, + ) -> Result>, StoreError> { + self.pool.get().map_err(StoreError::DbPool) + } + + #[instrument(skip_all)] + pub fn get_current_agent( + &self, + connection: &mut PgConnection, + ) -> Result { + use schema::agent::dsl; + Ok(schema::agent::table + .filter(dsl::current.ne(0)) + .first::(connection)?) + } + + /// Get the last fully synchronized offset + #[instrument(skip_all)] + pub fn get_last_block_id(&self) -> Result, StoreError> { + use schema::ledgersync::dsl; + self.connection()?.build_transaction().run(|connection| { + let block_id_and_tx = schema::ledgersync::table + .order_by(dsl::sync_time) + .select((dsl::bc_offset, dsl::tx_id)) + .first::<(Option, String)>(connection) + .map_err(StoreError::from)?; + + if let Some(block_id) = block_id_and_tx.0 { + Ok(Some(BlockId::try_from(&*block_id)?)) + } else { + Ok(None) + } + }) + } + + #[instrument(skip_all)] + pub fn namespace_by_external_id( + &self, + connection: &mut PgConnection, + namespace: &ExternalId, + ) -> Result<(NamespaceId, i32), StoreError> { + use self::schema::namespace::dsl; + + let ns = dsl::namespace + .filter(dsl::external_id.eq(namespace)) + .select((dsl::id, dsl::external_id, dsl::uuid)) + .first::<(i32, String, String)>(connection) + .optional()? + .ok_or(StoreError::RecordNotFound {})?; + + Ok((NamespaceId::from_external_id(ns.1, Uuid::from_str(&ns.2)?), ns.0)) + } + + #[instrument(skip_all)] + pub fn new(pool: Pool>) -> Result { + Ok(Store { pool }) + } + + #[instrument(skip_all)] + pub fn populate_prov_model_for_agent( + &self, + agent: query::Agent, + namespaceid: &NamespaceId, + model: &mut ProvModel, + connection: &mut PgConnection, + ) -> Result<(), StoreError> { + debug!(?agent, "Map agent to prov"); + + let attributes = schema::agent_attribute::table + .filter(schema::agent_attribute::agent_id.eq(&agent.id)) + .load::(connection)?; + + let agentid: AgentId = AgentId::from_external_id(&agent.external_id); + model.agents.insert( + (namespaceid.clone(), agentid.clone()), + Agent { + id: agentid, + namespaceid: namespaceid.clone(), + external_id: ExternalId::from(&agent.external_id), + domaintypeid: agent.domaintype.map(DomaintypeId::from_external_id), + attributes: attributes + .iter() + .map(|attr| { + serde_json::from_str(&attr.value) + .map_err(|e| StoreError::SerializationError(e.to_string())) + .map(|value| Attribute { typ: attr.typename.clone(), value }) + }) + .collect::, StoreError>>()?, + } + .into(), + ); + + for (responsible, activity, role) in schema::delegation::table + .filter(schema::delegation::delegate_id.eq(agent.id)) + .inner_join( + schema::agent::table.on(schema::delegation::responsible_id.eq(schema::agent::id)), + ) + .inner_join( + schema::activity::table + .on(schema::delegation::activity_id.eq(schema::activity::id)), + ) + .order(schema::agent::external_id) + .select(( + schema::agent::external_id, + schema::activity::external_id, + schema::delegation::role, + )) + .load::<(String, String, String)>(connection)? + { + model.qualified_delegation( + namespaceid, + &AgentId::from_external_id(responsible), + &AgentId::from_external_id(&agent.external_id), + { + if activity.contains("hidden entry for Option None") { + None + } else { + Some(ActivityId::from_external_id(activity)) + } + }, + { + if role.is_empty() { + None + } else { + Some(Role(role)) + } + }, + ); + } + + Ok(()) + } + + #[instrument(skip_all)] + pub fn populate_prov_model_for_activity( + &self, + activity: query::Activity, + namespaceid: &NamespaceId, + model: &mut ProvModel, + connection: &mut PgConnection, + ) -> Result<(), StoreError> { + use diesel::prelude::*; + use schema::{ + activity_attribute::dsl as activity_attr_dsl, + generation::dsl as generation_dsl, + usage::dsl as usage_dsl, + wasinformedby::dsl as wasinformedby_dsl, + association::dsl as association_dsl, + entity::dsl as entity_dsl, + agent::dsl as agent_dsl, + activity::dsl as activity_dsl, + }; + + let attributes = activity_attr_dsl::activity_attribute + .filter(activity_attr_dsl::activity_id.eq(&activity.id)) + .load::(connection)?; + + let id: ActivityId = ActivityId::from_external_id(&activity.external_id); + model.activities.insert( + (namespaceid.clone(), id.clone()), + Activity { + id: id.clone(), + namespace_id: namespaceid.clone(), + external_id: activity.external_id.into(), + started: activity.started.map(|x| Utc.from_utc_datetime(&x).into()), + ended: activity.ended.map(|x| Utc.from_utc_datetime(&x).into()), + domaintype_id: activity.domaintype.map(DomaintypeId::from_external_id), + attributes: attributes + .iter() + .map(|attr| { + serde_json::from_str(&attr.value) + .map_err(|e| StoreError::SerializationError(e.to_string())) + .map(|value| Attribute { typ: attr.typename.clone(), value }) + }) + .collect::, StoreError>>()?, + } + .into(), + ); + + let (generations, usages, wasinformedbys, associations): (Generations, Usages, WasInformedBys, Associations) = ( + generation_dsl::generation + .filter(generation_dsl::activity_id.eq(activity.id)) + .order(generation_dsl::activity_id.asc()) + .inner_join(entity_dsl::entity) + .select(entity_dsl::external_id) + .load::(connection)?, + usage_dsl::usage + .filter(usage_dsl::activity_id.eq(activity.id)) + .order(usage_dsl::activity_id.asc()) + .inner_join(entity_dsl::entity) + .select(entity_dsl::external_id) + .load::(connection)?, + wasinformedby_dsl::wasinformedby + .filter(wasinformedby_dsl::activity_id.eq(activity.id)) + .inner_join(activity_dsl::activity.on(wasinformedby_dsl::informing_activity_id.eq(activity_dsl::id))) + .select(activity_dsl::external_id) + .load::(connection)?, + association_dsl::association + .filter(association_dsl::activity_id.eq(activity.id)) + .order(association_dsl::activity_id.asc()) + .inner_join(agent_dsl::agent) + .select((agent_dsl::external_id, association_dsl::role)) + .load::<(String, String)>(connection)? + ); + + for generation in generations { + model.was_generated_by( + namespaceid.clone(), + &EntityId::from_external_id(generation), + &id, + ); + } + + for used in usages { + model.used(namespaceid.clone(), &id, &EntityId::from_external_id(used)); + } + + for wasinformedby in wasinformedbys { + model.was_informed_by( + namespaceid.clone(), + &id, + &ActivityId::from_external_id(wasinformedby), + ); + } + + for (agent, role) in associations { + model.qualified_association(namespaceid, &id, &AgentId::from_external_id(agent), { + if role.is_empty() { + None + } else { + Some(Role(role)) + } + }); + } + + debug!(populate_entity = %model.summarize()); + + Ok(()) + } + + #[instrument(skip_all)] + pub fn populate_prov_model_for_entity( + &self, + entity: query::Entity, + namespace_id: &NamespaceId, + model: &mut ProvModel, + connection: &mut PgConnection, + ) -> Result<(), StoreError> { + let query::Entity { id, namespace_id: _, domaintype, external_id } = entity; + + let entity_id = EntityId::from_external_id(&external_id); + + for (agent, role) in schema::attribution::table + .filter(schema::attribution::entity_id.eq(&id)) + .order(schema::attribution::entity_id.asc()) + .inner_join(schema::agent::table) + .select((schema::agent::external_id, schema::attribution::role)) + .load::<(String, String)>(connection)? + { + model.qualified_attribution( + namespace_id, + &entity_id, + &AgentId::from_external_id(agent), + { + if role.is_empty() { + None + } else { + Some(Role(role)) + } + }, + ); + } + + let attributes = schema::entity_attribute::table + .filter(schema::entity_attribute::entity_id.eq(&id)) + .load::(connection)?; + + model.entities.insert( + (namespace_id.clone(), entity_id.clone()), + Entity { + id: entity_id.clone(), + namespace_id: namespace_id.clone(), + external_id: external_id.into(), + domaintypeid: domaintype.map(DomaintypeId::from_external_id), + attributes: attributes + .iter() + .map(|attr| { + serde_json::from_str(&attr.value) + .map_err(|e| StoreError::SerializationError(e.to_string())) + .map(|value| Attribute { typ: attr.typename.clone(), value }) + }) + .collect::, StoreError>>()?, + } + .into(), + ); + + for (activity_id, activity_external_id, used_entity_id, typ) in schema::derivation::table + .filter(schema::derivation::generated_entity_id.eq(&id)) + .order(schema::derivation::generated_entity_id.asc()) + .inner_join( + schema::activity::table + .on(schema::derivation::activity_id.eq(schema::activity::id)), + ) + .inner_join( + schema::entity::table.on(schema::derivation::used_entity_id.eq(schema::entity::id)), + ) + .select(( + schema::derivation::activity_id, + schema::activity::external_id, + schema::entity::external_id, + schema::derivation::typ, + )) + .load::<(i32, String, String, i32)>(connection)? + { + let typ = DerivationType::try_from(typ) + .map_err(|_| StoreError::InvalidDerivationTypeRecord(typ))?; + + model.was_derived_from( + namespace_id.clone(), + typ, + EntityId::from_external_id(used_entity_id), + entity_id.clone(), + { + match activity_id { + -1 => None, + _ => Some(ActivityId::from_external_id(activity_external_id)), + } + }, + ); + } + + Ok(()) + } + + #[instrument(skip_all)] + pub fn load_prov_model_for_namespace( + &self, + connection: &mut PgConnection, + namespace: &NamespaceId, + ) -> Result { + let mut model = ProvModel::default(); + let (namespaceid, nsid) = + self.namespace_by_external_id(connection, namespace.external_id_part())?; + + let agents = schema::agent::table + .filter(schema::agent::namespace_id.eq(&nsid)) + .load::(connection)?; + + for agent in agents { + self.populate_prov_model_for_agent(agent, &namespaceid, &mut model, connection)?; + } + + let activities = schema::activity::table + .filter(schema::activity::namespace_id.eq(nsid)) + .load::(connection)?; + + for activity in activities { + self.populate_prov_model_for_activity(activity, &namespaceid, &mut model, connection)?; + } + + let entities = schema::entity::table + .filter(schema::entity::namespace_id.eq(nsid)) + .load::(connection)?; + + for entity in entities { + self.populate_prov_model_for_entity(entity, &namespaceid, &mut model, connection)?; + } + + Ok(model) + } + + /// Set the last fully synchronized offset + #[instrument(skip(self), level = "info")] + pub fn set_last_block_id( + &self, + block_id: &BlockId, + tx_id: ChronicleTransactionId, + ) -> Result<(), StoreError> { + use schema::ledgersync as dsl; + + Ok(self.connection()?.build_transaction().run(|connection| { + diesel::insert_into(dsl::table) + .values(( + dsl::bc_offset.eq(block_id.to_string()), + dsl::tx_id.eq(&*tx_id.to_string()), + (dsl::sync_time.eq(Utc::now().naive_utc())), + )) + .on_conflict(dsl::tx_id) + .do_update() + .set(dsl::sync_time.eq(Utc::now().naive_utc())) + .execute(connection) + .map(|_| ()) + })?) + } + + #[instrument(skip_all)] + pub fn apply_use_agent( + &self, + connection: &mut PgConnection, + external_id: &ExternalId, + namespace: &ExternalId, + ) -> Result<(), StoreError> { + let (_, nsid) = self.namespace_by_external_id(connection, namespace)?; + use schema::agent::dsl; + + diesel::update(schema::agent::table.filter(dsl::current.ne(0))) + .set(dsl::current.eq(0)) + .execute(connection)?; + + diesel::update( + schema::agent::table + .filter(dsl::external_id.eq(external_id).and(dsl::namespace_id.eq(nsid))), + ) + .set(dsl::current.eq(1)) + .execute(connection)?; + + Ok(()) + } + + #[instrument(skip_all)] + pub fn prov_model_for_agent_id( + &self, + connection: &mut PgConnection, + id: &AgentId, + ns: &ExternalId, + ) -> Result { + let agent = schema::agent::table + .inner_join(schema::namespace::dsl::namespace) + .filter(schema::agent::external_id.eq(id.external_id_part())) + .filter(schema::namespace::external_id.eq(ns)) + .select(query::Agent::as_select()) + .first(connection)?; + + let namespace = self.namespace_by_external_id(connection, ns)?.0; + + let mut model = ProvModel::default(); + self.populate_prov_model_for_agent(agent, &namespace, &mut model, connection)?; + Ok(model) + } + + #[instrument(skip_all)] + pub fn apply_prov_model_for_agent_id( + &self, + connection: &mut PgConnection, + mut model: ProvModel, + id: &AgentId, + ns: &ExternalId, + ) -> Result { + if let Some(agent) = schema::agent::table + .inner_join(schema::namespace::dsl::namespace) + .filter(schema::agent::external_id.eq(id.external_id_part())) + .filter(schema::namespace::external_id.eq(ns)) + .select(query::Agent::as_select()) + .first(connection) + .optional()? + { + let namespace = self.namespace_by_external_id(connection, ns)?.0; + self.populate_prov_model_for_agent(agent, &namespace, &mut model, connection)?; + } + Ok(model) + } + + #[instrument(skip_all)] + pub fn prov_model_for_activity_id( + &self, + connection: &mut PgConnection, + id: &ActivityId, + ns: &ExternalId, + ) -> Result { + let activity = schema::activity::table + .inner_join(schema::namespace::dsl::namespace) + .filter(schema::activity::external_id.eq(id.external_id_part())) + .filter(schema::namespace::external_id.eq(ns)) + .select(query::Activity::as_select()) + .first(connection)?; + + let namespace = self.namespace_by_external_id(connection, ns)?.0; + + let mut model = ProvModel::default(); + self.populate_prov_model_for_activity(activity, &namespace, &mut model, connection)?; + Ok(model) + } + + #[instrument(skip_all)] + pub fn apply_prov_model_for_activity_id( + &self, + connection: &mut PgConnection, + mut model: ProvModel, + id: &ActivityId, + ns: &ExternalId, + ) -> Result { + if let Some(activity) = schema::activity::table + .inner_join(schema::namespace::dsl::namespace) + .filter(schema::activity::external_id.eq(id.external_id_part())) + .filter(schema::namespace::external_id.eq(ns)) + .select(query::Activity::as_select()) + .first(connection) + .optional()? + { + let namespace = self.namespace_by_external_id(connection, ns)?.0; + self.populate_prov_model_for_activity(activity, &namespace, &mut model, connection)?; + } + Ok(model) + } + + #[instrument(skip_all)] + pub fn prov_model_for_entity_id( + &self, + connection: &mut PgConnection, + id: &EntityId, + ns: &ExternalId, + ) -> Result { + let entity = schema::entity::table + .inner_join(schema::namespace::dsl::namespace) + .filter(schema::entity::external_id.eq(id.external_id_part())) + .filter(schema::namespace::external_id.eq(ns)) + .select(query::Entity::as_select()) + .first(connection)?; + + let namespace = self.namespace_by_external_id(connection, ns)?.0; + + let mut model = ProvModel::default(); + self.populate_prov_model_for_entity(entity, &namespace, &mut model, connection)?; + Ok(model) + } + + #[instrument(skip_all)] + pub fn apply_prov_model_for_entity_id( + &self, + connection: &mut PgConnection, + mut model: ProvModel, + id: &EntityId, + ns: &ExternalId, + ) -> Result { + if let Some(entity) = schema::entity::table + .inner_join(schema::namespace::dsl::namespace) + .filter(schema::entity::external_id.eq(id.external_id_part())) + .filter(schema::namespace::external_id.eq(ns)) + .select(query::Entity::as_select()) + .first(connection) + .optional()? + { + let namespace = self.namespace_by_external_id(connection, ns)?.0; + self.populate_prov_model_for_entity(entity, &namespace, &mut model, connection)?; + } + Ok(model) + } + + #[instrument(skip_all)] + pub fn prov_model_for_usage( + &self, + connection: &mut PgConnection, + mut model: ProvModel, + id: &EntityId, + activity_id: &ActivityId, + ns: &ExternalId, + ) -> Result { + if let Some(entity) = schema::entity::table + .inner_join(schema::namespace::dsl::namespace) + .filter(schema::entity::external_id.eq(id.external_id_part())) + .filter(schema::namespace::external_id.eq(ns)) + .select(query::Entity::as_select()) + .first(connection) + .optional()? + { + if let Some(activity) = schema::activity::table + .inner_join(schema::namespace::dsl::namespace) + .filter(schema::activity::external_id.eq(id.external_id_part())) + .filter(schema::namespace::external_id.eq(ns)) + .select(query::Activity::as_select()) + .first(connection) + .optional()? + { + let namespace = self.namespace_by_external_id(connection, ns)?.0; + for used in schema::usage::table + .filter(schema::usage::activity_id.eq(activity.id)) + .order(schema::usage::activity_id.asc()) + .inner_join(schema::entity::table) + .select(schema::entity::external_id) + .load::(connection)? + { + model.used(namespace.clone(), activity_id, &EntityId::from_external_id(used)); + } + self.populate_prov_model_for_entity(entity, &namespace, &mut model, connection)?; + self.populate_prov_model_for_activity(activity, &namespace, &mut model, connection)?; + } + } + Ok(model) + } } diff --git a/crates/chronicle-persistence/src/query.rs b/crates/chronicle-persistence/src/query.rs index 0fd03fe5b..8b53edfc4 100644 --- a/crates/chronicle-persistence/src/query.rs +++ b/crates/chronicle-persistence/src/query.rs @@ -5,62 +5,62 @@ use diesel::prelude::*; #[derive(Queryable, Selectable)] #[diesel(table_name = namespace)] pub struct Namespace { - pub external_id: String, - pub uuid: String, + pub external_id: String, + pub uuid: String, } #[derive(Queryable)] pub struct LedgerSync { - pub bc_offset: String, - pub sync_time: Option, + pub bc_offset: String, + pub sync_time: Option, } #[derive(Insertable)] #[diesel(table_name = namespace)] pub struct NewNamespace<'a> { - pub external_id: &'a str, - pub uuid: &'a str, + pub external_id: &'a str, + pub uuid: &'a str, } #[derive(Insertable)] #[diesel(table_name = ledgersync)] pub struct NewOffset<'a> { - pub bc_offset: &'a str, - pub sync_time: Option, + pub bc_offset: &'a str, + pub sync_time: Option, } #[derive(Insertable, Queryable, Selectable)] #[diesel(table_name = entity_attribute)] pub struct EntityAttribute { - pub entity_id: i32, - pub typename: String, - pub value: String, + pub entity_id: i32, + pub typename: String, + pub value: String, } #[derive(Insertable, Queryable, Selectable)] #[diesel(table_name = activity_attribute)] pub struct ActivityAttribute { - pub activity_id: i32, - pub typename: String, - pub value: String, + pub activity_id: i32, + pub typename: String, + pub value: String, } #[derive(Insertable, Queryable, Selectable)] #[diesel(table_name = agent_attribute)] pub struct AgentAttribute { - pub agent_id: i32, - pub typename: String, - pub value: String, + pub agent_id: i32, + pub typename: String, + pub value: String, } #[derive(Insertable)] #[diesel(table_name = activity)] pub struct NewActivity<'a> { - pub external_id: &'a str, - pub namespace_id: i32, - pub started: Option, - pub ended: Option, - pub domaintype: Option<&'a str>, + pub external_id: &'a str, + pub namespace_id: i32, + pub started: Option, + pub ended: Option, + pub domaintype: Option<&'a str>, } #[derive(Debug, Queryable, Selectable, Identifiable, Associations, PartialEq)] @@ -71,12 +71,12 @@ pub struct NewActivity<'a> { #[diesel(belongs_to(Usage, foreign_key = id))] #[diesel(table_name = agent)] pub struct Agent { - pub id: i32, - pub external_id: String, - pub namespace_id: i32, - pub domaintype: Option, - pub current: i32, - pub identity_id: Option, + pub id: i32, + pub external_id: String, + pub namespace_id: i32, + pub domaintype: Option, + pub current: i32, + pub identity_id: Option, } #[derive(Debug, Queryable, Selectable, Identifiable, PartialEq)] @@ -84,34 +84,34 @@ pub struct Agent { #[diesel(belongs_to(Generation))] #[diesel(table_name = activity)] pub struct Activity { - pub id: i32, - pub external_id: String, - pub namespace_id: i32, - pub domaintype: Option, - pub started: Option, - pub ended: Option, + pub id: i32, + pub external_id: String, + pub namespace_id: i32, + pub domaintype: Option, + pub started: Option, + pub ended: Option, } #[derive(Debug, Queryable, Identifiable, Associations, Selectable)] -#[diesel(belongs_to(Generation, foreign_key=id))] -#[diesel(belongs_to(Usage, foreign_key=id))] -#[diesel(belongs_to(Attribution, foreign_key=id))] -#[diesel(belongs_to(Derivation, foreign_key=id))] +#[diesel(belongs_to(Generation, foreign_key = id))] +#[diesel(belongs_to(Usage, foreign_key = id))] +#[diesel(belongs_to(Attribution, foreign_key = id))] +#[diesel(belongs_to(Derivation, foreign_key = id))] #[diesel(table_name = entity)] pub struct Entity { - pub id: i32, - pub external_id: String, - pub namespace_id: i32, - pub domaintype: Option, + pub id: i32, + pub external_id: String, + pub namespace_id: i32, + pub domaintype: Option, } #[derive(Debug, Queryable, Selectable, Identifiable, Associations, PartialEq)] #[diesel(table_name = wasinformedby)] #[diesel(primary_key(activity_id, informing_activity_id))] -#[diesel(belongs_to(Activity, foreign_key = activity_id , foreign_key = informing_activity_id))] +#[diesel(belongs_to(Activity, foreign_key = activity_id, foreign_key = informing_activity_id))] pub struct WasInformedBy { - activity_id: i32, - informing_activity_id: i32, + activity_id: i32, + informing_activity_id: i32, } #[derive(Debug, Queryable, Selectable, Identifiable, Associations, PartialEq)] @@ -120,8 +120,8 @@ pub struct WasInformedBy { #[diesel(belongs_to(Activity))] #[diesel(belongs_to(Entity, foreign_key = generated_entity_id))] pub struct Generation { - activity_id: i32, - generated_entity_id: i32, + activity_id: i32, + generated_entity_id: i32, } #[derive(Debug, Queryable, Selectable, Identifiable, Associations, PartialEq)] @@ -130,8 +130,8 @@ pub struct Generation { #[diesel(belongs_to(Activity))] #[diesel(belongs_to(Entity))] pub struct Usage { - activity_id: i32, - entity_id: i32, + activity_id: i32, + entity_id: i32, } #[derive(Debug, Queryable, Selectable, Identifiable, Associations, PartialEq)] @@ -140,9 +140,9 @@ pub struct Usage { #[diesel(belongs_to(Activity))] #[diesel(primary_key(agent_id, activity_id, role))] pub struct Association { - agent_id: i32, - activity_id: i32, - role: String, + agent_id: i32, + activity_id: i32, + role: String, } #[derive(Debug, Queryable, Selectable, Associations, Identifiable, PartialEq)] @@ -151,9 +151,9 @@ pub struct Association { #[diesel(belongs_to(Agent))] #[diesel(belongs_to(Entity))] pub struct Attribution { - agent_id: i32, - entity_id: i32, - role: String, + agent_id: i32, + entity_id: i32, + role: String, } #[derive(Debug, Queryable, Selectable, Associations, Identifiable, PartialEq)] @@ -162,10 +162,10 @@ pub struct Attribution { #[diesel(belongs_to(Activity))] #[diesel(primary_key(delegate_id, responsible_id, activity_id, role))] pub struct Delegation { - delegate_id: i32, - responsible_id: i32, - activity_id: i32, - role: String, + delegate_id: i32, + responsible_id: i32, + activity_id: i32, + role: String, } #[derive(Debug, Queryable, Selectable, Identifiable, Associations, PartialEq)] @@ -174,17 +174,17 @@ pub struct Delegation { #[diesel(belongs_to(Entity, foreign_key = generated_entity_id, foreign_key = used_entity_id))] #[diesel(primary_key(activity_id, used_entity_id, generated_entity_id, typ))] pub struct Derivation { - activity_id: i32, - used_entity_id: i32, - generated_entity_id: i32, - typ: i32, + activity_id: i32, + used_entity_id: i32, + generated_entity_id: i32, + typ: i32, } #[derive(Insertable, Queryable, Selectable)] #[diesel(table_name = agent)] pub struct NewAgent<'a> { - pub external_id: &'a str, - pub namespace_id: i32, - pub current: i32, - pub domaintype: Option<&'a str>, + pub external_id: &'a str, + pub namespace_id: i32, + pub current: i32, + pub domaintype: Option<&'a str>, } diff --git a/crates/chronicle-persistence/src/queryable.rs b/crates/chronicle-persistence/src/queryable.rs index 9dfc97806..370cd7d87 100644 --- a/crates/chronicle-persistence/src/queryable.rs +++ b/crates/chronicle-persistence/src/queryable.rs @@ -5,39 +5,39 @@ use diesel::{Queryable, Selectable}; #[derive(Default, Queryable, Selectable, SimpleObject)] #[diesel(table_name = crate::schema::agent)] pub struct Agent { - pub id: i32, - pub external_id: String, - pub namespace_id: i32, - pub domaintype: Option, - pub current: i32, - pub identity_id: Option, + pub id: i32, + pub external_id: String, + pub namespace_id: i32, + pub domaintype: Option, + pub current: i32, + pub identity_id: Option, } #[derive(Default, Queryable, Selectable, SimpleObject)] #[diesel(table_name = crate::schema::activity)] pub struct Activity { - pub id: i32, - pub external_id: String, - pub namespace_id: i32, - pub domaintype: Option, - pub started: Option, - pub ended: Option, + pub id: i32, + pub external_id: String, + pub namespace_id: i32, + pub domaintype: Option, + pub started: Option, + pub ended: Option, } #[derive(Queryable, Selectable, SimpleObject)] #[diesel(table_name = crate::schema::entity)] pub struct Entity { - pub id: i32, - pub external_id: String, - pub namespace_id: i32, - pub domaintype: Option, + pub id: i32, + pub external_id: String, + pub namespace_id: i32, + pub domaintype: Option, } #[derive(Default, Queryable)] pub struct Namespace { - _id: i32, - uuid: String, - external_id: String, + _id: i32, + uuid: String, + external_id: String, } #[Object] @@ -47,11 +47,11 @@ pub struct Namespace { /// In order to work on the same namespace discrete Chronicle instances must share /// the uuid part. impl Namespace { - async fn external_id(&self) -> &str { - &self.external_id - } + async fn external_id(&self) -> &str { + &self.external_id + } - async fn uuid(&self) -> &str { - &self.uuid - } + async fn uuid(&self) -> &str { + &self.uuid + } } diff --git a/crates/chronicle-signing/Cargo.toml b/crates/chronicle-signing/Cargo.toml index ee44ce2af..0db125aa0 100644 --- a/crates/chronicle-signing/Cargo.toml +++ b/crates/chronicle-signing/Cargo.toml @@ -1,23 +1,23 @@ [package] edition = "2021" -name = "chronicle-signing" +name = "chronicle-signing" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-trait = { workspace = true } -k256 = { workspace = true } -rand = { workspace = true } -secret-vault = { workspace = true } +async-trait = { workspace = true } +k256 = { workspace = true } +rand = { workspace = true } +secret-vault = { workspace = true } secret-vault-value = { workspace = true } -thiserror = { workspace = true } -tokio = { workspace = true } -tokio-stream = { workspace = true } -tracing = { workspace = true } -url = { workspace = true } -vaultrs = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tokio-stream = { workspace = true } +tracing = { workspace = true } +url = { workspace = true } +vaultrs = { workspace = true } [dev-dependencies] testcontainers = { workspace = true } diff --git a/crates/chronicle-signing/src/embedded_secret_manager_source.rs b/crates/chronicle-signing/src/embedded_secret_manager_source.rs index d64d14fdc..bb59dd9e6 100644 --- a/crates/chronicle-signing/src/embedded_secret_manager_source.rs +++ b/crates/chronicle-signing/src/embedded_secret_manager_source.rs @@ -1,14 +1,14 @@ use async_trait::async_trait; use k256::{ - pkcs8::{EncodePrivateKey, LineEnding}, - SecretKey, + pkcs8::{EncodePrivateKey, LineEnding}, + SecretKey, }; use rand::{rngs::StdRng, SeedableRng}; use secret_vault::{Secret, SecretMetadata, SecretVaultRef, SecretVaultResult, SecretsSource}; use secret_vault_value::SecretValue; use std::{ - collections::{BTreeMap, HashMap}, - sync::Arc, + collections::{BTreeMap, HashMap}, + sync::Arc, }; use tokio::sync::Mutex; use tracing::debug; @@ -16,61 +16,61 @@ use tracing::debug; use crate::SecretError; pub struct EmbeddedSecretManagerSource { - secrets: Arc>>>, - seeds: BTreeMap, + secrets: Arc>>>, + seeds: BTreeMap, } impl EmbeddedSecretManagerSource { - pub fn new() -> Self { - Self { secrets: Arc::new(Mutex::new(HashMap::new())), seeds: BTreeMap::default() } - } + pub fn new() -> Self { + Self { secrets: Arc::new(Mutex::new(HashMap::new())), seeds: BTreeMap::default() } + } - pub fn new_seeded(seeds: BTreeMap) -> Self { - Self { secrets: Arc::new(Mutex::new(HashMap::new())), seeds } - } + pub fn new_seeded(seeds: BTreeMap) -> Self { + Self { secrets: Arc::new(Mutex::new(HashMap::new())), seeds } + } } fn new_signing_key(name: &str, seeds: &BTreeMap) -> Result, SecretError> { - let secret = if let Some(seed) = seeds.get(name) { - SecretKey::from_be_bytes(seed).map_err(|_| SecretError::BadSeed)? - } else { - SecretKey::random(StdRng::from_entropy()) - }; - let privpem = secret - .to_pkcs8_pem(LineEnding::CRLF) - .map_err(|_| SecretError::InvalidPrivateKey)?; + let secret = if let Some(seed) = seeds.get(name) { + SecretKey::from_be_bytes(seed).map_err(|_| SecretError::BadSeed)? + } else { + SecretKey::random(StdRng::from_entropy()) + }; + let privpem = secret + .to_pkcs8_pem(LineEnding::CRLF) + .map_err(|_| SecretError::InvalidPrivateKey)?; - Ok(privpem.as_bytes().into()) + Ok(privpem.as_bytes().into()) } #[async_trait] impl SecretsSource for EmbeddedSecretManagerSource { - fn name(&self) -> String { - "EmbeddedSecretManager".to_string() - } + fn name(&self) -> String { + "EmbeddedSecretManager".to_string() + } - // Simply create and cache a new signing key for each novel reference - async fn get_secrets( - &self, - references: &[SecretVaultRef], - ) -> SecretVaultResult> { - debug!(get_secrets=?references, "Getting secrets from embedded source"); + // Simply create and cache a new signing key for each novel reference + async fn get_secrets( + &self, + references: &[SecretVaultRef], + ) -> SecretVaultResult> { + debug!(get_secrets=?references, "Getting secrets from embedded source"); - let mut result_map: HashMap = HashMap::new(); - let mut secrets = self.secrets.lock().await; - for secret_ref in references.iter() { - let secret = secrets.entry(secret_ref.clone()).or_insert_with(|| { - let secret = - new_signing_key(secret_ref.key.secret_name.as_ref(), &self.seeds).unwrap(); - secret.to_vec() - }); + let mut result_map: HashMap = HashMap::new(); + let mut secrets = self.secrets.lock().await; + for secret_ref in references.iter() { + let secret = secrets.entry(secret_ref.clone()).or_insert_with(|| { + let secret = + new_signing_key(secret_ref.key.secret_name.as_ref(), &self.seeds).unwrap(); + secret.to_vec() + }); - let secret_value = SecretValue::from(secret); - let metadata = SecretMetadata::create_from_ref(secret_ref); + let secret_value = SecretValue::from(secret); + let metadata = SecretMetadata::create_from_ref(secret_ref); - result_map.insert(secret_ref.clone(), Secret::new(secret_value, metadata)); - } + result_map.insert(secret_ref.clone(), Secret::new(secret_value, metadata)); + } - Ok(result_map) - } + Ok(result_map) + } } diff --git a/crates/chronicle-signing/src/error.rs b/crates/chronicle-signing/src/error.rs index 76f74e4aa..5677973a0 100644 --- a/crates/chronicle-signing/src/error.rs +++ b/crates/chronicle-signing/src/error.rs @@ -2,19 +2,19 @@ use thiserror::Error; #[derive(Error, Debug)] pub enum SecretError { - #[error("Invalid public key")] - InvalidPublicKey, - #[error("Invalid private key")] - InvalidPrivateKey, - #[error("No public key found")] - NoPublicKeyFound, - #[error("No private key found")] - NoPrivateKeyFound, + #[error("Invalid public key")] + InvalidPublicKey, + #[error("Invalid private key")] + InvalidPrivateKey, + #[error("No public key found")] + NoPublicKeyFound, + #[error("No private key found")] + NoPrivateKeyFound, - #[error("Vault {source}")] - SecretVault { - #[from] - #[source] - source: anyhow::Error, - }, + #[error("Vault {source}")] + SecretVault { + #[from] + #[source] + source: anyhow::Error, + }, } diff --git a/crates/chronicle-signing/src/lib.rs b/crates/chronicle-signing/src/lib.rs index 1fb875d57..c70686ec9 100644 --- a/crates/chronicle-signing/src/lib.rs +++ b/crates/chronicle-signing/src/lib.rs @@ -1,22 +1,23 @@ use k256::{ - ecdsa::{ - signature::{Signer, Verifier}, - Signature, SigningKey, VerifyingKey, - }, - pkcs8::DecodePrivateKey, + ecdsa::{ + signature::{Signer, Verifier}, + Signature, SigningKey, VerifyingKey, + }, + pkcs8::DecodePrivateKey, }; use secret_vault::{ - errors::SecretVaultError, FilesSource, FilesSourceOptions, MultipleSecretsSources, SecretName, - SecretNamespace, SecretVaultBuilder, SecretVaultRef, SecretVaultView, + errors::SecretVaultError, FilesSource, FilesSourceOptions, MultipleSecretsSources, SecretName, + SecretNamespace, SecretVaultBuilder, SecretVaultRef, SecretVaultView, }; use std::{ - collections::BTreeMap, - path::{Path, PathBuf}, - sync::Arc, + collections::BTreeMap, + path::{Path, PathBuf}, + sync::Arc, }; use thiserror::Error; use tracing::instrument; use url::Url; + mod embedded_secret_manager_source; mod vault_secret_manager_source; @@ -29,526 +30,544 @@ pub static OPA_PK: &str = "opa-pk"; #[derive(Error, Debug)] pub enum SecretError { - #[error("Invalid public key")] - InvalidPublicKey, - #[error("Invalid private key")] - InvalidPrivateKey, - #[error("No public key found")] - NoPublicKeyFound, - #[error("No private key found")] - NoPrivateKeyFound, - - #[error("Vault {source}")] - SecretVault { - #[from] - #[source] - source: SecretVaultError, - }, - - #[error("Bad BIP39 seed")] - BadSeed, + #[error("Invalid public key")] + InvalidPublicKey, + #[error("Invalid private key")] + InvalidPrivateKey, + #[error("No public key found")] + NoPublicKeyFound, + #[error("No private key found")] + NoPrivateKeyFound, + + #[error("Vault {source}")] + SecretVault { + #[from] + #[source] + source: SecretVaultError, + }, + + #[error("Bad BIP39 seed")] + BadSeed, } pub enum ChronicleSecretsOptions { - // Connect to hashicorp vault for secrets - Vault(vault_secret_manager_source::VaultSecretManagerSourceOptions), - // Generate secrets from entropy in memory on demand - Embedded, - - //Seed secrets with name using a map of secret name to BIP39 seed phrase - Seeded(BTreeMap), - //Filesystem based keys - Filesystem(PathBuf), + // Connect to hashicorp vault for secrets + Vault(vault_secret_manager_source::VaultSecretManagerSourceOptions), + // Generate secrets from entropy in memory on demand + Embedded, + + //Seed secrets with name using a map of secret name to BIP39 seed phrase + Seeded(BTreeMap), + //Filesystem based keys + Filesystem(PathBuf), } impl ChronicleSecretsOptions { - // Get secrets from Hashicorp vault - pub fn stored_in_vault( - vault_url: &Url, - token: &str, - mount_path: &str, - ) -> ChronicleSecretsOptions { - ChronicleSecretsOptions::Vault( - vault_secret_manager_source::VaultSecretManagerSourceOptions::new( - vault_url.clone(), - token, - mount_path, - ), - ) - } - - // Load secrets from filesystem at path - pub fn stored_at_path(path: &Path) -> ChronicleSecretsOptions { - ChronicleSecretsOptions::Filesystem(path.to_owned()) - } - - // Generate secrets in memory on demand - pub fn generate_in_memory() -> ChronicleSecretsOptions { - ChronicleSecretsOptions::Embedded - } - - // Use supplied seeds, or fall back to entropy - pub fn seeded(seeds: BTreeMap) -> ChronicleSecretsOptions { - ChronicleSecretsOptions::Seeded(seeds) - } + // Get secrets from Hashicorp vault + pub fn stored_in_vault( + vault_url: &Url, + token: &str, + mount_path: &str, + ) -> ChronicleSecretsOptions { + ChronicleSecretsOptions::Vault( + vault_secret_manager_source::VaultSecretManagerSourceOptions::new( + vault_url.clone(), + token, + mount_path, + ), + ) + } + + // Load secrets from filesystem at path + pub fn stored_at_path(path: &Path) -> ChronicleSecretsOptions { + ChronicleSecretsOptions::Filesystem(path.to_owned()) + } + + // Generate secrets in memory on demand + pub fn generate_in_memory() -> ChronicleSecretsOptions { + ChronicleSecretsOptions::Embedded + } + + // Use supplied seeds, or fall back to entropy + pub fn seeded(seeds: BTreeMap) -> ChronicleSecretsOptions { + ChronicleSecretsOptions::Seeded(seeds) + } } #[derive(Clone)] pub struct ChronicleSigning { - vault: Arc>>, + vault: Arc>>, } impl core::fmt::Debug for ChronicleSigning { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("ChronicleSecrets").finish() - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ChronicleSecrets").finish() + } } impl ChronicleSigning { - pub async fn new( - // Secrets are namespace / name pairs - required_secret_names: Vec<(String, String)>, - // Secret stores are namespaced - options: Vec<(String, ChronicleSecretsOptions)>, - ) -> Result { - let mut multi_source = MultipleSecretsSources::new(); - let required_secret_refs: Vec<_> = required_secret_names - .into_iter() - .map(|(namespace, name)| { - SecretVaultRef::new(SecretName::new(name)) - .with_namespace(SecretNamespace::new(namespace)) - }) - .collect(); - - for options in options { - match options { - (namespace, ChronicleSecretsOptions::Embedded) => { - let source = embedded_secret_manager_source::EmbeddedSecretManagerSource::new(); - multi_source = - multi_source.add_source(&SecretNamespace::new(namespace), source); - }, - (namespace, ChronicleSecretsOptions::Seeded(seeds)) => { - let source = - embedded_secret_manager_source::EmbeddedSecretManagerSource::new_seeded( - seeds, - ); - multi_source = - multi_source.add_source(&SecretNamespace::new(namespace), source); - }, - (namespace, ChronicleSecretsOptions::Vault(options)) => { - let source = - vault_secret_manager_source::VaultSecretManagerSource::with_options( - options, - ) - .await?; - multi_source = - multi_source.add_source(&SecretNamespace::new(namespace), source); - }, - (namespace, ChronicleSecretsOptions::Filesystem(path)) => { - let source = FilesSource::with_options(FilesSourceOptions { - root_path: Some(path.into_boxed_path()), - }); - multi_source = - multi_source.add_source(&SecretNamespace::new(namespace), source); - }, - } - } - - let vault = SecretVaultBuilder::with_source(multi_source) - .with_secret_refs(required_secret_refs.iter().collect()) - .build()?; - - vault.refresh().await?; - Ok(Self { vault: Arc::new(tokio::sync::Mutex::new(Box::new(vault.viewer()))) }) - } + pub async fn new( + // Secrets are namespace / name pairs + required_secret_names: Vec<(String, String)>, + // Secret stores are namespaced + options: Vec<(String, ChronicleSecretsOptions)>, + ) -> Result { + let mut multi_source = MultipleSecretsSources::new(); + let required_secret_refs: Vec<_> = required_secret_names + .into_iter() + .map(|(namespace, name)| { + SecretVaultRef::new(SecretName::new(name)) + .with_namespace(SecretNamespace::new(namespace)) + }) + .collect(); + + for options in options { + match options { + (namespace, ChronicleSecretsOptions::Embedded) => { + let source = embedded_secret_manager_source::EmbeddedSecretManagerSource::new(); + multi_source = + multi_source.add_source(&SecretNamespace::new(namespace), source); + } + (namespace, ChronicleSecretsOptions::Seeded(seeds)) => { + let source = + embedded_secret_manager_source::EmbeddedSecretManagerSource::new_seeded( + seeds, + ); + multi_source = + multi_source.add_source(&SecretNamespace::new(namespace), source); + } + (namespace, ChronicleSecretsOptions::Vault(options)) => { + let source = + vault_secret_manager_source::VaultSecretManagerSource::with_options( + options, + ) + .await?; + multi_source = + multi_source.add_source(&SecretNamespace::new(namespace), source); + } + (namespace, ChronicleSecretsOptions::Filesystem(path)) => { + let source = FilesSource::with_options(FilesSourceOptions { + root_path: Some(path.into_boxed_path()), + }); + multi_source = + multi_source.add_source(&SecretNamespace::new(namespace), source); + } + } + } + + let vault = SecretVaultBuilder::with_source(multi_source) + .with_secret_refs(required_secret_refs.iter().collect()) + .build()?; + + vault.refresh().await?; + Ok(Self { vault: Arc::new(tokio::sync::Mutex::new(Box::new(vault.viewer()))) }) + } } #[async_trait::async_trait] pub trait WithSecret { - async fn with_signing_key( - &self, - secret_namespace: &str, - secret_name: &str, - f: F, - ) -> Result - where - F: Fn(SigningKey) -> T, - F: Send, - T: Send; - async fn with_verifying_key( - &self, - secret_namespace: &str, - secret_name: &str, - f: F, - ) -> Result - where - F: Fn(VerifyingKey) -> T, - F: Send, - T: Send; - - async fn verifying_key( - &self, - secret_namespace: &str, - secret_name: &str, - ) -> Result; + async fn with_signing_key( + &self, + secret_namespace: &str, + secret_name: &str, + f: F, + ) -> Result + where + F: Fn(SigningKey) -> T, + F: Send, + T: Send; + async fn with_verifying_key( + &self, + secret_namespace: &str, + secret_name: &str, + f: F, + ) -> Result + where + F: Fn(VerifyingKey) -> T, + F: Send, + T: Send; + + async fn verifying_key( + &self, + secret_namespace: &str, + secret_name: &str, + ) -> Result; } #[async_trait::async_trait] pub trait OwnedSecret { - async fn copy_signing_key( - &self, - secret_namespace: &str, - secret_name: &str, - ) -> Result; + async fn copy_signing_key( + &self, + secret_namespace: &str, + secret_name: &str, + ) -> Result; } #[async_trait::async_trait] impl OwnedSecret for T { - async fn copy_signing_key( - &self, - secret_namespace: &str, - secret_name: &str, - ) -> Result { - let secret = - WithSecret::with_signing_key(self, secret_namespace, secret_name, |secret| secret) - .await?; - - Ok(secret) - } + async fn copy_signing_key( + &self, + secret_namespace: &str, + secret_name: &str, + ) -> Result { + let secret = + WithSecret::with_signing_key(self, secret_namespace, secret_name, |secret| secret) + .await?; + + Ok(secret) + } } #[async_trait::async_trait] impl WithSecret for ChronicleSigning { - async fn with_signing_key( - &self, - secret_namespace: &str, - secret_name: &str, - f: F, - ) -> Result - where - F: Fn(SigningKey) -> T, - F: Send, - T: Send, - { - let secret_ref = SecretVaultRef::new(SecretName::new(secret_name.to_owned())) - .with_namespace(secret_namespace.into()); - let secret = self.vault.lock().await.require_secret_by_ref(&secret_ref).await?; - - let signing_result = secret.value.exposed_in_as_str(|secret| { - ( - // Not semantically the same thing as we re-use f - SigningKey::from_pkcs8_pem(&secret) - .map_err(|_| SecretError::InvalidPrivateKey) - .map(&f), - secret, - ) - }); - - Ok(signing_result?) - } - - async fn with_verifying_key( - &self, - secret_namespace: &str, - secret_name: &str, - f: F, - ) -> Result - where - F: Fn(VerifyingKey) -> T, - F: Send, - T: Send, - { - let secret_ref = SecretVaultRef::new(SecretName::new(secret_name.to_owned())) - .with_namespace(secret_namespace.into()); - let secret = self.vault.lock().await.require_secret_by_ref(&secret_ref).await?; - - let signing_result = secret.value.exposed_in_as_str(|secret| { - ( - SigningKey::from_pkcs8_pem(&secret) - .map_err(|_| SecretError::InvalidPrivateKey) - .map(|signing_key| f(signing_key.verifying_key())), - secret, - ) - }); - - Ok(signing_result?) - } - - async fn verifying_key( - &self, - secret_namespace: &str, - secret_name: &str, - ) -> Result { - let secret_ref = SecretVaultRef::new(SecretName::new(secret_name.to_owned())) - .with_namespace(secret_namespace.into()); - let secret = self.vault.lock().await.require_secret_by_ref(&secret_ref).await?; - - let key = secret.value.exposed_in_as_str(|secret| { - ( - SigningKey::from_pkcs8_pem(&secret) - .map_err(|_| SecretError::InvalidPrivateKey) - .map(|signing_key| signing_key.verifying_key()), - secret, - ) - }); - - Ok(key?) - } + async fn with_signing_key( + &self, + secret_namespace: &str, + secret_name: &str, + f: F, + ) -> Result + where + F: Fn(SigningKey) -> T, + F: Send, + T: Send, + { + let secret_ref = SecretVaultRef::new(SecretName::new(secret_name.to_owned())) + .with_namespace(secret_namespace.into()); + let secret = self.vault.lock().await.require_secret_by_ref(&secret_ref).await?; + + let signing_result = secret.value.exposed_in_as_str(|secret| { + ( + // Not semantically the same thing as we re-use f + SigningKey::from_pkcs8_pem(&secret) + .map_err(|_| SecretError::InvalidPrivateKey) + .map(&f), + secret, + ) + }); + + Ok(signing_result?) + } + + async fn with_verifying_key( + &self, + secret_namespace: &str, + secret_name: &str, + f: F, + ) -> Result + where + F: Fn(VerifyingKey) -> T, + F: Send, + T: Send, + { + let secret_ref = SecretVaultRef::new(SecretName::new(secret_name.to_owned())) + .with_namespace(secret_namespace.into()); + let secret = self.vault.lock().await.require_secret_by_ref(&secret_ref).await?; + + let signing_result = secret.value.exposed_in_as_str(|secret| { + ( + SigningKey::from_pkcs8_pem(&secret) + .map_err(|_| SecretError::InvalidPrivateKey) + .map(|signing_key| f(signing_key.verifying_key())), + secret, + ) + }); + + Ok(signing_result?) + } + + async fn verifying_key( + &self, + secret_namespace: &str, + secret_name: &str, + ) -> Result { + let secret_ref = SecretVaultRef::new(SecretName::new(secret_name.to_owned())) + .with_namespace(secret_namespace.into()); + let secret = self.vault.lock().await.require_secret_by_ref(&secret_ref).await?; + + let key = secret.value.exposed_in_as_str(|secret| { + ( + SigningKey::from_pkcs8_pem(&secret) + .map_err(|_| SecretError::InvalidPrivateKey) + .map(|signing_key| signing_key.verifying_key()), + secret, + ) + }); + + Ok(key?) + } } /// Trait for signing with a key known by chronicle #[async_trait::async_trait] pub trait ChronicleSigner { - /// Sign data with the a known key and return a signature - async fn sign( - &self, - secret_namespace: &str, - secret_name: &str, - data: &[u8], - ) -> Result; - - /// Verify a signature with a known key - async fn verify( - &self, - secret_namespace: &str, - secret_name: &str, - data: &[u8], - signature: &[u8], - ) -> Result; + /// Sign data with the a known key and return a signature + async fn sign( + &self, + secret_namespace: &str, + secret_name: &str, + data: &[u8], + ) -> Result; + + /// Verify a signature with a known key + async fn verify( + &self, + secret_namespace: &str, + secret_name: &str, + data: &[u8], + signature: &[u8], + ) -> Result; } #[async_trait::async_trait] impl ChronicleSigner for T { - /// Sign data with the chronicle key and return a signature - async fn sign( - &self, - secret_namespace: &str, - secret_name: &str, - data: &[u8], - ) -> Result { - self.with_signing_key(secret_namespace, secret_name, |signing_key| { - let s: Signature = signing_key.sign(data); - s - }) - .await - } - - /// Verify a signature with the chronicle key - async fn verify( - &self, - secret_namespace: &str, - secret_name: &str, - data: &[u8], - signature: &[u8], - ) -> Result { - self.with_verifying_key(secret_namespace, secret_name, |verifying_key| { - let signature: Signature = k256::ecdsa::signature::Signature::from_bytes(signature) - .map_err(|_| SecretError::InvalidPublicKey)?; - - Ok(verifying_key.verify(data, &signature).is_ok()) - }) - .await? - } + /// Sign data with the chronicle key and return a signature + async fn sign( + &self, + secret_namespace: &str, + secret_name: &str, + data: &[u8], + ) -> Result { + self.with_signing_key(secret_namespace, secret_name, |signing_key| { + let s: Signature = signing_key.sign(data); + s + }) + .await + } + + /// Verify a signature with the chronicle key + async fn verify( + &self, + secret_namespace: &str, + secret_name: &str, + data: &[u8], + signature: &[u8], + ) -> Result { + self.with_verifying_key(secret_namespace, secret_name, |verifying_key| { + let signature: Signature = k256::ecdsa::signature::Signature::from_bytes(signature) + .map_err(|_| SecretError::InvalidPublicKey)?; + + Ok(verifying_key.verify(data, &signature).is_ok()) + }) + .await? + } } /// Trait for signing with a key known by the batcher #[async_trait::async_trait] pub trait BatcherKnownKeyNamesSigner { - /// Sign data with the batcher key and return a signature in low-s form, as this - /// is required by sawtooth for batcher signatures - async fn batcher_sign(&self, data: &[u8]) -> Result, SecretError>; + /// Sign data with the batcher key and return a signature in low-s form, as this + /// is required by sawtooth for batcher signatures + async fn batcher_sign(&self, data: &[u8]) -> Result, SecretError>; - /// Verify a signature with the batcher key - async fn batcher_verify(&self, data: &[u8], signature: &[u8]) -> Result; + /// Verify a signature with the batcher key + async fn batcher_verify(&self, data: &[u8], signature: &[u8]) -> Result; - /// Get the verifying key for the batcher key - async fn batcher_verifying(&self) -> Result; + /// Get the verifying key for the batcher key + async fn batcher_verifying(&self) -> Result; } /// Trait for signing with a key known by chronicle #[async_trait::async_trait] pub trait ChronicleKnownKeyNamesSigner { - /// Sign data with the chronicle key and return a signature - async fn chronicle_sign(&self, data: &[u8]) -> Result, SecretError>; + /// Sign data with the chronicle key and return a signature + async fn chronicle_sign(&self, data: &[u8]) -> Result, SecretError>; - /// Verify a signature with the chronicle key - async fn chronicle_verify(&self, data: &[u8], signature: &[u8]) -> Result; + /// Verify a signature with the chronicle key + async fn chronicle_verify(&self, data: &[u8], signature: &[u8]) -> Result; - /// Get the verifying key for the chronicle key - async fn chronicle_verifying(&self) -> Result; + /// Get the verifying key for the chronicle key + async fn chronicle_verifying(&self) -> Result; } /// Trait for signing with a key known by OPA #[async_trait::async_trait] pub trait OpaKnownKeyNamesSigner { - /// Sign data with the OPA key and return a signature - async fn opa_sign(&self, data: &[u8]) -> Result, SecretError>; + /// Sign data with the OPA key and return a signature + async fn opa_sign(&self, data: &[u8]) -> Result, SecretError>; - /// Verify a signature with the OPA key - async fn opa_verify(&self, data: &[u8], signature: &[u8]) -> Result; + /// Verify a signature with the OPA key + async fn opa_verify(&self, data: &[u8], signature: &[u8]) -> Result; - /// Get the verifying key for the OPA key - async fn opa_verifying(&self) -> Result; + /// Get the verifying key for the OPA key + async fn opa_verifying(&self) -> Result; } #[async_trait::async_trait] impl BatcherKnownKeyNamesSigner for T { - // Sign with the batcher key and return a signature in low-s form, as this - // is required by sawtooth for batcher signatures - #[instrument(skip(self,data), level = "trace", name = "batcher_sign", fields(namespace = BATCHER_NAMESPACE, pk = BATCHER_PK))] - async fn batcher_sign(&self, data: &[u8]) -> Result, SecretError> { - let s = self.sign(BATCHER_NAMESPACE, BATCHER_PK, data).await?; - - let s = s.normalize_s().unwrap_or(s); - - Ok(s.to_vec()) - } - - #[instrument(skip(self,data,signature), level = "trace", name = "batcher_verify", fields(namespace = BATCHER_NAMESPACE, pk = BATCHER_PK))] - async fn batcher_verify(&self, data: &[u8], signature: &[u8]) -> Result { - self.verify(BATCHER_NAMESPACE, BATCHER_PK, data, signature).await - } - - #[instrument(skip(self), level = "trace", name = "batcher_verifying", fields(namespace = BATCHER_NAMESPACE, pk = BATCHER_PK))] - async fn batcher_verifying(&self) -> Result { - self.verifying_key(BATCHER_NAMESPACE, BATCHER_PK).await - } + // Sign with the batcher key and return a signature in low-s form, as this + // is required by sawtooth for batcher signatures + #[instrument(skip(self, data), level = "trace", name = "batcher_sign", fields( + namespace = BATCHER_NAMESPACE, pk = BATCHER_PK + ))] + async fn batcher_sign(&self, data: &[u8]) -> Result, SecretError> { + let s = self.sign(BATCHER_NAMESPACE, BATCHER_PK, data).await?; + + let s = s.normalize_s().unwrap_or(s); + + Ok(s.to_vec()) + } + + #[instrument(skip(self, data, signature), level = "trace", name = "batcher_verify", fields( + namespace = BATCHER_NAMESPACE, pk = BATCHER_PK + ))] + async fn batcher_verify(&self, data: &[u8], signature: &[u8]) -> Result { + self.verify(BATCHER_NAMESPACE, BATCHER_PK, data, signature).await + } + + #[instrument(skip(self), level = "trace", name = "batcher_verifying", fields( + namespace = BATCHER_NAMESPACE, pk = BATCHER_PK + ))] + async fn batcher_verifying(&self) -> Result { + self.verifying_key(BATCHER_NAMESPACE, BATCHER_PK).await + } } #[async_trait::async_trait] impl ChronicleKnownKeyNamesSigner for T { - #[instrument(skip(self,data), level = "trace", name = "chronicle_sign", fields(namespace = CHRONICLE_NAMESPACE, pk = CHRONICLE_PK))] - async fn chronicle_sign(&self, data: &[u8]) -> Result, SecretError> { - Ok(self.sign(CHRONICLE_NAMESPACE, CHRONICLE_PK, data).await?.to_vec()) - } - - #[instrument(skip(self,data,signature), level = "trace", name = "chronicle_verify", fields(namespace = CHRONICLE_NAMESPACE, pk = CHRONICLE_PK))] - async fn chronicle_verify(&self, data: &[u8], signature: &[u8]) -> Result { - self.verify(CHRONICLE_NAMESPACE, CHRONICLE_PK, data, signature).await - } - - #[instrument(skip(self), level = "trace", name = "chronicle_verifying", fields(namespace = CHRONICLE_NAMESPACE, pk = CHRONICLE_PK))] - async fn chronicle_verifying(&self) -> Result { - self.verifying_key(CHRONICLE_NAMESPACE, CHRONICLE_PK).await - } + #[instrument(skip(self, data), level = "trace", name = "chronicle_sign", fields( + namespace = CHRONICLE_NAMESPACE, pk = CHRONICLE_PK + ))] + async fn chronicle_sign(&self, data: &[u8]) -> Result, SecretError> { + Ok(self.sign(CHRONICLE_NAMESPACE, CHRONICLE_PK, data).await?.to_vec()) + } + + #[instrument(skip(self, data, signature), level = "trace", name = "chronicle_verify", fields( + namespace = CHRONICLE_NAMESPACE, pk = CHRONICLE_PK + ))] + async fn chronicle_verify(&self, data: &[u8], signature: &[u8]) -> Result { + self.verify(CHRONICLE_NAMESPACE, CHRONICLE_PK, data, signature).await + } + + #[instrument(skip(self), level = "trace", name = "chronicle_verifying", fields( + namespace = CHRONICLE_NAMESPACE, pk = CHRONICLE_PK + ))] + async fn chronicle_verifying(&self) -> Result { + self.verifying_key(CHRONICLE_NAMESPACE, CHRONICLE_PK).await + } } #[async_trait::async_trait] impl OpaKnownKeyNamesSigner for T { - #[instrument(skip(self), level = "trace", name = "opa_sign", fields(namespace = OPA_NAMESPACE, pk = OPA_PK))] - async fn opa_sign(&self, data: &[u8]) -> Result, SecretError> { - let s = self.sign(OPA_NAMESPACE, OPA_PK, data).await?; - - let s = s.normalize_s().unwrap_or(s); - - Ok(s.to_vec()) - } - - #[instrument(skip(self,data,signature), level = "trace", name = "opa_verify", fields(namespace = OPA_NAMESPACE, pk = OPA_PK))] - async fn opa_verify(&self, data: &[u8], signature: &[u8]) -> Result { - self.verify(OPA_NAMESPACE, OPA_PK, data, signature).await - } - - #[instrument(skip(self), level = "trace", name = "opa_verifying", fields(namespace = OPA_NAMESPACE, pk = OPA_PK))] - async fn opa_verifying(&self) -> Result { - self.verifying_key(OPA_NAMESPACE, OPA_PK).await - } + #[instrument(skip(self), level = "trace", name = "opa_sign", fields( + namespace = OPA_NAMESPACE, pk = OPA_PK + ))] + async fn opa_sign(&self, data: &[u8]) -> Result, SecretError> { + let s = self.sign(OPA_NAMESPACE, OPA_PK, data).await?; + + let s = s.normalize_s().unwrap_or(s); + + Ok(s.to_vec()) + } + + #[instrument(skip(self, data, signature), level = "trace", name = "opa_verify", fields( + namespace = OPA_NAMESPACE, pk = OPA_PK + ))] + async fn opa_verify(&self, data: &[u8], signature: &[u8]) -> Result { + self.verify(OPA_NAMESPACE, OPA_PK, data, signature).await + } + + #[instrument(skip(self), level = "trace", name = "opa_verifying", fields( + namespace = OPA_NAMESPACE, pk = OPA_PK + ))] + async fn opa_verifying(&self) -> Result { + self.verifying_key(OPA_NAMESPACE, OPA_PK).await + } } pub fn chronicle_secret_names() -> Vec<(String, String)> { - vec![ - (CHRONICLE_NAMESPACE.to_string(), CHRONICLE_PK.to_string()), - (BATCHER_NAMESPACE.to_string(), BATCHER_PK.to_string()), - ] + vec![ + (CHRONICLE_NAMESPACE.to_string(), CHRONICLE_PK.to_string()), + (BATCHER_NAMESPACE.to_string(), BATCHER_PK.to_string()), + ] } pub fn opa_secret_names() -> Vec<(String, String)> { - vec![ - (OPA_NAMESPACE.to_string(), OPA_PK.to_string()), - (BATCHER_NAMESPACE.to_string(), BATCHER_PK.to_string()), - ] + vec![ + (OPA_NAMESPACE.to_string(), OPA_PK.to_string()), + (BATCHER_NAMESPACE.to_string(), BATCHER_PK.to_string()), + ] } #[cfg(test)] mod tests { - use super::*; - use k256::schnorr::signature::Signature; - - #[tokio::test] - async fn embedded_keys() { - let secrets = ChronicleSigning::new( - chronicle_secret_names(), - vec![(CHRONICLE_NAMESPACE.to_string(), ChronicleSecretsOptions::Embedded)], - ) - .await - .unwrap(); - - secrets - .with_signing_key(CHRONICLE_NAMESPACE, "chronicle-pk", |signing_key| { - assert_eq!(signing_key.to_bytes().len(), 32, "Signing key should be 32 bytes"); - }) - .await - .unwrap(); - - secrets - .with_verifying_key(CHRONICLE_NAMESPACE, "chronicle-pk", |verifying_key| { - assert_eq!(verifying_key.to_bytes().len(), 33, "Verifying key should be 33 bytes"); - }) - .await - .unwrap(); - - let sig = secrets - .sign(CHRONICLE_NAMESPACE, "chronicle-pk", "hello world".as_bytes()) - .await - .unwrap(); - - assert!(secrets - .verify(CHRONICLE_NAMESPACE, "chronicle-pk", "hello world".as_bytes(), sig.as_bytes()) - .await - .unwrap()); - - assert!(!secrets - .verify(CHRONICLE_NAMESPACE, "chronicle-pk", "boom".as_bytes(), sig.as_bytes()) - .await - .unwrap()); - } - - #[tokio::test] - async fn vault_keys() { - let secrets = ChronicleSigning::new( - chronicle_secret_names(), - vec![(CHRONICLE_NAMESPACE.to_string(), ChronicleSecretsOptions::Embedded)], - ) - .await - .unwrap(); - - secrets - .with_signing_key(CHRONICLE_NAMESPACE, "chronicle-pk", |signing_key| { - assert_eq!(signing_key.to_bytes().len(), 32, "Signing key should be 32 bytes"); - }) - .await - .unwrap(); - - secrets - .with_verifying_key(CHRONICLE_NAMESPACE, "chronicle-pk", |verifying_key| { - assert_eq!(verifying_key.to_bytes().len(), 33, "Verifying key should be 33 bytes"); - }) - .await - .unwrap(); - - let sig = secrets - .sign(CHRONICLE_NAMESPACE, "chronicle-pk", "hello world".as_bytes()) - .await - .unwrap(); - - assert!(secrets - .verify(CHRONICLE_NAMESPACE, "chronicle-pk", "hello world".as_bytes(), sig.as_bytes()) - .await - .unwrap()); - - assert!(!secrets - .verify(CHRONICLE_NAMESPACE, "chronicle-pk", "boom".as_bytes(), sig.as_bytes()) - .await - .unwrap()); - } + use super::*; + use k256::schnorr::signature::Signature; + + #[tokio::test] + async fn embedded_keys() { + let secrets = ChronicleSigning::new( + chronicle_secret_names(), + vec![(CHRONICLE_NAMESPACE.to_string(), ChronicleSecretsOptions::Embedded)], + ) + .await + .unwrap(); + + secrets + .with_signing_key(CHRONICLE_NAMESPACE, "chronicle-pk", |signing_key| { + assert_eq!(signing_key.to_bytes().len(), 32, "Signing key should be 32 bytes"); + }) + .await + .unwrap(); + + secrets + .with_verifying_key(CHRONICLE_NAMESPACE, "chronicle-pk", |verifying_key| { + assert_eq!(verifying_key.to_bytes().len(), 33, "Verifying key should be 33 bytes"); + }) + .await + .unwrap(); + + let sig = secrets + .sign(CHRONICLE_NAMESPACE, "chronicle-pk", "hello world".as_bytes()) + .await + .unwrap(); + + assert!(secrets + .verify(CHRONICLE_NAMESPACE, "chronicle-pk", "hello world".as_bytes(), sig.as_bytes()) + .await + .unwrap()); + + assert!(!secrets + .verify(CHRONICLE_NAMESPACE, "chronicle-pk", "boom".as_bytes(), sig.as_bytes()) + .await + .unwrap()); + } + + #[tokio::test] + async fn vault_keys() { + let secrets = ChronicleSigning::new( + chronicle_secret_names(), + vec![(CHRONICLE_NAMESPACE.to_string(), ChronicleSecretsOptions::Embedded)], + ) + .await + .unwrap(); + + secrets + .with_signing_key(CHRONICLE_NAMESPACE, "chronicle-pk", |signing_key| { + assert_eq!(signing_key.to_bytes().len(), 32, "Signing key should be 32 bytes"); + }) + .await + .unwrap(); + + secrets + .with_verifying_key(CHRONICLE_NAMESPACE, "chronicle-pk", |verifying_key| { + assert_eq!(verifying_key.to_bytes().len(), 33, "Verifying key should be 33 bytes"); + }) + .await + .unwrap(); + + let sig = secrets + .sign(CHRONICLE_NAMESPACE, "chronicle-pk", "hello world".as_bytes()) + .await + .unwrap(); + + assert!(secrets + .verify(CHRONICLE_NAMESPACE, "chronicle-pk", "hello world".as_bytes(), sig.as_bytes()) + .await + .unwrap()); + + assert!(!secrets + .verify(CHRONICLE_NAMESPACE, "chronicle-pk", "boom".as_bytes(), sig.as_bytes()) + .await + .unwrap()); + } } diff --git a/crates/chronicle-signing/src/types.rs b/crates/chronicle-signing/src/types.rs index 1c72fbe2b..70ad7e8a7 100644 --- a/crates/chronicle-signing/src/types.rs +++ b/crates/chronicle-signing/src/types.rs @@ -1,203 +1,203 @@ #[async_trait::async_trait] pub trait WithSecret { - async fn with_signing_key( - &self, - secret_namespace: &str, - secret_name: &str, - f: F, - ) -> Result - where - F: Fn(SigningKey) -> T, - F: Send, - T: Send; - async fn with_verifying_key( - &self, - secret_namespace: &str, - secret_name: &str, - f: F, - ) -> Result - where - F: Fn(VerifyingKey) -> T, - F: Send, - T: Send; - - async fn verifying_key( - &self, - secret_namespace: &str, - secret_name: &str, - ) -> Result; + async fn with_signing_key( + &self, + secret_namespace: &str, + secret_name: &str, + f: F, + ) -> Result + where + F: Fn(SigningKey) -> T, + F: Send, + T: Send; + async fn with_verifying_key( + &self, + secret_namespace: &str, + secret_name: &str, + f: F, + ) -> Result + where + F: Fn(VerifyingKey) -> T, + F: Send, + T: Send; + + async fn verifying_key( + &self, + secret_namespace: &str, + secret_name: &str, + ) -> Result; } #[async_trait::async_trait] impl WithSecret for ChronicleSigning { - async fn with_signing_key( - &self, - secret_namespace: &str, - secret_name: &str, - f: F, - ) -> Result - where - F: Fn(SigningKey) -> T, - F: Send, - T: Send, - { - let secret_ref = SecretVaultRef::new(SecretName::new(secret_name.to_owned())) - .with_namespace(secret_namespace.into()); - let secret = self.vault.lock().await.require_secret_by_ref(&secret_ref).await?; - - let signing_result = secret.value.exposed_in_as_str(|secret| { - ( - // Not semantically the same thing as we re-use f - SigningKey::from_pkcs8_pem(&secret) - .map_err(|_| SecretError::InvalidPrivateKey) - .map(&f), - secret, - ) - }); - - Ok(signing_result?) - } - - async fn with_verifying_key( - &self, - secret_namespace: &str, - secret_name: &str, - f: F, - ) -> Result - where - F: Fn(VerifyingKey) -> T, - F: Send, - T: Send, - { - let secret_ref = SecretVaultRef::new(SecretName::new(secret_name.to_owned())) - .with_namespace(secret_namespace.into()); - let secret = self.vault.lock().await.require_secret_by_ref(&secret_ref).await?; - - let signing_result = secret.value.exposed_in_as_str(|secret| { - ( - SigningKey::from_pkcs8_pem(&secret) - .map_err(|_| SecretError::InvalidPrivateKey) - .map(|signing_key| f(signing_key.verifying_key())), - secret, - ) - }); - - Ok(signing_result?) - } - - async fn verifying_key( - &self, - secret_namespace: &str, - secret_name: &str, - ) -> Result { - let secret_ref = SecretVaultRef::new(SecretName::new(secret_name.to_owned())) - .with_namespace(secret_namespace.into()); - let secret = self.vault.lock().await.require_secret_by_ref(&secret_ref).await?; - - let key = secret.value.exposed_in_as_str(|secret| { - ( - SigningKey::from_pkcs8_pem(&secret) - .map_err(|_| SecretError::InvalidPrivateKey) - .map(|signing_key| signing_key.verifying_key()), - secret, - ) - }); - - Ok(key?) - } + async fn with_signing_key( + &self, + secret_namespace: &str, + secret_name: &str, + f: F, + ) -> Result + where + F: Fn(SigningKey) -> T, + F: Send, + T: Send, + { + let secret_ref = SecretVaultRef::new(SecretName::new(secret_name.to_owned())) + .with_namespace(secret_namespace.into()); + let secret = self.vault.lock().await.require_secret_by_ref(&secret_ref).await?; + + let signing_result = secret.value.exposed_in_as_str(|secret| { + ( + // Not semantically the same thing as we re-use f + SigningKey::from_pkcs8_pem(&secret) + .map_err(|_| SecretError::InvalidPrivateKey) + .map(&f), + secret, + ) + }); + + Ok(signing_result?) + } + + async fn with_verifying_key( + &self, + secret_namespace: &str, + secret_name: &str, + f: F, + ) -> Result + where + F: Fn(VerifyingKey) -> T, + F: Send, + T: Send, + { + let secret_ref = SecretVaultRef::new(SecretName::new(secret_name.to_owned())) + .with_namespace(secret_namespace.into()); + let secret = self.vault.lock().await.require_secret_by_ref(&secret_ref).await?; + + let signing_result = secret.value.exposed_in_as_str(|secret| { + ( + SigningKey::from_pkcs8_pem(&secret) + .map_err(|_| SecretError::InvalidPrivateKey) + .map(|signing_key| f(signing_key.verifying_key())), + secret, + ) + }); + + Ok(signing_result?) + } + + async fn verifying_key( + &self, + secret_namespace: &str, + secret_name: &str, + ) -> Result { + let secret_ref = SecretVaultRef::new(SecretName::new(secret_name.to_owned())) + .with_namespace(secret_namespace.into()); + let secret = self.vault.lock().await.require_secret_by_ref(&secret_ref).await?; + + let key = secret.value.exposed_in_as_str(|secret| { + ( + SigningKey::from_pkcs8_pem(&secret) + .map_err(|_| SecretError::InvalidPrivateKey) + .map(|signing_key| signing_key.verifying_key()), + secret, + ) + }); + + Ok(key?) + } } /// Trait for signing with a key known by chronicle #[async_trait::async_trait] pub trait ChronicleSigner { - /// Sign data with the a known key and return a signature - async fn sign( - &self, - secret_namespace: &str, - secret_name: &str, - data: &[u8], - ) -> Result; - - /// Verify a signature with a known key - async fn verify( - &self, - secret_namespace: &str, - secret_name: &str, - data: &[u8], - signature: &[u8], - ) -> Result; + /// Sign data with the a known key and return a signature + async fn sign( + &self, + secret_namespace: &str, + secret_name: &str, + data: &[u8], + ) -> Result; + + /// Verify a signature with a known key + async fn verify( + &self, + secret_namespace: &str, + secret_name: &str, + data: &[u8], + signature: &[u8], + ) -> Result; } #[async_trait::async_trait] impl ChronicleSigner for T { - /// Sign data with the chronicle key and return a signature - async fn sign( - &self, - secret_namespace: &str, - secret_name: &str, - data: &[u8], - ) -> Result { - self.with_signing_key(secret_namespace, secret_name, |signing_key| { - let s: Signature = signing_key.sign(data); - s - }) - .await - } - - /// Verify a signature with the chronicle key - async fn verify( - &self, - secret_namespace: &str, - secret_name: &str, - data: &[u8], - signature: &[u8], - ) -> Result { - self.with_verifying_key(secret_namespace, secret_name, |verifying_key| { - let signature: Signature = k256::ecdsa::signature::Signature::from_bytes(signature) - .map_err(|_| SecretError::InvalidPublicKey)?; - - Ok(verifying_key.verify(data, &signature).is_ok()) - }) - .await? - } + /// Sign data with the chronicle key and return a signature + async fn sign( + &self, + secret_namespace: &str, + secret_name: &str, + data: &[u8], + ) -> Result { + self.with_signing_key(secret_namespace, secret_name, |signing_key| { + let s: Signature = signing_key.sign(data); + s + }) + .await + } + + /// Verify a signature with the chronicle key + async fn verify( + &self, + secret_namespace: &str, + secret_name: &str, + data: &[u8], + signature: &[u8], + ) -> Result { + self.with_verifying_key(secret_namespace, secret_name, |verifying_key| { + let signature: Signature = k256::ecdsa::signature::Signature::from_bytes(signature) + .map_err(|_| SecretError::InvalidPublicKey)?; + + Ok(verifying_key.verify(data, &signature).is_ok()) + }) + .await? + } } /// Trait for signing with a key known by the batcher #[async_trait::async_trait] pub trait BatcherKnownKeyNamesSigner { - /// Sign data with the batcher key and return a signature in low-s form, as this - /// is required by sawtooth for batcher signatures - async fn batcher_sign(&self, data: &[u8]) -> Result, SecretError>; + /// Sign data with the batcher key and return a signature in low-s form, as this + /// is required by sawtooth for batcher signatures + async fn batcher_sign(&self, data: &[u8]) -> Result, SecretError>; - /// Verify a signature with the batcher key - async fn batcher_verify(&self, data: &[u8], signature: &[u8]) -> Result; + /// Verify a signature with the batcher key + async fn batcher_verify(&self, data: &[u8], signature: &[u8]) -> Result; - /// Get the verifying key for the batcher key - async fn batcher_verifying(&self) -> Result; + /// Get the verifying key for the batcher key + async fn batcher_verifying(&self) -> Result; } /// Trait for signing with a key known by chronicle #[async_trait::async_trait] pub trait ChronicleKnownKeyNamesSigner { - /// Sign data with the chronicle key and return a signature - async fn chronicle_sign(&self, data: &[u8]) -> Result, SecretError>; + /// Sign data with the chronicle key and return a signature + async fn chronicle_sign(&self, data: &[u8]) -> Result, SecretError>; - /// Verify a signature with the chronicle key - async fn chronicle_verify(&self, data: &[u8], signature: &[u8]) -> Result; + /// Verify a signature with the chronicle key + async fn chronicle_verify(&self, data: &[u8], signature: &[u8]) -> Result; - /// Get the verifying key for the chronicle key - async fn chronicle_verifying(&self) -> Result; + /// Get the verifying key for the chronicle key + async fn chronicle_verifying(&self) -> Result; } /// Trait for signing with a key known by OPA #[async_trait::async_trait] pub trait OpaKnownKeyNamesSigner { - /// Sign data with the OPA key and return a signature - async fn opa_sign(&self, data: &[u8]) -> Result, SecretError>; + /// Sign data with the OPA key and return a signature + async fn opa_sign(&self, data: &[u8]) -> Result, SecretError>; - /// Verify a signature with the OPA key - async fn opa_verify(&self, data: &[u8], signature: &[u8]) -> Result; + /// Verify a signature with the OPA key + async fn opa_verify(&self, data: &[u8], signature: &[u8]) -> Result; - /// Get the verifying key for the OPA key - async fn opa_verifying(&self) -> Result; + /// Get the verifying key for the OPA key + async fn opa_verifying(&self) -> Result; } diff --git a/crates/chronicle-signing/src/vault_secret_manager_source.rs b/crates/chronicle-signing/src/vault_secret_manager_source.rs index e4a08ca2f..897c27f47 100644 --- a/crates/chronicle-signing/src/vault_secret_manager_source.rs +++ b/crates/chronicle-signing/src/vault_secret_manager_source.rs @@ -2,120 +2,120 @@ use std::{collections::HashMap, sync::Arc}; use async_trait::*; use secret_vault::{ - errors::{SecretVaultError, SecretVaultErrorPublicGenericDetails, SecretsSourceError}, - Secret, SecretMetadata, SecretVaultRef, SecretVaultResult, SecretsSource, + errors::{SecretVaultError, SecretVaultErrorPublicGenericDetails, SecretsSourceError}, + Secret, SecretMetadata, SecretVaultRef, SecretVaultResult, SecretsSource, }; use secret_vault_value::SecretValue; use tokio::sync::Mutex; use tracing::*; use url::Url; use vaultrs::{ - client::{VaultClient, VaultClientSettingsBuilder}, - kv2, + client::{VaultClient, VaultClientSettingsBuilder}, + kv2, }; #[derive(Debug, Clone, Eq, PartialEq)] pub struct VaultSecretManagerSourceOptions { - pub vault_url: Url, - pub token: String, - pub mount_path: String, + pub vault_url: Url, + pub token: String, + pub mount_path: String, } impl VaultSecretManagerSourceOptions { - pub fn new(vault_url: Url, token: &str, mount_path: &str) -> Self { - VaultSecretManagerSourceOptions { - vault_url, - token: token.to_owned(), - mount_path: mount_path.to_owned(), - } - } + pub fn new(vault_url: Url, token: &str, mount_path: &str) -> Self { + VaultSecretManagerSourceOptions { + vault_url, + token: token.to_owned(), + mount_path: mount_path.to_owned(), + } + } } #[derive(Clone)] pub struct VaultSecretManagerSource { - options: VaultSecretManagerSourceOptions, - client: Arc>, + options: VaultSecretManagerSourceOptions, + client: Arc>, } impl VaultSecretManagerSource { - pub async fn with_options(options: VaultSecretManagerSourceOptions) -> SecretVaultResult { - Ok(VaultSecretManagerSource { - options: options.clone(), - client: Arc::new(Mutex::new( - VaultClient::new( - VaultClientSettingsBuilder::default() - .address(options.vault_url.as_str()) - .token(options.token) - .build() - .unwrap(), - ) - .map_err(|e| { - SecretVaultError::SecretsSourceError( - SecretsSourceError::new( - SecretVaultErrorPublicGenericDetails::new(format!("{}", e)), - format!("Vault error: {}", e), - ) - .with_root_cause(Box::new(e)), - ) - })?, - )), - }) - } + pub async fn with_options(options: VaultSecretManagerSourceOptions) -> SecretVaultResult { + Ok(VaultSecretManagerSource { + options: options.clone(), + client: Arc::new(Mutex::new( + VaultClient::new( + VaultClientSettingsBuilder::default() + .address(options.vault_url.as_str()) + .token(options.token) + .build() + .unwrap(), + ) + .map_err(|e| { + SecretVaultError::SecretsSourceError( + SecretsSourceError::new( + SecretVaultErrorPublicGenericDetails::new(format!("{}", e)), + format!("Vault error: {}", e), + ) + .with_root_cause(Box::new(e)), + ) + })?, + )), + }) + } } #[async_trait] impl SecretsSource for VaultSecretManagerSource { - fn name(&self) -> String { - "HashiVaultSecretManager".to_string() - } + fn name(&self) -> String { + "HashiVaultSecretManager".to_string() + } - async fn get_secrets( - &self, - references: &[SecretVaultRef], - ) -> SecretVaultResult> { - let mut result_map: HashMap = HashMap::new(); - let client = &*self.client.lock().await; + async fn get_secrets( + &self, + references: &[SecretVaultRef], + ) -> SecretVaultResult> { + let mut result_map: HashMap = HashMap::new(); + let client = &*self.client.lock().await; - let mut results = vec![]; - for secret_ref in references { - results.push(( - secret_ref.clone(), - kv2::read(client, &self.options.mount_path, secret_ref.key.secret_name.as_ref()) - .await, - )); - } + let mut results = vec![]; + for secret_ref in references { + results.push(( + secret_ref.clone(), + kv2::read(client, &self.options.mount_path, secret_ref.key.secret_name.as_ref()) + .await, + )); + } - for (secret_ref, result) in results { - match result { - Ok(vault_secret) => { - let metadata = SecretMetadata::create_from_ref(&secret_ref); - result_map.insert( - secret_ref.clone(), - Secret::new(SecretValue::new(vault_secret), metadata), - ); - }, - Err(err) => { - error!( + for (secret_ref, result) in results { + match result { + Ok(vault_secret) => { + let metadata = SecretMetadata::create_from_ref(&secret_ref); + result_map.insert( + secret_ref.clone(), + Secret::new(SecretValue::new(vault_secret), metadata), + ); + } + Err(err) => { + error!( "Unable to read secret or secret version {}:{}/{:?}: {}.", self.options.mount_path, &secret_ref.key.secret_name, &secret_ref.key.secret_version, err ); - return Err(SecretVaultError::SecretsSourceError(SecretsSourceError::new( - SecretVaultErrorPublicGenericDetails::new(format!( - "Unable to read secret or secret version {}/{:?}: {}.", - self.options.mount_path, &secret_ref.key.secret_name, err - )), - format!( - "Unable to read secret or secret version {}/{:?}: {}.", - self.options.mount_path, &secret_ref.key.secret_name, err - ), - ))) - }, - } - } + return Err(SecretVaultError::SecretsSourceError(SecretsSourceError::new( + SecretVaultErrorPublicGenericDetails::new(format!( + "Unable to read secret or secret version {}/{:?}: {}.", + self.options.mount_path, &secret_ref.key.secret_name, err + )), + format!( + "Unable to read secret or secret version {}/{:?}: {}.", + self.options.mount_path, &secret_ref.key.secret_name, err + ), + ))); + } + } + } - Ok(result_map) - } + Ok(result_map) + } } diff --git a/crates/chronicle-synth/Cargo.toml b/crates/chronicle-synth/Cargo.toml index fa747ab6f..af6a9072c 100644 --- a/crates/chronicle-synth/Cargo.toml +++ b/crates/chronicle-synth/Cargo.toml @@ -1,7 +1,7 @@ [package] -build = "build.rs" +build = "build.rs" edition = "2021" -name = "chronicle-synth" +name = "chronicle-synth" version = "0.7.5" [lib] @@ -13,19 +13,19 @@ name = "chronicle-synth" path = "src/generate.rs" [dependencies] -clap = { workspace = true } -maplit = { workspace = true } +clap = { workspace = true } +maplit = { workspace = true } owo-colors = { workspace = true } -serde = { workspace = true } +serde = { workspace = true } serde_json = { workspace = true } serde_yaml = { workspace = true } -thiserror = { workspace = true } +thiserror = { workspace = true } #local dependencies chronicle = { path = "../chronicle" } -common = { path = "../common", features = ["std"] } +common = { path = "../common", features = ["std"] } [dev-dependencies] assert_fs = { workspace = true } -insta = { workspace = true, features = ["json"] } +insta = { workspace = true, features = ["json"] } diff --git a/crates/chronicle-synth/build.rs b/crates/chronicle-synth/build.rs index afb2c9546..5a1d86bbe 100644 --- a/crates/chronicle-synth/build.rs +++ b/crates/chronicle-synth/build.rs @@ -1,8 +1,8 @@ fn main() { - //Create a .VERSION file containing 'local' if it does not exist + //Create a .VERSION file containing 'local' if it does not exist - let version_file = std::path::Path::new("../../.VERSION"); - if !version_file.exists() { - std::fs::write(version_file, "local").expect("Unable to write file"); - } + let version_file = std::path::Path::new("../../.VERSION"); + if !version_file.exists() { + std::fs::write(version_file, "local").expect("Unable to write file"); + } } diff --git a/crates/chronicle-synth/domain.yaml b/crates/chronicle-synth/domain.yaml index ffae147a5..61b8e093b 100644 --- a/crates/chronicle-synth/domain.yaml +++ b/crates/chronicle-synth/domain.yaml @@ -1,6 +1,6 @@ name: "untyped" -attributes: {} -entities: {} -activities: {} -agents: {} -roles: [] +attributes: { } +entities: { } +activities: { } +agents: { } +roles: [ ] diff --git a/crates/chronicle-synth/exclude_collections.json b/crates/chronicle-synth/exclude_collections.json index a689c434b..f71b7ecf1 100644 --- a/crates/chronicle-synth/exclude_collections.json +++ b/crates/chronicle-synth/exclude_collections.json @@ -1,21 +1,21 @@ { - "exclude": [ - "activity_name", - "agent_name", - "attribute", - "attributes", - "earlier_date_time", - "later_date_time", - "domain_type_id", - "entity_name", - "namespace", - "namespace_uuid", - "role", - "roles", - "same_namespace_name", - "same_namespace_uuid", - "second_activity_name", - "second_agent_name", - "second_entity_name" - ] - } + "exclude": [ + "activity_name", + "agent_name", + "attribute", + "attributes", + "earlier_date_time", + "later_date_time", + "domain_type_id", + "entity_name", + "namespace", + "namespace_uuid", + "role", + "roles", + "same_namespace_name", + "same_namespace_uuid", + "second_activity_name", + "second_agent_name", + "second_entity_name" + ] +} diff --git a/crates/chronicle-synth/src/collection.rs b/crates/chronicle-synth/src/collection.rs index 79bf899a7..3285ce80d 100644 --- a/crates/chronicle-synth/src/collection.rs +++ b/crates/chronicle-synth/src/collection.rs @@ -1,7 +1,7 @@ use std::{ - fmt::Display, - fs::File, - path::{Path, PathBuf}, + fmt::Display, + fs::File, + path::{Path, PathBuf}, }; use serde_json::Value; @@ -12,208 +12,208 @@ use crate::error::ChronicleSynthError; /// operation collection. #[derive(Debug)] pub enum Collection { - Operation(Operation), - Generator(Generator), + Operation(Operation), + Generator(Generator), } /// `Operation` refers to a Synth schema collection that generates a Chronicle operation. /// An `Operation` usually has dependencies in the form of component [`Generator`]s. #[derive(Debug)] pub enum Operation { - ActivityExists, - ActivityUses, - AgentActsOnBehalfOf, - AgentExists, - CreateNamespace, - EndActivity, - EntityDerive, - EntityExists, - SetActivityAttributes, - SetAgentAttributes, - SetEntityAttributes, - StartActivity, - WasAssociatedWith, - WasAssociatedWithHasRole, - WasAttributedTo, - WasGeneratedBy, - WasInformedBy, - DomainCollection(DomainCollection), + ActivityExists, + ActivityUses, + AgentActsOnBehalfOf, + AgentExists, + CreateNamespace, + EndActivity, + EntityDerive, + EntityExists, + SetActivityAttributes, + SetAgentAttributes, + SetEntityAttributes, + StartActivity, + WasAssociatedWith, + WasAssociatedWithHasRole, + WasAttributedTo, + WasGeneratedBy, + WasInformedBy, + DomainCollection(DomainCollection), } /// `Generator` refers to a Synth schema collection that generates a component of a Chronicle /// operation, as opposed to being an operation itself. A `Generator` should have no dependencies. #[derive(Debug)] pub enum Generator { - ActivityName, - SecondActivityName, - AgentName, - SecondAgentName, - Attribute, - Attributes, - DateTime, - DomainTypeId, - EntityName, - SecondEntityName, - Namespace, - NamespaceUuid, - Role, - Roles, - SameNamespaceName, - SameNamespaceUuid, - DomainCollection(DomainCollection), + ActivityName, + SecondActivityName, + AgentName, + SecondAgentName, + Attribute, + Attributes, + DateTime, + DomainTypeId, + EntityName, + SecondEntityName, + Namespace, + NamespaceUuid, + Role, + Roles, + SameNamespaceName, + SameNamespaceUuid, + DomainCollection(DomainCollection), } /// Represents a Synth collection that is generated specifically for a Chronicle domain. #[derive(Debug)] pub struct DomainCollection { - pub name: String, - pub schema: Value, + pub name: String, + pub schema: Value, } impl DomainCollection { - pub fn new(name: impl Into, schema: Value) -> Self { - let name = name.into(); - Self { name, schema } - } + pub fn new(name: impl Into, schema: Value) -> Self { + let name = name.into(); + Self { name, schema } + } } pub trait CollectionHandling { - fn name(&self) -> String - where - Self: Display, - { - self.to_string() - } - - fn path(&self) -> PathBuf - where - Self: Display, - { - Path::new(&format!("{}.json", self)).to_path_buf() - } - - fn json_schema(&self) -> Result - where - Self: Display; + fn name(&self) -> String + where + Self: Display, + { + self.to_string() + } + + fn path(&self) -> PathBuf + where + Self: Display, + { + Path::new(&format!("{}.json", self)).to_path_buf() + } + + fn json_schema(&self) -> Result + where + Self: Display; } impl From for Collection { - fn from(operation: Operation) -> Self { - Self::Operation(operation) - } + fn from(operation: Operation) -> Self { + Self::Operation(operation) + } } impl From for Collection { - fn from(generator: Generator) -> Self { - Self::Generator(generator) - } + fn from(generator: Generator) -> Self { + Self::Generator(generator) + } } impl Display for Collection { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Collection::Operation(operation) => write!(f, "{}", operation), - Collection::Generator(generator) => write!(f, "{}", generator), - } - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Collection::Operation(operation) => write!(f, "{}", operation), + Collection::Generator(generator) => write!(f, "{}", generator), + } + } } impl CollectionHandling for Collection { - fn json_schema(&self) -> Result { - match self { - Collection::Operation(operation) => operation.json_schema(), - Collection::Generator(generator) => generator.json_schema(), - } - } + fn json_schema(&self) -> Result { + match self { + Collection::Operation(operation) => operation.json_schema(), + Collection::Generator(generator) => generator.json_schema(), + } + } } impl CollectionHandling for Operation { - fn json_schema(&self) -> Result - where - Self: Display, - { - match self { - Self::DomainCollection(domain_collection) => Ok(domain_collection.schema.to_owned()), - _ => { - let path = self.path(); - let reader = File::open(path)?; - let schema: serde_json::Value = serde_json::from_reader(reader)?; - Ok(schema) - }, - } - } + fn json_schema(&self) -> Result + where + Self: Display, + { + match self { + Self::DomainCollection(domain_collection) => Ok(domain_collection.schema.to_owned()), + _ => { + let path = self.path(); + let reader = File::open(path)?; + let schema: serde_json::Value = serde_json::from_reader(reader)?; + Ok(schema) + } + } + } } impl Display for Operation { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!( - f, - "{}", - match self { - Self::ActivityExists => "activity_exists", - Self::ActivityUses => "activity_uses", - Self::AgentActsOnBehalfOf => "agent_acts_on_behalf_of", - Self::AgentExists => "agent_exists", - Self::CreateNamespace => "create_namespace", - Self::EndActivity => "end_activity", - Self::EntityDerive => "entity_derive", - Self::EntityExists => "entity_exists", - Self::SetActivityAttributes => "set_activity_attributes", - Self::SetAgentAttributes => "set_agent_attributes", - Self::SetEntityAttributes => "set_entity_attributes", - Self::StartActivity => "start_activity", - Self::WasAssociatedWith => "was_associated_with", - Self::WasAssociatedWithHasRole => "was_associated_with_has_role", - Self::WasAttributedTo => "was_attributed_to", - Self::WasGeneratedBy => "was_generated_by", - Self::WasInformedBy => "was_informed_by", - Self::DomainCollection(domain_collection) => &domain_collection.name, - } - ) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "{}", + match self { + Self::ActivityExists => "activity_exists", + Self::ActivityUses => "activity_uses", + Self::AgentActsOnBehalfOf => "agent_acts_on_behalf_of", + Self::AgentExists => "agent_exists", + Self::CreateNamespace => "create_namespace", + Self::EndActivity => "end_activity", + Self::EntityDerive => "entity_derive", + Self::EntityExists => "entity_exists", + Self::SetActivityAttributes => "set_activity_attributes", + Self::SetAgentAttributes => "set_agent_attributes", + Self::SetEntityAttributes => "set_entity_attributes", + Self::StartActivity => "start_activity", + Self::WasAssociatedWith => "was_associated_with", + Self::WasAssociatedWithHasRole => "was_associated_with_has_role", + Self::WasAttributedTo => "was_attributed_to", + Self::WasGeneratedBy => "was_generated_by", + Self::WasInformedBy => "was_informed_by", + Self::DomainCollection(domain_collection) => &domain_collection.name, + } + ) + } } impl CollectionHandling for Generator { - fn json_schema(&self) -> Result - where - Self: Display, - { - match self { - Self::DomainCollection(domain_collection) => Ok(domain_collection.schema.to_owned()), - _ => { - let path = self.path(); - let reader = File::open(path)?; - let schema: serde_json::Value = serde_json::from_reader(reader)?; - Ok(schema) - }, - } - } + fn json_schema(&self) -> Result + where + Self: Display, + { + match self { + Self::DomainCollection(domain_collection) => Ok(domain_collection.schema.to_owned()), + _ => { + let path = self.path(); + let reader = File::open(path)?; + let schema: serde_json::Value = serde_json::from_reader(reader)?; + Ok(schema) + } + } + } } impl Display for Generator { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!( - f, - "{}", - match self { - Self::ActivityName => "activity_name", - Self::SecondActivityName => "second_activity_name", - Self::AgentName => "agent_name", - Self::SecondAgentName => "second_agent_name", - Self::Attribute => "attribute", - Self::Attributes => "attributes", - Self::DateTime => "date_time", - Self::DomainTypeId => "domain_type_id", - Self::EntityName => "entity_name", - Self::SecondEntityName => "second_entity_name", - Self::Namespace => "namespace", - Self::NamespaceUuid => "namespace_uuid", - Self::Role => "role", - Self::Roles => "roles", - Self::SameNamespaceName => "same_namespace_name", - Self::SameNamespaceUuid => "same_namespace_uuid", - Self::DomainCollection(dc) => &dc.name, - } - ) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "{}", + match self { + Self::ActivityName => "activity_name", + Self::SecondActivityName => "second_activity_name", + Self::AgentName => "agent_name", + Self::SecondAgentName => "second_agent_name", + Self::Attribute => "attribute", + Self::Attributes => "attributes", + Self::DateTime => "date_time", + Self::DomainTypeId => "domain_type_id", + Self::EntityName => "entity_name", + Self::SecondEntityName => "second_entity_name", + Self::Namespace => "namespace", + Self::NamespaceUuid => "namespace_uuid", + Self::Role => "role", + Self::Roles => "roles", + Self::SameNamespaceName => "same_namespace_name", + Self::SameNamespaceUuid => "same_namespace_uuid", + Self::DomainCollection(dc) => &dc.name, + } + ) + } } diff --git a/crates/chronicle-synth/src/domain.rs b/crates/chronicle-synth/src/domain.rs index 04a379df7..a0980d302 100644 --- a/crates/chronicle-synth/src/domain.rs +++ b/crates/chronicle-synth/src/domain.rs @@ -1,113 +1,114 @@ use std::{collections::BTreeMap, path::Path}; -use common::domain::PrimitiveType; use serde::Deserialize; use serde_json::json; +use common::domain::PrimitiveType; + use crate::{ - collection::{Collection, DomainCollection, Generator, Operation}, - error::ChronicleSynthError, + collection::{Collection, DomainCollection, Generator, Operation}, + error::ChronicleSynthError, }; #[derive(Debug)] pub struct TypesAttributesRoles { - pub name: String, - entities: BTreeMap>, - agents: BTreeMap>, - activities: BTreeMap>, - roles: Vec, + pub name: String, + entities: BTreeMap>, + agents: BTreeMap>, + activities: BTreeMap>, + roles: Vec, } impl TypesAttributesRoles { - /// Creates a new `TypesAttributesRoles` instance from a YAML file at the specified path. - /// - /// # Arguments - /// - /// * `path` - The path to the YAML file. - /// - /// # Returns - /// - /// A `Result` containing the `TypesAttributesRoles` instance, or an error if the operation - /// fails. - pub fn from_file(path: &Path) -> Result { - #[derive(Debug, Deserialize)] - struct ChronicleDomain { - #[serde(skip)] - _roles_doc: Option, - roles: Vec, - name: String, - attributes: BTreeMap, - entities: BTreeMap, - agents: BTreeMap, - activities: BTreeMap, - } - - impl ChronicleDomain { - fn from_path(path: &Path) -> Result { - let yaml: String = std::fs::read_to_string(path)?; - let domain: ChronicleDomain = serde_yaml::from_str(&yaml)?; - Ok(domain) - } - } - - impl From for TypesAttributesRoles { - fn from(value: ChronicleDomain) -> Self { - let mut attribute_types = BTreeMap::new(); - attribute_types.extend(value.attributes); - - let entities = value - .entities - .into_iter() - .map(|(entity_type, attributes)| { - (entity_type, attributes.link_attribute_types(&attribute_types)) - }) - .collect(); - let agents = value - .agents - .into_iter() - .map(|(agent_type, attributes)| { - (agent_type, attributes.link_attribute_types(&attribute_types)) - }) - .collect(); - let activities = value - .activities - .into_iter() - .map(|(activity_type, attributes)| { - (activity_type, attributes.link_attribute_types(&attribute_types)) - }) - .collect(); - - Self { name: value.name, entities, agents, activities, roles: value.roles } - } - } - - let domain = ChronicleDomain::from_path(path)?; - Ok(domain.into()) - } - - pub fn generate_domain_collections(&self) -> Result, ChronicleSynthError> { - let mut collections = vec![self.generate_roles()?]; - collections.extend(self.generate_activity_schema()?); - collections.extend(self.generate_agent_schema()?); - collections.extend(self.generate_entity_schema()?); - Ok(collections) - } - - fn generate_roles(&self) -> Result { - generate_roles(&self.roles) - } - - fn generate_activity_schema(&self) -> Result, ChronicleSynthError> { - generate_schema(&self.activities) - } - - fn generate_agent_schema(&self) -> Result, ChronicleSynthError> { - generate_schema(&self.agents) - } - - fn generate_entity_schema(&self) -> Result, ChronicleSynthError> { - generate_schema(&self.entities) - } + /// Creates a new `TypesAttributesRoles` instance from a YAML file at the specified path. + /// + /// # Arguments + /// + /// * `path` - The path to the YAML file. + /// + /// # Returns + /// + /// A `Result` containing the `TypesAttributesRoles` instance, or an error if the operation + /// fails. + pub fn from_file(path: &Path) -> Result { + #[derive(Debug, Deserialize)] + struct ChronicleDomain { + #[serde(skip)] + _roles_doc: Option, + roles: Vec, + name: String, + attributes: BTreeMap, + entities: BTreeMap, + agents: BTreeMap, + activities: BTreeMap, + } + + impl ChronicleDomain { + fn from_path(path: &Path) -> Result { + let yaml: String = std::fs::read_to_string(path)?; + let domain: ChronicleDomain = serde_yaml::from_str(&yaml)?; + Ok(domain) + } + } + + impl From for TypesAttributesRoles { + fn from(value: ChronicleDomain) -> Self { + let mut attribute_types = BTreeMap::new(); + attribute_types.extend(value.attributes); + + let entities = value + .entities + .into_iter() + .map(|(entity_type, attributes)| { + (entity_type, attributes.link_attribute_types(&attribute_types)) + }) + .collect(); + let agents = value + .agents + .into_iter() + .map(|(agent_type, attributes)| { + (agent_type, attributes.link_attribute_types(&attribute_types)) + }) + .collect(); + let activities = value + .activities + .into_iter() + .map(|(activity_type, attributes)| { + (activity_type, attributes.link_attribute_types(&attribute_types)) + }) + .collect(); + + Self { name: value.name, entities, agents, activities, roles: value.roles } + } + } + + let domain = ChronicleDomain::from_path(path)?; + Ok(domain.into()) + } + + pub fn generate_domain_collections(&self) -> Result, ChronicleSynthError> { + let mut collections = vec![self.generate_roles()?]; + collections.extend(self.generate_activity_schema()?); + collections.extend(self.generate_agent_schema()?); + collections.extend(self.generate_entity_schema()?); + Ok(collections) + } + + fn generate_roles(&self) -> Result { + generate_roles(&self.roles) + } + + fn generate_activity_schema(&self) -> Result, ChronicleSynthError> { + generate_schema(&self.activities) + } + + fn generate_agent_schema(&self) -> Result, ChronicleSynthError> { + generate_schema(&self.agents) + } + + fn generate_entity_schema(&self) -> Result, ChronicleSynthError> { + generate_schema(&self.entities) + } } #[derive(Debug, Deserialize, Eq, PartialEq, Hash, PartialOrd, Ord)] @@ -117,108 +118,108 @@ struct AttributeType(String); struct ParsedDomainType(String); impl ParsedDomainType { - fn as_str(&self) -> &str { - &self.0 - } + fn as_str(&self) -> &str { + &self.0 + } } #[derive(Debug, Deserialize)] struct Role(String); impl Role { - fn as_str(&self) -> &str { - &self.0 - } + fn as_str(&self) -> &str { + &self.0 + } } #[derive(Debug)] enum SynthType { - String, - Object, - Number, - Bool, + String, + Object, + Number, + Bool, } impl From<&ChroniclePrimitive> for SynthType { - fn from(value: &ChroniclePrimitive) -> Self { - match value.r#type { - PrimitiveType::String => SynthType::String, - PrimitiveType::JSON => SynthType::Object, - PrimitiveType::Int => SynthType::Number, - PrimitiveType::Bool => SynthType::Bool, - } - } + fn from(value: &ChroniclePrimitive) -> Self { + match value.r#type { + PrimitiveType::String => SynthType::String, + PrimitiveType::JSON => SynthType::Object, + PrimitiveType::Int => SynthType::Number, + PrimitiveType::Bool => SynthType::Bool, + } + } } #[derive(Debug, Deserialize)] struct ChroniclePrimitive { - #[serde(skip)] - _doc: Option, - #[serde(rename = "type")] - r#type: PrimitiveType, + #[serde(skip)] + _doc: Option, + #[serde(rename = "type")] + r#type: PrimitiveType, } #[derive(Debug, Deserialize)] struct Attributes { - #[serde(skip)] - _doc: Option, - attributes: Vec, + #[serde(skip)] + _doc: Option, + attributes: Vec, } impl Attributes { - fn link_attribute_types( - self, - attribute_types: &BTreeMap, - ) -> BTreeMap { - let mut attr = BTreeMap::new(); - for attr_type in self.attributes { - let r#type: SynthType = attribute_types.get(&attr_type).unwrap().into(); - attr.insert(attr_type, r#type); - } - attr - } + fn link_attribute_types( + self, + attribute_types: &BTreeMap, + ) -> BTreeMap { + let mut attr = BTreeMap::new(); + for attr_type in self.attributes { + let r#type: SynthType = attribute_types.get(&attr_type).unwrap().into(); + attr.insert(attr_type, r#type); + } + attr + } } fn generate_roles(roles: &[Role]) -> Result { - let mut variants = vec![json!({ + let mut variants = vec![json!({ "type": "string", "constant": "UNSPECIFIED" })]; - // Uppercase guaranteed by the Linter - for role in roles { - variants.push(json!({ + // Uppercase guaranteed by the Linter + for role in roles { + variants.push(json!({ "type": "string", "constant": role.as_str() })); - } + } - let roles = json!({ + let roles = json!({ "type": "one_of", "variants": variants }); - let domain_collection = DomainCollection::new("roles", roles); + let domain_collection = DomainCollection::new("roles", roles); - Ok(Collection::Generator(Generator::DomainCollection(domain_collection))) + Ok(Collection::Generator(Generator::DomainCollection(domain_collection))) } fn domain_type_id_for_domain(ParsedDomainType(r#type): &ParsedDomainType) -> Collection { - let domain_type_id = json!({ + let domain_type_id = json!({ "type": "string", "constant": r#type }); - let collection_name = format!("{}_domain_type_id", r#type.to_lowercase()); - let domain_collection = DomainCollection::new(collection_name, domain_type_id); + let collection_name = format!("{}_domain_type_id", r#type.to_lowercase()); + let domain_collection = DomainCollection::new(collection_name, domain_type_id); - Collection::Generator(Generator::DomainCollection(domain_collection)) + Collection::Generator(Generator::DomainCollection(domain_collection)) } fn set_attributes(type_name_lower: &str) -> Collection { - let type_collection = format!("@{}_attributes", type_name_lower); - let type_domain_type = format!("@{}_domain_type_id", type_name_lower); - let type_attributes = json!({ + let type_collection = format!("@{}_attributes", type_name_lower); + let type_domain_type = format!("@{}_domain_type_id", type_name_lower); + let type_attributes = json!({ "type": "object", "@id": "_:n1", "@type": { @@ -251,100 +252,101 @@ fn set_attributes(type_name_lower: &str) -> Collection { "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" }); - let name = format!("set_{}_attributes", type_name_lower); - let domain_collection = DomainCollection::new(name, type_attributes); - Collection::Operation(Operation::DomainCollection(domain_collection)) + let name = format!("set_{}_attributes", type_name_lower); + let domain_collection = DomainCollection::new(name, type_attributes); + Collection::Operation(Operation::DomainCollection(domain_collection)) } fn type_attribute_variants( - type_name_lower: &str, - attributes: &BTreeMap, + type_name_lower: &str, + attributes: &BTreeMap, ) -> Result { - let mut type_attribute_variants: BTreeMap = maplit::btreemap! { + let mut type_attribute_variants: BTreeMap = maplit::btreemap! { "type".to_string() => json!("object"), }; - for (AttributeType(attribute), r#type) in attributes { - let type_attribute_variant = match r#type { - SynthType::String => { - json!({ + for (AttributeType(attribute), r#type) in attributes { + let type_attribute_variant = match r#type { + SynthType::String => { + json!({ "type": "string", "faker": { "generator": "bs_noun" } }) - }, - SynthType::Number => { - json!({ + } + SynthType::Number => { + json!({ "type": "number", "subtype": "u32" }) - }, - SynthType::Bool => { - json!({ + } + SynthType::Bool => { + json!({ "type": "bool", "frequency": 0.5 }) - }, - // Object will be an empty object. - // This is something that could be tweaked on a case by case basis given some domain - // knowledge - SynthType::Object => { - json!({ + } + // Object will be an empty object. + // This is something that could be tweaked on a case by case basis given some domain + // knowledge + SynthType::Object => { + json!({ "type": "object", }) - }, - }; + } + }; - type_attribute_variants.insert(attribute.clone(), type_attribute_variant); - } + type_attribute_variants.insert(attribute.clone(), type_attribute_variant); + } - let name = format!("{}_attributes", type_name_lower); - let schema = serde_json::to_value(type_attribute_variants)?; - let collection = DomainCollection::new(name, schema); + let name = format!("{}_attributes", type_name_lower); + let schema = serde_json::to_value(type_attribute_variants)?; + let collection = DomainCollection::new(name, schema); - Ok(Collection::Generator(Generator::DomainCollection(collection))) + Ok(Collection::Generator(Generator::DomainCollection(collection))) } fn generate_schema( - types_attributes: &BTreeMap>, + types_attributes: &BTreeMap>, ) -> Result, ChronicleSynthError> { - let mut collections = Vec::new(); + let mut collections = Vec::new(); - for (r#type, attributes) in types_attributes { - let collection1 = domain_type_id_for_domain(r#type); - collections.push(collection1); + for (r#type, attributes) in types_attributes { + let collection1 = domain_type_id_for_domain(r#type); + collections.push(collection1); - let type_name_lower = r#type.as_str().to_lowercase(); + let type_name_lower = r#type.as_str().to_lowercase(); - let collection2 = set_attributes(&type_name_lower); - collections.push(collection2); + let collection2 = set_attributes(&type_name_lower); + collections.push(collection2); - let collection3 = type_attribute_variants(&type_name_lower, attributes)?; - collections.push(collection3); - } - Ok(collections) + let collection3 = type_attribute_variants(&type_name_lower, attributes)?; + collections.push(collection3); + } + Ok(collections) } #[cfg(test)] mod tests { - use crate::collection::CollectionHandling; + use maplit::btreemap; + + use crate::collection::CollectionHandling; - use super::*; - use maplit::btreemap; + use super::*; - #[test] - fn test_type_attribute_variants() { - // Create a sample attribute map with two attributes - let attributes = btreemap! { + #[test] + fn test_type_attribute_variants() { + // Create a sample attribute map with two attributes + let attributes = btreemap! { AttributeType("TestAttribute1".to_owned()) => SynthType::String, AttributeType("TestAttribute2".to_owned()) => SynthType::Number, }; - // Call the function being tested - let result = type_attribute_variants("test_type", &attributes).unwrap(); + // Call the function being tested + let result = type_attribute_variants("test_type", &attributes).unwrap(); - // Assert that the function returns a Collection with the expected properties - insta::assert_json_snapshot!(result.json_schema().unwrap().to_string(), @r###""{\"TestAttribute1\":{\"faker\":{\"generator\":\"bs_noun\"},\"type\":\"string\"},\"TestAttribute2\":{\"subtype\":\"u32\",\"type\":\"number\"},\"type\":\"object\"}""###); - } + // Assert that the function returns a Collection with the expected properties + insta::assert_json_snapshot!(result.json_schema().unwrap().to_string(), @r###""{\"TestAttribute1\":{\"faker\":{\"generator\":\"bs_noun\"},\"type\":\"string\"},\"TestAttribute2\":{\"subtype\":\"u32\",\"type\":\"number\"},\"type\":\"object\"}""###); + } } diff --git a/crates/chronicle-synth/src/error.rs b/crates/chronicle-synth/src/error.rs index fba455705..b22dc7ddc 100644 --- a/crates/chronicle-synth/src/error.rs +++ b/crates/chronicle-synth/src/error.rs @@ -2,31 +2,31 @@ use thiserror::Error; #[derive(Error, Debug)] pub enum ChronicleSynthError { - #[error("Chronicle domain parsing error: {0}")] - ModelError( - #[from] - #[source] - common::domain::ModelError, - ), + #[error("Chronicle domain parsing error: {0}")] + ModelError( + #[from] + #[source] + common::domain::ModelError, + ), - #[error("Invalid JSON: {0}")] - JsonError( - #[from] - #[source] - serde_json::Error, - ), + #[error("Invalid JSON: {0}")] + JsonError( + #[from] + #[source] + serde_json::Error, + ), - #[error("I/O error: {0}")] - IO( - #[from] - #[source] - std::io::Error, - ), + #[error("I/O error: {0}")] + IO( + #[from] + #[source] + std::io::Error, + ), - #[error("YAML parsing error: {0}")] - YamlError( - #[from] - #[source] - serde_yaml::Error, - ), + #[error("YAML parsing error: {0}")] + YamlError( + #[from] + #[source] + serde_yaml::Error, + ), } diff --git a/crates/chronicle-synth/src/generate.rs b/crates/chronicle-synth/src/generate.rs index 282ccfb4b..5897106b8 100644 --- a/crates/chronicle-synth/src/generate.rs +++ b/crates/chronicle-synth/src/generate.rs @@ -1,76 +1,77 @@ //! A command-line interface for generating Chronicle Synth schema for a given domain. use std::{ - fs::File, - io::{BufReader, Write}, - path::{Path, PathBuf}, + fs::File, + io::{BufReader, Write}, + path::{Path, PathBuf}, }; -use chronicle::codegen::linter::check_files; -use chronicle_synth::{ - collection::{Collection, CollectionHandling}, - domain::TypesAttributesRoles, - error::ChronicleSynthError, -}; use clap::StructOpt; use owo_colors::OwoColorize; use serde::{Deserialize, Serialize}; +use chronicle::codegen::linter::check_files; +use chronicle_synth::{ + collection::{Collection, CollectionHandling}, + domain::TypesAttributesRoles, + error::ChronicleSynthError, +}; + #[derive(StructOpt)] #[structopt( - name = "chronicle-domain-synth", - about = "Generate Chronicle Synth schema for your domain", - author = "Blockchain Technology Partners" + name = "chronicle-domain-synth", + about = "Generate Chronicle Synth schema for your domain", + author = "Blockchain Technology Partners" )] struct Cli { - #[structopt( - value_name = "FILE", - help = "Chronicle domain definition file", - parse(from_os_str), - default_value = "crates/chronicle-synth/domain.yaml" - )] - domain_file: PathBuf, + #[structopt( + value_name = "FILE", + help = "Chronicle domain definition file", + parse(from_os_str), + default_value = "crates/chronicle-synth/domain.yaml" + )] + domain_file: PathBuf, } const COLLECT_SCRIPT: &str = "./crates/chronicle-synth/collect"; fn main() -> Result<(), ChronicleSynthError> { - let args = Cli::from_args(); + let args = Cli::from_args(); - let domain_file = args.domain_file.as_path(); + let domain_file = args.domain_file.as_path(); - // Use Chronicle Domain Linter to check the domain definition file - let filenames = vec![domain_file.to_str().ok_or_else(|| { - ChronicleSynthError::IO(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Invalid path argument", - )) - })?]; + // Use Chronicle Domain Linter to check the domain definition file + let filenames = vec![domain_file.to_str().ok_or_else(|| { + ChronicleSynthError::IO(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Invalid path argument", + )) + })?]; - check_files(filenames); + check_files(filenames); - println!("{}", "No domain definition errors detected.".green()); + println!("{}", "No domain definition errors detected.".green()); - generate_synth_collections(domain_file)?; + generate_synth_collections(domain_file)?; - // Run the `collect` script to collate the complete set of Synth collections for the domain - let output = std::process::Command::new("bash") - .args([COLLECT_SCRIPT]) - .output() - .expect("Failed to execute 'collect' command"); + // Run the `collect` script to collate the complete set of Synth collections for the domain + let output = std::process::Command::new("bash") + .args([COLLECT_SCRIPT]) + .output() + .expect("Failed to execute 'collect' command"); - println!("{}", String::from_utf8_lossy(&output.stdout)); + println!("{}", String::from_utf8_lossy(&output.stdout)); - println!( - "{} contains the additional Synth collections generated for your domain.", - "crates/chronicle-synth/domain-schema/".underline() - ); - println!( - "The complete set of Synth collections for your domain can be found in '{}'.", - "crates/chronicle-synth/collections/".underline() - ); + println!( + "{} contains the additional Synth collections generated for your domain.", + "crates/chronicle-synth/domain-schema/".underline() + ); + println!( + "The complete set of Synth collections for your domain can be found in '{}'.", + "crates/chronicle-synth/collections/".underline() + ); - Ok(()) + Ok(()) } /// Generates Synth collections for the given domain definition file. @@ -99,24 +100,24 @@ fn main() -> Result<(), ChronicleSynthError> { /// } /// ``` fn generate_synth_collections(domain_file: &Path) -> Result<(), ChronicleSynthError> { - let generator = TypesAttributesRoles::from_file(domain_file)?; - println!("Generating schema for domain: {}.", generator.name.underline()); - - let dir_path = PathBuf::from(DOMAIN_SCHEMA_TARGET_DIRECTORY); - std::fs::create_dir_all(&dir_path)?; - - let collections = generator.generate_domain_collections()?; - for collection in collections { - write_collection(&collection, &dir_path)?; - - match collection { - Collection::Operation(_) => {}, - Collection::Generator(collection) => { - append_to_exclude_list(EXCLUDE_LIST, &collection.name())?; - }, - } - } - Ok(()) + let generator = TypesAttributesRoles::from_file(domain_file)?; + println!("Generating schema for domain: {}.", generator.name.underline()); + + let dir_path = PathBuf::from(DOMAIN_SCHEMA_TARGET_DIRECTORY); + std::fs::create_dir_all(&dir_path)?; + + let collections = generator.generate_domain_collections()?; + for collection in collections { + write_collection(&collection, &dir_path)?; + + match collection { + Collection::Operation(_) => {} + Collection::Generator(collection) => { + append_to_exclude_list(EXCLUDE_LIST, &collection.name())?; + } + } + } + Ok(()) } const DOMAIN_SCHEMA_TARGET_DIRECTORY: &str = "./crates/chronicle-synth/domain-schema"; @@ -125,86 +126,85 @@ const EXCLUDE_LIST: &str = "./crates/chronicle-synth/exclude_collections.json"; #[derive(Deserialize, Serialize)] struct ExcludeCollections { - exclude: Vec, + exclude: Vec, } impl ExcludeCollections { - fn from_file(filename: impl AsRef) -> Result { - let file = File::open(filename)?; - let reader = BufReader::new(file); - let exclude_collections = serde_json::from_reader(reader)?; - Ok(exclude_collections) - } + fn from_file(filename: impl AsRef) -> Result { + let file = File::open(filename)?; + let reader = BufReader::new(file); + let exclude_collections = serde_json::from_reader(reader)?; + Ok(exclude_collections) + } } fn write_collection(collection: &Collection, dir_path: &Path) -> Result<(), ChronicleSynthError> { - let file_path = dir_path.join(collection.path()); - let mut file = File::create(file_path)?; - let schema = collection.json_schema()?; - file.write_all(serde_json::to_string(&schema)?.as_bytes())?; - Ok(()) + let file_path = dir_path.join(collection.path()); + let mut file = File::create(file_path)?; + let schema = collection.json_schema()?; + file.write_all(serde_json::to_string(&schema)?.as_bytes())?; + Ok(()) } /// Appends a collection name to the "exclude list" file, a list of collection files to be ignored /// when generating the domain schema. See `generate` script in this repository for more /// information. fn append_to_exclude_list( - path: impl AsRef, - collection: &str, + path: impl AsRef, + collection: &str, ) -> Result<(), ChronicleSynthError> { - let collection = collection.to_string(); - let mut list = ExcludeCollections::from_file(&path)?; + let collection = collection.to_string(); + let mut list = ExcludeCollections::from_file(&path)?; - if list.exclude.contains(&collection) { - return Ok(()); - } else { - list.exclude.push(collection); - } + if list.exclude.contains(&collection) { + return Ok(()); + } else { + list.exclude.push(collection); + } - let mut file = File::create(&path)?; - file.write_all(serde_json::to_string_pretty(&list)?.as_bytes())?; + let mut file = File::create(&path)?; + file.write_all(serde_json::to_string_pretty(&list)?.as_bytes())?; - Ok(()) + Ok(()) } #[cfg(test)] mod tests { - use super::*; + use assert_fs::prelude::*; - use assert_fs::prelude::*; + use super::*; - const PATH: &str = "test_exclude_collections.json"; + const PATH: &str = "test_exclude_collections.json"; - fn create_test_exclude_collections( - ) -> Result> { - let file = assert_fs::NamedTempFile::new(PATH)?; + fn create_test_exclude_collections() -> Result> { + let file = assert_fs::NamedTempFile::new(PATH)?; - file.write_str( - r#" + file.write_str( + r#" { "exclude": [ "already_ignore_this" ] } "#, - )?; + )?; - Ok(file) - } + Ok(file) + } - #[test] - fn test_append_to_exclude_list() -> Result<(), ChronicleSynthError> { - let file = create_test_exclude_collections().unwrap(); + #[test] + fn test_append_to_exclude_list() -> Result<(), ChronicleSynthError> { + let file = create_test_exclude_collections().unwrap(); - // Call the function to append to the exclude list - append_to_exclude_list(file.path(), "ignore_this_collection_when_printing")?; + // Call the function to append to the exclude list + append_to_exclude_list(file.path(), "ignore_this_collection_when_printing")?; - // Read the contents of the file and check if the collection was added - let file = File::open(file.path())?; - let reader = BufReader::new(file); - let exclude_collections: ExcludeCollections = serde_json::from_reader(reader)?; + // Read the contents of the file and check if the collection was added + let file = File::open(file.path())?; + let reader = BufReader::new(file); + let exclude_collections: ExcludeCollections = serde_json::from_reader(reader)?; - insta::assert_json_snapshot!(exclude_collections, @r###" + insta::assert_json_snapshot!(exclude_collections, @r###" { "exclude": [ "already_ignore_this", @@ -212,29 +212,28 @@ mod tests { ] }"###); - Ok(()) - } + Ok(()) + } - #[test] - fn test_append_to_exclude_list_skips_collections_already_on_list( - ) -> Result<(), ChronicleSynthError> { - let file = create_test_exclude_collections().unwrap(); + #[test] + fn test_append_to_exclude_list_skips_collections_already_on_list() -> Result<(), ChronicleSynthError> { + let file = create_test_exclude_collections().unwrap(); - // Call the function to append to the exclude list - append_to_exclude_list(file.path(), "already_ignore_this")?; + // Call the function to append to the exclude list + append_to_exclude_list(file.path(), "already_ignore_this")?; - // Read the contents of the file and check if the collection was added - let file = File::open(file.path())?; - let reader = BufReader::new(file); - let exclude_collections: ExcludeCollections = serde_json::from_reader(reader)?; + // Read the contents of the file and check if the collection was added + let file = File::open(file.path())?; + let reader = BufReader::new(file); + let exclude_collections: ExcludeCollections = serde_json::from_reader(reader)?; - insta::assert_json_snapshot!(exclude_collections, @r###" + insta::assert_json_snapshot!(exclude_collections, @r###" { "exclude": [ "already_ignore_this" ] }"###); - Ok(()) - } + Ok(()) + } } diff --git a/crates/chronicle-synth/synth/activity_uses.json b/crates/chronicle-synth/synth/activity_uses.json index 5d88ae2c6..e664ff3f4 100644 --- a/crates/chronicle-synth/synth/activity_uses.json +++ b/crates/chronicle-synth/synth/activity_uses.json @@ -1,13 +1,13 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#ActivityUses" - }, - "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", - "http://chronicle.works/chronicleoperations/ns#entityName": "@entity_name", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#ActivityUses" + }, + "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", + "http://chronicle.works/chronicleoperations/ns#entityName": "@entity_name", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" } diff --git a/crates/chronicle-synth/synth/agent_acts_on_behalf_of.json b/crates/chronicle-synth/synth/agent_acts_on_behalf_of.json index dcabc9ebe..7e82b934f 100644 --- a/crates/chronicle-synth/synth/agent_acts_on_behalf_of.json +++ b/crates/chronicle-synth/synth/agent_acts_on_behalf_of.json @@ -1,14 +1,14 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#AgentActsOnBehalfOf" - }, - "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", - "http://chronicle.works/chronicleoperations/ns#delegateId": "@agent_name", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid", - "http://chronicle.works/chronicleoperations/ns#responsibleId": "@second_agent_name" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#AgentActsOnBehalfOf" + }, + "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", + "http://chronicle.works/chronicleoperations/ns#delegateId": "@agent_name", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid", + "http://chronicle.works/chronicleoperations/ns#responsibleId": "@second_agent_name" } diff --git a/crates/chronicle-synth/synth/attribute.json b/crates/chronicle-synth/synth/attribute.json index 50c7cdcdc..e6307dc1c 100644 --- a/crates/chronicle-synth/synth/attribute.json +++ b/crates/chronicle-synth/synth/attribute.json @@ -1,3 +1,3 @@ { - "type": "object" + "type": "object" } diff --git a/crates/chronicle-synth/synth/attributes.json b/crates/chronicle-synth/synth/attributes.json index 37aec08af..2732aa600 100644 --- a/crates/chronicle-synth/synth/attributes.json +++ b/crates/chronicle-synth/synth/attributes.json @@ -1,12 +1,12 @@ { - "type": "array", - "length": 1, - "content": { - "type": "object", - "@type": { - "type": "string", - "constant": "@json" - }, - "@value": "@attribute" - } + "type": "array", + "length": 1, + "content": { + "type": "object", + "@type": { + "type": "string", + "constant": "@json" + }, + "@value": "@attribute" + } } diff --git a/crates/chronicle-synth/synth/create_namespace.json b/crates/chronicle-synth/synth/create_namespace.json index cd1bdbf1a..41c9915d3 100644 --- a/crates/chronicle-synth/synth/create_namespace.json +++ b/crates/chronicle-synth/synth/create_namespace.json @@ -1,11 +1,11 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#CreateNamespace" - }, - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#CreateNamespace" + }, + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" } diff --git a/crates/chronicle-synth/synth/domain_type_id.json b/crates/chronicle-synth/synth/domain_type_id.json index 6cedacdd6..f0f676023 100644 --- a/crates/chronicle-synth/synth/domain_type_id.json +++ b/crates/chronicle-synth/synth/domain_type_id.json @@ -1,13 +1,13 @@ { - "type": "array", - "length": 1, - "content": { - "type": "object", - "@value": { - "type": "string", - "faker": { - "generator": "bs_noun" - } - } + "type": "array", + "length": 1, + "content": { + "type": "object", + "@value": { + "type": "string", + "faker": { + "generator": "bs_noun" + } } + } } diff --git a/crates/chronicle-synth/synth/earlier_date_time.json b/crates/chronicle-synth/synth/earlier_date_time.json index 7443f5394..522d51c27 100644 --- a/crates/chronicle-synth/synth/earlier_date_time.json +++ b/crates/chronicle-synth/synth/earlier_date_time.json @@ -1,13 +1,13 @@ { - "type": "array", - "length": 1, - "content": { - "type": "object", - "@value": { - "type": "date_time", - "format": "%+", - "begin": "2000-07-08T00:34:00.026490+09:30", - "end": "2000-07-08T00:35:00.026490+09:30" - } + "type": "array", + "length": 1, + "content": { + "type": "object", + "@value": { + "type": "date_time", + "format": "%+", + "begin": "2000-07-08T00:34:00.026490+09:30", + "end": "2000-07-08T00:35:00.026490+09:30" } + } } diff --git a/crates/chronicle-synth/synth/end_activity.json b/crates/chronicle-synth/synth/end_activity.json index 7536f9db5..eb55965a4 100644 --- a/crates/chronicle-synth/synth/end_activity.json +++ b/crates/chronicle-synth/synth/end_activity.json @@ -1,13 +1,13 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#EndActivity" - }, - "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid", - "http://chronicle.works/chronicleoperations/ns#endActivityTime": "@later_date_time" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#EndActivity" + }, + "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid", + "http://chronicle.works/chronicleoperations/ns#endActivityTime": "@later_date_time" } diff --git a/crates/chronicle-synth/synth/entity_derive.json b/crates/chronicle-synth/synth/entity_derive.json index 2b7be5c22..c5c854415 100644 --- a/crates/chronicle-synth/synth/entity_derive.json +++ b/crates/chronicle-synth/synth/entity_derive.json @@ -1,13 +1,13 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#EntityDerive" - }, - "http://chronicle.works/chronicleoperations/ns#entityName": "@entity_name", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid", - "http://chronicle.works/chronicleoperations/ns#usedEntityName": "@second_entity_name" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#EntityDerive" + }, + "http://chronicle.works/chronicleoperations/ns#entityName": "@entity_name", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid", + "http://chronicle.works/chronicleoperations/ns#usedEntityName": "@second_entity_name" } diff --git a/crates/chronicle-synth/synth/later_date_time.json b/crates/chronicle-synth/synth/later_date_time.json index 0619cf68b..3150ba01d 100644 --- a/crates/chronicle-synth/synth/later_date_time.json +++ b/crates/chronicle-synth/synth/later_date_time.json @@ -1,13 +1,13 @@ { - "type": "array", - "length": 1, - "content": { - "type": "object", - "@value": { - "type": "date_time", - "format": "%+", - "begin": "2001-07-08T00:35:00.026490+09:30", - "end": "2001-07-08T00:36:00.026490+09:30" - } + "type": "array", + "length": 1, + "content": { + "type": "object", + "@value": { + "type": "date_time", + "format": "%+", + "begin": "2001-07-08T00:35:00.026490+09:30", + "end": "2001-07-08T00:36:00.026490+09:30" } + } } diff --git a/crates/chronicle-synth/synth/namespace_uuid.json b/crates/chronicle-synth/synth/namespace_uuid.json index d28f9c637..5e5827152 100644 --- a/crates/chronicle-synth/synth/namespace_uuid.json +++ b/crates/chronicle-synth/synth/namespace_uuid.json @@ -1,11 +1,11 @@ { - "type": "array", - "length": 1, - "content": { - "type": "object", - "@value": { - "type": "string", - "uuid": {} - } + "type": "array", + "length": 1, + "content": { + "type": "object", + "@value": { + "type": "string", + "uuid": {} } + } } diff --git a/crates/chronicle-synth/synth/role.json b/crates/chronicle-synth/synth/role.json index 14049ab1b..2c6ce1bd4 100644 --- a/crates/chronicle-synth/synth/role.json +++ b/crates/chronicle-synth/synth/role.json @@ -1,5 +1,5 @@ { - "type": "array", - "length": 1, - "content": "@roles" + "type": "array", + "length": 1, + "content": "@roles" } diff --git a/crates/chronicle-synth/synth/roles.json b/crates/chronicle-synth/synth/roles.json index 82a414f43..54841e97f 100644 --- a/crates/chronicle-synth/synth/roles.json +++ b/crates/chronicle-synth/synth/roles.json @@ -1,9 +1,9 @@ { - "type": "one_of", - "variants": [ - { - "type": "string", - "constant": "UNSPECIFIED" - } - ] + "type": "one_of", + "variants": [ + { + "type": "string", + "constant": "UNSPECIFIED" + } + ] } diff --git a/crates/chronicle-synth/synth/same_namespace_name.json b/crates/chronicle-synth/synth/same_namespace_name.json index 9f5f69fbf..88b847aba 100644 --- a/crates/chronicle-synth/synth/same_namespace_name.json +++ b/crates/chronicle-synth/synth/same_namespace_name.json @@ -1,11 +1,11 @@ { - "type": "array", - "length": 1, - "content": { - "type": "object", - "@value": { - "type": "string", - "pattern": "testns" - } + "type": "array", + "length": 1, + "content": { + "type": "object", + "@value": { + "type": "string", + "pattern": "testns" } + } } diff --git a/crates/chronicle-synth/synth/same_namespace_uuid.json b/crates/chronicle-synth/synth/same_namespace_uuid.json index c8d757d4c..1515d56db 100644 --- a/crates/chronicle-synth/synth/same_namespace_uuid.json +++ b/crates/chronicle-synth/synth/same_namespace_uuid.json @@ -1,11 +1,11 @@ { - "type": "array", - "length": 1, - "content": { - "type": "object", - "@value": { - "type": "string", - "pattern": "60976119-adc6-3826-a57b-3ccb0580e7bd" - } + "type": "array", + "length": 1, + "content": { + "type": "object", + "@value": { + "type": "string", + "pattern": "60976119-adc6-3826-a57b-3ccb0580e7bd" } + } } diff --git a/crates/chronicle-synth/synth/second_activity_name.json b/crates/chronicle-synth/synth/second_activity_name.json index 555d6c998..55f39d929 100644 --- a/crates/chronicle-synth/synth/second_activity_name.json +++ b/crates/chronicle-synth/synth/second_activity_name.json @@ -1,13 +1,13 @@ { - "type": "array", - "length": 1, - "content": { - "type": "object", - "@value": { - "type": "string", - "faker": { - "generator": "bs_verb" - } - } + "type": "array", + "length": 1, + "content": { + "type": "object", + "@value": { + "type": "string", + "faker": { + "generator": "bs_verb" + } } + } } diff --git a/crates/chronicle-synth/synth/second_agent_name.json b/crates/chronicle-synth/synth/second_agent_name.json index e469e6496..f3772bfa0 100644 --- a/crates/chronicle-synth/synth/second_agent_name.json +++ b/crates/chronicle-synth/synth/second_agent_name.json @@ -1,13 +1,13 @@ { - "type": "array", - "length": 1, - "content": { - "type": "object", - "@value": { - "type": "string", - "faker": { - "generator": "name" - } - } + "type": "array", + "length": 1, + "content": { + "type": "object", + "@value": { + "type": "string", + "faker": { + "generator": "name" + } } + } } diff --git a/crates/chronicle-synth/synth/second_entity_name.json b/crates/chronicle-synth/synth/second_entity_name.json index 6cedacdd6..f0f676023 100644 --- a/crates/chronicle-synth/synth/second_entity_name.json +++ b/crates/chronicle-synth/synth/second_entity_name.json @@ -1,13 +1,13 @@ { - "type": "array", - "length": 1, - "content": { - "type": "object", - "@value": { - "type": "string", - "faker": { - "generator": "bs_noun" - } - } + "type": "array", + "length": 1, + "content": { + "type": "object", + "@value": { + "type": "string", + "faker": { + "generator": "bs_noun" + } } + } } diff --git a/crates/chronicle-synth/synth/set_activity_attributes.json b/crates/chronicle-synth/synth/set_activity_attributes.json index 55209c182..fc4f9a922 100644 --- a/crates/chronicle-synth/synth/set_activity_attributes.json +++ b/crates/chronicle-synth/synth/set_activity_attributes.json @@ -1,13 +1,13 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#SetAttributes" - }, - "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", - "http://chronicle.works/chronicleoperations/ns#attributes": "@attributes", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#SetAttributes" + }, + "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", + "http://chronicle.works/chronicleoperations/ns#attributes": "@attributes", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" } diff --git a/crates/chronicle-synth/synth/set_agent_attributes.json b/crates/chronicle-synth/synth/set_agent_attributes.json index a0c67c4f3..5c2510826 100644 --- a/crates/chronicle-synth/synth/set_agent_attributes.json +++ b/crates/chronicle-synth/synth/set_agent_attributes.json @@ -1,13 +1,13 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#SetAttributes" - }, - "http://chronicle.works/chronicleoperations/ns#agentName": "@agent_name", - "http://chronicle.works/chronicleoperations/ns#attributes": "@attributes", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#SetAttributes" + }, + "http://chronicle.works/chronicleoperations/ns#agentName": "@agent_name", + "http://chronicle.works/chronicleoperations/ns#attributes": "@attributes", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" } diff --git a/crates/chronicle-synth/synth/set_entity_attributes.json b/crates/chronicle-synth/synth/set_entity_attributes.json index bd40fe462..18bbcbb2d 100644 --- a/crates/chronicle-synth/synth/set_entity_attributes.json +++ b/crates/chronicle-synth/synth/set_entity_attributes.json @@ -1,13 +1,13 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#SetAttributes" - }, - "http://chronicle.works/chronicleoperations/ns#entityName": "@entity_name", - "http://chronicle.works/chronicleoperations/ns#attributes": "@attributes", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#SetAttributes" + }, + "http://chronicle.works/chronicleoperations/ns#entityName": "@entity_name", + "http://chronicle.works/chronicleoperations/ns#attributes": "@attributes", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" } diff --git a/crates/chronicle-synth/synth/start_activity.json b/crates/chronicle-synth/synth/start_activity.json index 3a80e7f5e..b831263c6 100644 --- a/crates/chronicle-synth/synth/start_activity.json +++ b/crates/chronicle-synth/synth/start_activity.json @@ -1,13 +1,13 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#StartActivity" - }, - "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid", - "http://chronicle.works/chronicleoperations/ns#startActivityTime": "@earlier_date_time" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#StartActivity" + }, + "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid", + "http://chronicle.works/chronicleoperations/ns#startActivityTime": "@earlier_date_time" } diff --git a/crates/chronicle-synth/synth/was_associated_with.json b/crates/chronicle-synth/synth/was_associated_with.json index 7c58c8243..c7d5a149b 100644 --- a/crates/chronicle-synth/synth/was_associated_with.json +++ b/crates/chronicle-synth/synth/was_associated_with.json @@ -1,13 +1,13 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#WasAssociatedWith" - }, - "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", - "http://chronicle.works/chronicleoperations/ns#agentName": "@agent_name", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#WasAssociatedWith" + }, + "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", + "http://chronicle.works/chronicleoperations/ns#agentName": "@agent_name", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" } diff --git a/crates/chronicle-synth/synth/was_associated_with_has_role.json b/crates/chronicle-synth/synth/was_associated_with_has_role.json index 0fa2c97f3..93a24113d 100644 --- a/crates/chronicle-synth/synth/was_associated_with_has_role.json +++ b/crates/chronicle-synth/synth/was_associated_with_has_role.json @@ -1,14 +1,14 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#WasAssociatedWith" - }, - "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", - "http://chronicle.works/chronicleoperations/ns#agentName": "@agent_name", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid", - "http://chronicle.works/chronicleoperations/ns#role": "@role" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#WasAssociatedWith" + }, + "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", + "http://chronicle.works/chronicleoperations/ns#agentName": "@agent_name", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid", + "http://chronicle.works/chronicleoperations/ns#role": "@role" } diff --git a/crates/chronicle-synth/synth/was_attributed_to.json b/crates/chronicle-synth/synth/was_attributed_to.json index 5cdf6fd2d..c5e769ace 100644 --- a/crates/chronicle-synth/synth/was_attributed_to.json +++ b/crates/chronicle-synth/synth/was_attributed_to.json @@ -1,13 +1,13 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#WasAttributedTo" - }, - "http://chronicle.works/chronicleoperations/ns#agentName": "@agent_name", - "http://chronicle.works/chronicleoperations/ns#entityName": "@entity_name", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#WasAttributedTo" + }, + "http://chronicle.works/chronicleoperations/ns#agentName": "@agent_name", + "http://chronicle.works/chronicleoperations/ns#entityName": "@entity_name", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" } diff --git a/crates/chronicle-synth/synth/was_generated_by.json b/crates/chronicle-synth/synth/was_generated_by.json index ea5d43bf5..e4bd73bad 100644 --- a/crates/chronicle-synth/synth/was_generated_by.json +++ b/crates/chronicle-synth/synth/was_generated_by.json @@ -1,13 +1,13 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#WasGeneratedBy" - }, - "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", - "http://chronicle.works/chronicleoperations/ns#entityName": "@entity_name", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#WasGeneratedBy" + }, + "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", + "http://chronicle.works/chronicleoperations/ns#entityName": "@entity_name", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" } diff --git a/crates/chronicle-synth/synth/was_informed_by.json b/crates/chronicle-synth/synth/was_informed_by.json index 958afa35e..33fbec4e8 100644 --- a/crates/chronicle-synth/synth/was_informed_by.json +++ b/crates/chronicle-synth/synth/was_informed_by.json @@ -1,13 +1,13 @@ { - "type": "object", - "@id": "_:n1", - "@type": { - "type": "array", - "length": 1, - "content": "http://chronicle.works/chronicleoperations/ns#WasInformedBy" - }, - "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", - "http://chronicle.works/chronicleoperations/ns#informingActivityName": "@second_activity_name", - "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", - "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" + "type": "object", + "@id": "_:n1", + "@type": { + "type": "array", + "length": 1, + "content": "http://chronicle.works/chronicleoperations/ns#WasInformedBy" + }, + "http://chronicle.works/chronicleoperations/ns#activityName": "@activity_name", + "http://chronicle.works/chronicleoperations/ns#informingActivityName": "@second_activity_name", + "http://chronicle.works/chronicleoperations/ns#namespaceName": "@same_namespace_name", + "http://chronicle.works/chronicleoperations/ns#namespaceUuid": "@same_namespace_uuid" } diff --git a/crates/chronicle-telemetry/Cargo.toml b/crates/chronicle-telemetry/Cargo.toml index fff6b2146..035b07efe 100644 --- a/crates/chronicle-telemetry/Cargo.toml +++ b/crates/chronicle-telemetry/Cargo.toml @@ -1,20 +1,20 @@ [package] edition = "2021" -name = "chronicle-telemetry" +name = "chronicle-telemetry" version = "0.7.5" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cfg-if = { workspace = true } -console-subscriber = { workspace = true } -opentelemetry-otlp = { version = "^0.15" } -tracing = { workspace = true } -tracing-flame = { version = "^0.2" } -tracing-log = { workspace = true } +cfg-if = { workspace = true } +console-subscriber = { workspace = true } +opentelemetry-otlp = { version = "^0.15" } +tracing = { workspace = true } +tracing-flame = { version = "^0.2" } +tracing-log = { workspace = true } tracing-opentelemetry = { workspace = true } -tracing-subscriber = { workspace = true } -url = { workspace = true, features = ["serde"] } +tracing-subscriber = { workspace = true } +url = { workspace = true, features = ["serde"] } [features] tokio-tracing = [] diff --git a/crates/chronicle-telemetry/src/telemetry.rs b/crates/chronicle-telemetry/src/telemetry.rs index 353fe5ad7..b4734d3a5 100644 --- a/crates/chronicle-telemetry/src/telemetry.rs +++ b/crates/chronicle-telemetry/src/telemetry.rs @@ -1,4 +1,3 @@ - use tracing::subscriber::set_global_default; use tracing_flame::FlameLayer; use tracing_log::{log::LevelFilter, LogTracer}; @@ -7,9 +6,9 @@ use tracing_subscriber::{prelude::*, EnvFilter, Registry}; #[derive(Debug, Clone, Copy)] pub enum ConsoleLogging { - Off, - Pretty, - Json, + Off, + Pretty, + Json, } #[cfg(feature = "tokio-tracing")] @@ -33,7 +32,7 @@ macro_rules! oltp_exporter_layer { let tracer = opentelemetry_otlp::new_pipeline() .tracing() .with_exporter( - opentelemetry_otlp::new_exporter().tonic().with_env(), + opentelemetry_otlp::new_exporter().tonic(), ) .install_simple() .expect("Failed to install OpenTelemetry tracer"); @@ -43,73 +42,73 @@ macro_rules! oltp_exporter_layer { } pub struct OptionalDrop { - inner: Option, + inner: Option, } impl OptionalDrop { - pub fn new(inner: T) -> Self { - Self { inner: Some(inner) } - } + pub fn new(inner: T) -> Self { + Self { inner: Some(inner) } + } } impl Drop for OptionalDrop { - fn drop(&mut self) { - self.inner.take(); - } + fn drop(&mut self) { + self.inner.take(); + } } pub fn telemetry( - otel_enable: bool, - console_logging: ConsoleLogging, + otel_enable: bool, + console_logging: ConsoleLogging, ) -> impl Drop { - full_telemetry(otel_enable, None, console_logging) + full_telemetry(otel_enable, None, console_logging) } pub fn full_telemetry( - otel_export: bool, - flame_file: Option<&str>, - console_logging: ConsoleLogging, + otel_export: bool, + flame_file: Option<&str>, + console_logging: ConsoleLogging, ) -> impl Drop { - let (flame_layer, guard) = flame_file - .map(|path| { - let (flame_layer, guard) = FlameLayer::with_file(path).unwrap(); - (Some(flame_layer), Some(guard)) - }) - .unwrap_or((None, None)); - - LogTracer::init_with_filter(LevelFilter::Trace).ok(); - - let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("error")); - match (otel_export, flame_layer, console_logging) { - (true, Some(flame_layer), ConsoleLogging::Json) => set_global_default( - Registry::default() - .with(env_filter) - .with(flame_layer) - .with(stdio_layer!().json()) - .with(oltp_exporter_layer!()), - ), - - (true, Some(flame_layer), ConsoleLogging::Pretty) => set_global_default( - Registry::default() - .with(env_filter) - .with(flame_layer) - .with(stdio_layer!().pretty()) - .with(oltp_exporter_layer!()), - ), - (true, Some(flame_layer), ConsoleLogging::Off) => set_global_default( - Registry::default() - .with(env_filter) - .with(flame_layer) - .with(oltp_exporter_layer!()), - ), - (false, Some(flame_layer), ConsoleLogging::Json) => set_global_default( - Registry::default() - .with(env_filter) - .with(flame_layer) - .with(stdio_layer!().json()), - ), - (false, Some(flame_layer), ConsoleLogging::Pretty) => { - cfg_if::cfg_if! { + let (flame_layer, guard) = flame_file + .map(|path| { + let (flame_layer, guard) = FlameLayer::with_file(path).unwrap(); + (Some(flame_layer), Some(guard)) + }) + .unwrap_or((None, None)); + + LogTracer::init_with_filter(LevelFilter::Trace).ok(); + + let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("error")); + match (otel_export, flame_layer, console_logging) { + (true, Some(flame_layer), ConsoleLogging::Json) => set_global_default( + Registry::default() + .with(env_filter) + .with(flame_layer) + .with(stdio_layer!().json()) + .with(oltp_exporter_layer!()), + ), + + (true, Some(flame_layer), ConsoleLogging::Pretty) => set_global_default( + Registry::default() + .with(env_filter) + .with(flame_layer) + .with(stdio_layer!().pretty()) + .with(oltp_exporter_layer!()), + ), + (true, Some(flame_layer), ConsoleLogging::Off) => set_global_default( + Registry::default() + .with(env_filter) + .with(flame_layer) + .with(oltp_exporter_layer!()), + ), + (false, Some(flame_layer), ConsoleLogging::Json) => set_global_default( + Registry::default() + .with(env_filter) + .with(flame_layer) + .with(stdio_layer!().json()), + ), + (false, Some(flame_layer), ConsoleLogging::Pretty) => { + cfg_if::cfg_if! { if #[cfg(feature = "tokio-tracing")] { set_global_default(Registry::default() .with(env_filter) @@ -124,27 +123,27 @@ pub fn full_telemetry( ) } } - }, - (true, None, ConsoleLogging::Json) => set_global_default( - Registry::default() - .with(env_filter) - .with(stdio_layer!().json()) - .with(oltp_exporter_layer!()), - ), - (true, None, ConsoleLogging::Pretty) => set_global_default( - Registry::default() - .with(env_filter) - .with(stdio_layer!().pretty()) - .with(oltp_exporter_layer!()), - ), - (true, None, ConsoleLogging::Off) => { - let otel_layer = oltp_exporter_layer!(); - set_global_default(Registry::default().with(env_filter).with(otel_layer)) - }, - (false, None, ConsoleLogging::Json) => - set_global_default(Registry::default().with(env_filter).with(stdio_layer!().json())), - (false, None, ConsoleLogging::Pretty) => { - cfg_if::cfg_if! { + } + (true, None, ConsoleLogging::Json) => set_global_default( + Registry::default() + .with(env_filter) + .with(stdio_layer!().json()) + .with(oltp_exporter_layer!()), + ), + (true, None, ConsoleLogging::Pretty) => set_global_default( + Registry::default() + .with(env_filter) + .with(stdio_layer!().pretty()) + .with(oltp_exporter_layer!()), + ), + (true, None, ConsoleLogging::Off) => { + let otel_layer = oltp_exporter_layer!(); + set_global_default(Registry::default().with(env_filter).with(otel_layer)) + } + (false, None, ConsoleLogging::Json) => + set_global_default(Registry::default().with(env_filter).with(stdio_layer!().json())), + (false, None, ConsoleLogging::Pretty) => { + cfg_if::cfg_if! { if #[cfg(feature = "tokio-tracing")] { set_global_default(Registry::default() .with(env_filter) @@ -157,11 +156,11 @@ pub fn full_telemetry( ) } } - }, - _ => set_global_default(Registry::default().with(env_filter)), - } - .map_err(|e| eprintln!("Failed to set global default subscriber: {:?}", e)) - .ok(); + } + _ => set_global_default(Registry::default().with(env_filter)), + } + .map_err(|e| eprintln!("Failed to set global default subscriber: {:?}", e)) + .ok(); - OptionalDrop::new(guard) + OptionalDrop::new(guard) } diff --git a/crates/chronicle-test-infrastructure/Cargo.toml b/crates/chronicle-test-infrastructure/Cargo.toml index aa247c531..860305443 100644 --- a/crates/chronicle-test-infrastructure/Cargo.toml +++ b/crates/chronicle-test-infrastructure/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "chronicle-test-infrastructure" +name = "chronicle-test-infrastructure" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -13,9 +13,9 @@ chronicle-signing = { path = "../chronicle-signing" } chronicle-telemetry = { path = "../chronicle-telemetry" } chrono = { workspace = true } common = { path = "../common", features = [ - "parity-encoding", - "json-ld", - "std", + "parity-encoding", + "json-ld", + "std", ] } diesel = { workspace = true } frame-support = { version = "25.0.0", features = ["std"] } @@ -25,7 +25,7 @@ insta = { workspace = true, features = ["json", "yaml"] } lazy_static = { workspace = true } pallet-chronicle = { path = "../pallet-chronicle" } parity-scale-codec = { version = "3.4.0", default-features = false, features = [ - "derive", + "derive", ] } portpicker = { workspace = true } protocol-abstract = { path = "../protocol-abstract" } @@ -33,7 +33,7 @@ protocol-substrate = { path = "../protocol-substrate" } protocol-substrate-chronicle = { path = "../protocol-substrate-chronicle" } r2d2 = { version = "^0.8.1" } scale-info = { version = "2.10.0", default-features = false, features = [ - "derive", + "derive", ] } serde_json = { workspace = true } sp-core = { version = "25.0.0" } diff --git a/crates/chronicle-test-infrastructure/src/api_test.rs b/crates/chronicle-test-infrastructure/src/api_test.rs index c0b325ad7..0dd9cd891 100644 --- a/crates/chronicle-test-infrastructure/src/api_test.rs +++ b/crates/chronicle-test-infrastructure/src/api_test.rs @@ -1,15 +1,15 @@ use api::commands::{ - ActivityCommand, AgentCommand, ApiCommand, EntityCommand, ImportCommand, NamespaceCommand, + ActivityCommand, AgentCommand, ApiCommand, EntityCommand, ImportCommand, NamespaceCommand, }; use chrono::{TimeZone, Utc}; use common::{ - attributes::{Attribute, Attributes}, - identity::AuthId, - prov::{ - json_ld::ToJson, - operations::{ChronicleOperation, DerivationType}, - ActivityId, AgentId, DomaintypeId, EntityId, NamespaceId, - }, + attributes::{Attribute, Attributes}, + identity::AuthId, + prov::{ + json_ld::ToJson, + operations::{ChronicleOperation, DerivationType}, + ActivityId, AgentId, DomaintypeId, EntityId, NamespaceId, + }, }; use uuid::Uuid; @@ -18,10 +18,10 @@ use crate::substitutes::test_api; // Creates a mock file containing JSON-LD of the ChronicleOperations // that would be created by the given command, although not in any particular order. fn test_create_agent_operations_import() -> assert_fs::NamedTempFile { - let file = assert_fs::NamedTempFile::new("import.json").unwrap(); - assert_fs::prelude::FileWriteStr::write_str( - &file, - r#" + let file = assert_fs::NamedTempFile::new("import.json").unwrap(); + assert_fs::prelude::FileWriteStr::write_str( + &file, + r#" [ { "@id": "_:n1", @@ -94,36 +94,32 @@ fn test_create_agent_operations_import() -> assert_fs::NamedTempFile { } ] "#, - ) - .unwrap(); - file + ) + .unwrap(); + file } #[tokio::test] async fn test_import_operations() { - let mut api = test_api().await; + let mut api = test_api().await; - let file = test_create_agent_operations_import(); + let file = test_create_agent_operations_import(); - let contents = std::fs::read_to_string(file.path()).unwrap(); + let contents = std::fs::read_to_string(file.path()).unwrap(); - let json_array = serde_json::from_str::>(&contents).unwrap(); + let json_array = serde_json::from_str::>(&contents).unwrap(); - let mut operations = Vec::with_capacity(json_array.len()); - for value in json_array.into_iter() { - let op = ChronicleOperation::from_json(&value) - .await - .expect("Failed to parse imported JSON-LD to ChronicleOperation"); - operations.push(op); - } + let mut operations = Vec::with_capacity(json_array.len()); + for value in json_array.into_iter() { + let op = ChronicleOperation::from_json(&value) + .await + .expect("Failed to parse imported JSON-LD to ChronicleOperation"); + operations.push(op); + } - let namespace = NamespaceId::from_external_id( - "testns", - Uuid::parse_str("6803790d-5891-4dfa-b773-41827d2c630b").unwrap(), - ); - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!(api + insta::assert_json_snapshot!(api .dispatch(ApiCommand::Import(ImportCommand { operations: operations.clone() } ), identity.clone()) .await .unwrap() @@ -152,8 +148,8 @@ async fn test_import_operations() { } "###); - // Check that the operations that do not result in data changes are not submitted - insta::assert_json_snapshot!(api + // Check that the operations that do not result in data changes are not submitted + insta::assert_json_snapshot!(api .dispatch(ApiCommand::Import(ImportCommand { operations } ), identity) .await .unwrap() @@ -179,11 +175,11 @@ async fn test_import_operations() { #[tokio::test] async fn create_namespace() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!(api + insta::assert_json_snapshot!(api .dispatch(ApiCommand::NameSpace(NamespaceCommand::Create { id: "testns".into(), }), identity) @@ -203,11 +199,11 @@ async fn create_namespace() { #[tokio::test] async fn create_agent() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!(api.dispatch(ApiCommand::Agent(AgentCommand::Create { + insta::assert_json_snapshot!(api.dispatch(ApiCommand::Agent(AgentCommand::Create { id: "testagent".into(), namespace: "testns".into(), attributes: Attributes::new( @@ -248,11 +244,11 @@ async fn create_agent() { #[tokio::test] async fn create_system_activity() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!(api.dispatch(ApiCommand::Activity(ActivityCommand::Create { + insta::assert_json_snapshot!(api.dispatch(ApiCommand::Activity(ActivityCommand::Create { id: "testactivity".into(), namespace: common::prov::SYSTEM_ID.into(), attributes: Attributes::new( @@ -293,11 +289,11 @@ async fn create_system_activity() { #[tokio::test] async fn create_activity() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!(api.dispatch(ApiCommand::Activity(ActivityCommand::Create { + insta::assert_json_snapshot!(api.dispatch(ApiCommand::Activity(ActivityCommand::Create { id: "testactivity".into(), namespace: "testns".into(), attributes: Attributes::new( @@ -338,11 +334,11 @@ async fn create_activity() { #[tokio::test] async fn start_activity() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Agent(AgentCommand::Create { id: "testagent".into(), namespace: "testns".into(), @@ -381,17 +377,17 @@ async fn start_activity() { } "###); - api.dispatch( - ApiCommand::Agent(AgentCommand::UseInContext { - id: AgentId::from_external_id("testagent"), - namespace: "testns".into(), - }), - identity.clone(), - ) - .await - .unwrap(); - - insta::assert_json_snapshot!( + api.dispatch( + ApiCommand::Agent(AgentCommand::UseInContext { + id: AgentId::from_external_id("testagent"), + namespace: "testns".into(), + }), + identity.clone(), + ) + .await + .unwrap(); + + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Activity(ActivityCommand::Start { id: ActivityId::from_external_id("testactivity"), namespace: "testns".into(), @@ -439,11 +435,11 @@ async fn start_activity() { #[tokio::test] async fn contradict_attributes() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Agent(AgentCommand::Create { id: "testagent".into(), namespace: "testns".into(), @@ -482,35 +478,35 @@ async fn contradict_attributes() { } "###); - let res = api - .dispatch( - ApiCommand::Agent(AgentCommand::Create { - id: "testagent".into(), - namespace: "testns".into(), - attributes: Attributes::new( - Some(DomaintypeId::from_external_id("test")), - [Attribute { - typ: "test".to_owned(), - value: serde_json::Value::String("test2".to_owned()).into(), - }] - .into_iter() - .collect(), - ), - }), - identity, - ) - .await; - - insta::assert_snapshot!(res.err().unwrap().to_string(), @r###"Contradiction: Contradiction { attribute value change: test Attribute { typ: "test", value: SerdeWrapper(String("test2")) } Attribute { typ: "test", value: SerdeWrapper(String("test")) } }"###); + let res = api + .dispatch( + ApiCommand::Agent(AgentCommand::Create { + id: "testagent".into(), + namespace: "testns".into(), + attributes: Attributes::new( + Some(DomaintypeId::from_external_id("test")), + [Attribute { + typ: "test".to_owned(), + value: serde_json::Value::String("test2".to_owned()).into(), + }] + .into_iter() + .collect(), + ), + }), + identity, + ) + .await; + + insta::assert_snapshot!(res.err().unwrap().to_string(), @r###"Contradiction: Contradiction { attribute value change: test Attribute { typ: "test", value: SerdeWrapper(String("test2")) } Attribute { typ: "test", value: SerdeWrapper(String("test")) } }"###); } #[tokio::test] async fn contradict_start_time() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Agent(AgentCommand::Create { id: "testagent".into(), namespace: "testns".into(), @@ -549,17 +545,17 @@ async fn contradict_start_time() { } "###); - api.dispatch( - ApiCommand::Agent(AgentCommand::UseInContext { - id: AgentId::from_external_id("testagent"), - namespace: "testns".into(), - }), - identity.clone(), - ) - .await - .unwrap(); - - insta::assert_json_snapshot!( + api.dispatch( + ApiCommand::Agent(AgentCommand::UseInContext { + id: AgentId::from_external_id("testagent"), + namespace: "testns".into(), + }), + identity.clone(), + ) + .await + .unwrap(); + + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Activity(ActivityCommand::Start { id: ActivityId::from_external_id("testactivity"), namespace: "testns".into(), @@ -604,29 +600,29 @@ async fn contradict_start_time() { } "###); - // Should contradict - let res = api - .dispatch( - ApiCommand::Activity(ActivityCommand::Start { - id: ActivityId::from_external_id("testactivity"), - namespace: "testns".into(), - time: Some(Utc.with_ymd_and_hms(2018, 7, 8, 9, 10, 11).unwrap()), - agent: None, - }), - identity, - ) - .await; - - insta::assert_snapshot!(res.err().unwrap().to_string(), @"Contradiction: Contradiction { start date alteration: 2014-07-08T09:10:11+00:00 2018-07-08T09:10:11+00:00 }"); + // Should contradict + let res = api + .dispatch( + ApiCommand::Activity(ActivityCommand::Start { + id: ActivityId::from_external_id("testactivity"), + namespace: "testns".into(), + time: Some(Utc.with_ymd_and_hms(2018, 7, 8, 9, 10, 11).unwrap()), + agent: None, + }), + identity, + ) + .await; + + insta::assert_snapshot!(res.err().unwrap().to_string(), @"Contradiction: Contradiction { start date alteration: 2014-07-08T09:10:11+00:00 2018-07-08T09:10:11+00:00 }"); } #[tokio::test] async fn contradict_end_time() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Agent(AgentCommand::Create { id: "testagent".into(), namespace: "testns".into(), @@ -665,17 +661,17 @@ async fn contradict_end_time() { } "###); - api.dispatch( - ApiCommand::Agent(AgentCommand::UseInContext { - id: AgentId::from_external_id("testagent"), - namespace: "testns".into(), - }), - identity.clone(), - ) - .await - .unwrap(); - - insta::assert_json_snapshot!( + api.dispatch( + ApiCommand::Agent(AgentCommand::UseInContext { + id: AgentId::from_external_id("testagent"), + namespace: "testns".into(), + }), + identity.clone(), + ) + .await + .unwrap(); + + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Activity(ActivityCommand::End { id: ActivityId::from_external_id("testactivity"), namespace: "testns".into(), @@ -720,29 +716,29 @@ async fn contradict_end_time() { } "###); - // Should contradict - let res = api - .dispatch( - ApiCommand::Activity(ActivityCommand::End { - id: ActivityId::from_external_id("testactivity"), - namespace: "testns".into(), - time: Some(Utc.with_ymd_and_hms(2022, 7, 8, 9, 10, 11).unwrap()), - agent: None, - }), - identity, - ) - .await; - - insta::assert_snapshot!(res.err().unwrap().to_string(), @"Contradiction: Contradiction { end date alteration: 2018-07-08T09:10:11+00:00 2022-07-08T09:10:11+00:00 }"); + // Should contradict + let res = api + .dispatch( + ApiCommand::Activity(ActivityCommand::End { + id: ActivityId::from_external_id("testactivity"), + namespace: "testns".into(), + time: Some(Utc.with_ymd_and_hms(2022, 7, 8, 9, 10, 11).unwrap()), + agent: None, + }), + identity, + ) + .await; + + insta::assert_snapshot!(res.err().unwrap().to_string(), @"Contradiction: Contradiction { end date alteration: 2018-07-08T09:10:11+00:00 2022-07-08T09:10:11+00:00 }"); } #[tokio::test] async fn end_activity() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Agent(AgentCommand::Create { id: "testagent".into(), namespace: "testns".into(), @@ -781,17 +777,17 @@ async fn end_activity() { } "###); - api.dispatch( - ApiCommand::Agent(AgentCommand::UseInContext { - id: AgentId::from_external_id("testagent"), - namespace: "testns".into(), - }), - identity.clone(), - ) - .await - .unwrap(); - - insta::assert_json_snapshot!( + api.dispatch( + ApiCommand::Agent(AgentCommand::UseInContext { + id: AgentId::from_external_id("testagent"), + namespace: "testns".into(), + }), + identity.clone(), + ) + .await + .unwrap(); + + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Activity(ActivityCommand::Start { id: ActivityId::from_external_id("testactivity"), namespace: "testns".into(), @@ -836,7 +832,7 @@ async fn end_activity() { } "###); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Activity(ActivityCommand::End { id: ActivityId::from_external_id("testactivity"), @@ -886,11 +882,11 @@ async fn end_activity() { #[tokio::test] async fn activity_use() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Agent(AgentCommand::Create { id: "testagent".into(), namespace: "testns".into(), @@ -929,17 +925,17 @@ async fn activity_use() { } "###); - api.dispatch( - ApiCommand::Agent(AgentCommand::UseInContext { - id: AgentId::from_external_id("testagent"), - namespace: "testns".into(), - }), - identity.clone(), - ) - .await - .unwrap(); - - insta::assert_json_snapshot!( + api.dispatch( + ApiCommand::Agent(AgentCommand::UseInContext { + id: AgentId::from_external_id("testagent"), + namespace: "testns".into(), + }), + identity.clone(), + ) + .await + .unwrap(); + + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Activity(ActivityCommand::Create { id: "testactivity".into(), namespace: "testns".into(), @@ -978,7 +974,7 @@ async fn activity_use() { } "###); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Activity(ActivityCommand::Use { id: EntityId::from_external_id("testentity"), namespace: "testns".into(), @@ -1021,7 +1017,7 @@ async fn activity_use() { } "###); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Activity(ActivityCommand::End { id: ActivityId::from_external_id("testactivity"), namespace: "testns".into(), @@ -1077,11 +1073,11 @@ async fn activity_use() { #[tokio::test] async fn activity_generate() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Activity(ActivityCommand::Create { id: "testactivity".into(), namespace: "testns".into(), @@ -1120,7 +1116,7 @@ async fn activity_generate() { } "###); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Activity(ActivityCommand::Generate { id: EntityId::from_external_id("testentity"), namespace: "testns".into(), @@ -1150,11 +1146,11 @@ async fn activity_generate() { #[tokio::test] async fn derive_entity_abstract() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Entity(EntityCommand::Derive { id: EntityId::from_external_id("testgeneratedentity"), namespace: "testns".into(), @@ -1197,11 +1193,11 @@ async fn derive_entity_abstract() { #[tokio::test] async fn derive_entity_primary_source() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Entity(EntityCommand::Derive { id: EntityId::from_external_id("testgeneratedentity"), namespace: "testns".into(), @@ -1244,11 +1240,11 @@ async fn derive_entity_primary_source() { #[tokio::test] async fn derive_entity_revision() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Entity(EntityCommand::Derive { id: EntityId::from_external_id("testgeneratedentity"), namespace: "testns".into(), @@ -1291,11 +1287,11 @@ async fn derive_entity_revision() { #[tokio::test] async fn derive_entity_quotation() { - let mut api = test_api().await; + let mut api = test_api().await; - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - insta::assert_json_snapshot!( + insta::assert_json_snapshot!( api.dispatch(ApiCommand::Entity(EntityCommand::Derive { id: EntityId::from_external_id("testgeneratedentity"), namespace: "testns".into(), diff --git a/crates/chronicle-test-infrastructure/src/cli_test.rs b/crates/chronicle-test-infrastructure/src/cli_test.rs index c882cad3d..c7cd8c0ab 100644 --- a/crates/chronicle-test-infrastructure/src/cli_test.rs +++ b/crates/chronicle-test-infrastructure/src/cli_test.rs @@ -1,79 +1,79 @@ use api::commands::ApiCommand; use chronicle::{ - bootstrap::{CliModel, SubCommand}, - codegen::ChronicleDomainDef, - PrimitiveType, + bootstrap::{CliModel, SubCommand}, + codegen::ChronicleDomainDef, + PrimitiveType, }; use common::{ - identity::AuthId, - prov::{json_ld::ToJson, ActivityId, AgentId, ChronicleIri, EntityId, ProvModel}, + identity::AuthId, + prov::{json_ld::ToJson, ActivityId, AgentId, ChronicleIri, EntityId, ProvModel}, }; use crate::substitutes::test_api; fn get_api_cmd(command_line: &str) -> ApiCommand { - let cli = test_cli_model(); - let matches = cli.as_cmd().get_matches_from(command_line.split_whitespace()); - cli.matches(&matches).unwrap().unwrap() + let cli = test_cli_model(); + let matches = cli.as_cmd().get_matches_from(command_line.split_whitespace()); + cli.matches(&matches).unwrap().unwrap() } async fn parse_and_execute(command_line: &str, cli: CliModel) -> Box { - let mut api = test_api().await; + let mut api = test_api().await; - let matches = cli.as_cmd().get_matches_from(command_line.split_whitespace()); + let matches = cli.as_cmd().get_matches_from(command_line.split_whitespace()); - let cmd = cli.matches(&matches).unwrap().unwrap(); + let cmd = cli.matches(&matches).unwrap().unwrap(); - let identity = AuthId::chronicle(); + let identity = AuthId::chronicle(); - api.dispatch(cmd, identity).await.unwrap().unwrap().0 + api.dispatch(cmd, identity).await.unwrap().unwrap().0 } fn test_cli_model() -> CliModel { - CliModel::from( - ChronicleDomainDef::build("test") - .with_attribute_type("testString", None, PrimitiveType::String) - .unwrap() - .with_attribute_type("testBool", None, PrimitiveType::Bool) - .unwrap() - .with_attribute_type("testInt", None, PrimitiveType::Int) - .unwrap() - .with_attribute_type("testJSON", None, PrimitiveType::JSON) - .unwrap() - .with_activity("testActivity", None, |b| { - b.with_attribute("testString") - .unwrap() - .with_attribute("testBool") - .unwrap() - .with_attribute("testInt") - }) - .unwrap() - .with_agent("testAgent", None, |b| { - b.with_attribute("testString") - .unwrap() - .with_attribute("testBool") - .unwrap() - .with_attribute("testInt") - }) - .unwrap() - .with_entity("testEntity", None, |b| { - b.with_attribute("testString") - .unwrap() - .with_attribute("testBool") - .unwrap() - .with_attribute("testInt") - }) - .unwrap() - .build(), - ) + CliModel::from( + ChronicleDomainDef::build("test") + .with_attribute_type("testString", None, PrimitiveType::String) + .unwrap() + .with_attribute_type("testBool", None, PrimitiveType::Bool) + .unwrap() + .with_attribute_type("testInt", None, PrimitiveType::Int) + .unwrap() + .with_attribute_type("testJSON", None, PrimitiveType::JSON) + .unwrap() + .with_activity("testActivity", None, |b| { + b.with_attribute("testString") + .unwrap() + .with_attribute("testBool") + .unwrap() + .with_attribute("testInt") + }) + .unwrap() + .with_agent("testAgent", None, |b| { + b.with_attribute("testString") + .unwrap() + .with_attribute("testBool") + .unwrap() + .with_attribute("testInt") + }) + .unwrap() + .with_entity("testEntity", None, |b| { + b.with_attribute("testString") + .unwrap() + .with_attribute("testBool") + .unwrap() + .with_attribute("testInt") + }) + .unwrap() + .build(), + ) } #[tokio::test] async fn agent_define() { - let command_line = r#"chronicle test-agent-agent define test_agent --test-bool-attr false --test-string-attr "test" --test-int-attr 23 --namespace testns "#; + let command_line = r#"chronicle test-agent-agent define test_agent --test-bool-attr false --test-string-attr "test" --test-int-attr 23 --namespace testns "#; - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &parse_and_execute(command_line, test_cli_model()).await.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -97,12 +97,12 @@ async fn agent_define() { #[tokio::test] async fn agent_define_id() { - let id = ChronicleIri::from(common::prov::AgentId::from_external_id("test_agent")); - let command_line = format!( - r#"chronicle test-agent-agent define --test-bool-attr false --test-string-attr "test" --test-int-attr 23 --namespace testns --id {id} "# - ); + let id = ChronicleIri::from(common::prov::AgentId::from_external_id("test_agent")); + let command_line = format!( + r#"chronicle test-agent-agent define --test-bool-attr false --test-string-attr "test" --test-int-attr 23 --namespace testns --id {id} "# + ); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &parse_and_execute(&command_line, test_cli_model()).await.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -126,14 +126,14 @@ async fn agent_define_id() { #[tokio::test] async fn agent_use() { - let mut api = test_api().await; + let mut api = test_api().await; - // note, if you don't supply all three types of attribute this won't run - let command_line = r#"chronicle test-agent-agent define testagent --namespace testns --test-string-attr "test" --test-bool-attr true --test-int-attr 23 "#; + // note, if you don't supply all three types of attribute this won't run + let command_line = r#"chronicle test-agent-agent define testagent --namespace testns --test-string-attr "test" --test-bool-attr true --test-int-attr 23 "#; - let cmd = get_api_cmd(command_line); + let cmd = get_api_cmd(command_line); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &api.dispatch(cmd, AuthId::chronicle()).await.unwrap().unwrap().0.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -154,20 +154,20 @@ async fn agent_use() { } "###); - let id = AgentId::from_external_id("testagent"); + let id = AgentId::from_external_id("testagent"); - let command_line = format!(r#"chronicle test-agent-agent use --namespace testns {id} "#); - let cmd = get_api_cmd(&command_line); + let command_line = format!(r#"chronicle test-agent-agent use --namespace testns {id} "#); + let cmd = get_api_cmd(&command_line); - api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); + api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); - let id = ActivityId::from_external_id("testactivity"); - let command_line = format!( - r#"chronicle test-activity-activity start {id} --namespace testns --time 2014-07-08T09:10:11Z "# - ); - let cmd = get_api_cmd(&command_line); + let id = ActivityId::from_external_id("testactivity"); + let command_line = format!( + r#"chronicle test-activity-activity start {id} --namespace testns --time 2014-07-08T09:10:11Z "# + ); + let cmd = get_api_cmd(&command_line); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &api.dispatch(cmd, AuthId::chronicle()).await.unwrap().unwrap().0.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -204,10 +204,10 @@ async fn agent_use() { #[tokio::test] async fn entity_define() { - let command_line = r#"chronicle test-entity-entity define test_entity --test-bool-attr false --test-string-attr "test" --test-int-attr 23 --namespace testns "#; - let _delta = parse_and_execute(command_line, test_cli_model()); + let command_line = r#"chronicle test-entity-entity define test_entity --test-bool-attr false --test-string-attr "test" --test-int-attr 23 --namespace testns "#; + let _delta = parse_and_execute(command_line, test_cli_model()); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &parse_and_execute(command_line, test_cli_model()).await.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -231,12 +231,12 @@ async fn entity_define() { #[tokio::test] async fn entity_define_id() { - let id = ChronicleIri::from(common::prov::EntityId::from_external_id("test_entity")); - let command_line = format!( - r#"chronicle test-entity-entity define --test-bool-attr false --test-string-attr "test" --test-int-attr 23 --namespace testns --id {id} "# - ); + let id = ChronicleIri::from(common::prov::EntityId::from_external_id("test_entity")); + let command_line = format!( + r#"chronicle test-entity-entity define --test-bool-attr false --test-string-attr "test" --test-int-attr 23 --namespace testns --id {id} "# + ); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &parse_and_execute(&command_line, test_cli_model()).await.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -260,17 +260,17 @@ async fn entity_define_id() { #[tokio::test] async fn entity_derive_abstract() { - let mut api = test_api().await; + let mut api = test_api().await; - let generated_entity_id = EntityId::from_external_id("testgeneratedentity"); - let used_entity_id = EntityId::from_external_id("testusedentity"); + let generated_entity_id = EntityId::from_external_id("testgeneratedentity"); + let used_entity_id = EntityId::from_external_id("testusedentity"); - let command_line = format!( - r#"chronicle test-entity-entity derive {generated_entity_id} {used_entity_id} --namespace testns "# - ); - let cmd = get_api_cmd(&command_line); + let command_line = format!( + r#"chronicle test-entity-entity derive {generated_entity_id} {used_entity_id} --namespace testns "# + ); + let cmd = get_api_cmd(&command_line); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &api.dispatch(cmd, AuthId::chronicle()).await.unwrap().unwrap().0.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -301,17 +301,17 @@ async fn entity_derive_abstract() { #[tokio::test] async fn entity_derive_primary_source() { - let mut api = test_api().await; + let mut api = test_api().await; - let generated_entity_id = EntityId::from_external_id("testgeneratedentity"); - let used_entity_id = EntityId::from_external_id("testusedentity"); + let generated_entity_id = EntityId::from_external_id("testgeneratedentity"); + let used_entity_id = EntityId::from_external_id("testusedentity"); - let command_line = format!( - r#"chronicle test-entity-entity derive {generated_entity_id} {used_entity_id} --namespace testns --subtype primary-source "# - ); - let cmd = get_api_cmd(&command_line); + let command_line = format!( + r#"chronicle test-entity-entity derive {generated_entity_id} {used_entity_id} --namespace testns --subtype primary-source "# + ); + let cmd = get_api_cmd(&command_line); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &api.dispatch(cmd, AuthId::chronicle()).await.unwrap().unwrap().0.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -342,17 +342,17 @@ async fn entity_derive_primary_source() { #[tokio::test] async fn entity_derive_revision() { - let mut api = test_api().await; + let mut api = test_api().await; - let generated_entity_id = EntityId::from_external_id("testgeneratedentity"); - let used_entity_id = EntityId::from_external_id("testusedentity"); + let generated_entity_id = EntityId::from_external_id("testgeneratedentity"); + let used_entity_id = EntityId::from_external_id("testusedentity"); - let command_line = format!( - r#"chronicle test-entity-entity derive {generated_entity_id} {used_entity_id} --namespace testns --subtype revision "# - ); - let cmd = get_api_cmd(&command_line); + let command_line = format!( + r#"chronicle test-entity-entity derive {generated_entity_id} {used_entity_id} --namespace testns --subtype revision "# + ); + let cmd = get_api_cmd(&command_line); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &api.dispatch(cmd, AuthId::chronicle()).await.unwrap().unwrap().0.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -383,17 +383,17 @@ async fn entity_derive_revision() { #[tokio::test] async fn entity_derive_quotation() { - let mut api = test_api().await; + let mut api = test_api().await; - let generated_entity_id = EntityId::from_external_id("testgeneratedentity"); - let used_entity_id = EntityId::from_external_id("testusedentity"); + let generated_entity_id = EntityId::from_external_id("testgeneratedentity"); + let used_entity_id = EntityId::from_external_id("testusedentity"); - let command_line = format!( - r#"chronicle test-entity-entity derive {generated_entity_id} {used_entity_id} --namespace testns --subtype quotation "# - ); - let cmd = get_api_cmd(&command_line); + let command_line = format!( + r#"chronicle test-entity-entity derive {generated_entity_id} {used_entity_id} --namespace testns --subtype quotation "# + ); + let cmd = get_api_cmd(&command_line); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &api.dispatch(cmd, AuthId::chronicle()).await.unwrap().unwrap().0.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -424,9 +424,9 @@ async fn entity_derive_quotation() { #[tokio::test] async fn activity_define() { - let command_line = r#"chronicle test-activity-activity define test_activity --test-bool-attr false --test-string-attr "test" --test-int-attr 23 --namespace testns "#; + let command_line = r#"chronicle test-activity-activity define test_activity --test-bool-attr false --test-string-attr "test" --test-int-attr 23 --namespace testns "#; - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &parse_and_execute(command_line, test_cli_model()).await.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -450,12 +450,12 @@ async fn activity_define() { #[tokio::test] async fn activity_define_id() { - let id = ChronicleIri::from(common::prov::ActivityId::from_external_id("test_activity")); - let command_line = format!( - r#"chronicle test-activity-activity define --test-bool-attr false --test-string-attr "test" --test-int-attr 23 --namespace testns --id {id} "# - ); + let id = ChronicleIri::from(common::prov::ActivityId::from_external_id("test_activity")); + let command_line = format!( + r#"chronicle test-activity-activity define --test-bool-attr false --test-string-attr "test" --test-int-attr 23 --namespace testns --id {id} "# + ); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &parse_and_execute(&command_line, test_cli_model()).await.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -479,25 +479,25 @@ async fn activity_define_id() { #[tokio::test] async fn activity_start() { - let mut api = test_api().await; + let mut api = test_api().await; - let command_line = r#"chronicle test-agent-agent define testagent --namespace testns --test-string-attr "test" --test-bool-attr true --test-int-attr 40 "#; - let cmd = get_api_cmd(command_line); + let command_line = r#"chronicle test-agent-agent define testagent --namespace testns --test-string-attr "test" --test-bool-attr true --test-int-attr 40 "#; + let cmd = get_api_cmd(command_line); - api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); + api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); - let id = ChronicleIri::from(AgentId::from_external_id("testagent")); - let command_line = format!(r#"chronicle test-agent-agent use --namespace testns {id} "#); - let cmd = get_api_cmd(&command_line); - api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); + let id = ChronicleIri::from(AgentId::from_external_id("testagent")); + let command_line = format!(r#"chronicle test-agent-agent use --namespace testns {id} "#); + let cmd = get_api_cmd(&command_line); + api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); - let id = ChronicleIri::from(ActivityId::from_external_id("testactivity")); - let command_line = format!( - r#"chronicle test-activity-activity start {id} --namespace testns --time 2014-07-08T09:10:11Z "# - ); - let cmd = get_api_cmd(&command_line); + let id = ChronicleIri::from(ActivityId::from_external_id("testactivity")); + let command_line = format!( + r#"chronicle test-activity-activity start {id} --namespace testns --time 2014-07-08T09:10:11Z "# + ); + let cmd = get_api_cmd(&command_line); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &api.dispatch(cmd, AuthId::chronicle()).await.unwrap().unwrap().0.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -534,33 +534,33 @@ async fn activity_start() { #[tokio::test] async fn activity_end() { - let mut api = test_api().await; + let mut api = test_api().await; - let command_line = r#"chronicle test-agent-agent define testagent --namespace testns --test-string-attr "test" --test-bool-attr true --test-int-attr 40 "#; - let cmd = get_api_cmd(command_line); + let command_line = r#"chronicle test-agent-agent define testagent --namespace testns --test-string-attr "test" --test-bool-attr true --test-int-attr 40 "#; + let cmd = get_api_cmd(command_line); - api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); + api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); - let id = ChronicleIri::from(AgentId::from_external_id("testagent")); - let command_line = format!(r#"chronicle test-agent-agent use --namespace testns {id} "#); - let cmd = get_api_cmd(&command_line); - api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); + let id = ChronicleIri::from(AgentId::from_external_id("testagent")); + let command_line = format!(r#"chronicle test-agent-agent use --namespace testns {id} "#); + let cmd = get_api_cmd(&command_line); + api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); - let id = ChronicleIri::from(ActivityId::from_external_id("testactivity")); - let command_line = format!( - r#"chronicle test-activity-activity start {id} --namespace testns --time 2014-07-08T09:10:11Z "# - ); - let cmd = get_api_cmd(&command_line); - api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); + let id = ChronicleIri::from(ActivityId::from_external_id("testactivity")); + let command_line = format!( + r#"chronicle test-activity-activity start {id} --namespace testns --time 2014-07-08T09:10:11Z "# + ); + let cmd = get_api_cmd(&command_line); + api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); - // Should end the last opened activity - let id = ActivityId::from_external_id("testactivity"); - let command_line = format!( - r#"chronicle test-activity-activity end --namespace testns --time 2014-08-09T09:10:12Z {id} "# - ); - let cmd = get_api_cmd(&command_line); + // Should end the last opened activity + let id = ActivityId::from_external_id("testactivity"); + let command_line = format!( + r#"chronicle test-activity-activity end --namespace testns --time 2014-08-09T09:10:12Z {id} "# + ); + let cmd = get_api_cmd(&command_line); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &api.dispatch(cmd, AuthId::chronicle()).await.unwrap().unwrap().0.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -598,21 +598,21 @@ async fn activity_end() { #[tokio::test] async fn activity_generate() { - let mut api = test_api().await; + let mut api = test_api().await; - let command_line = r#"chronicle test-activity-activity define testactivity --namespace testns --test-string-attr "test" --test-bool-attr true --test-int-attr 40 "#; - let cmd = get_api_cmd(command_line); + let command_line = r#"chronicle test-activity-activity define testactivity --namespace testns --test-string-attr "test" --test-bool-attr true --test-int-attr 40 "#; + let cmd = get_api_cmd(command_line); - api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); + api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); - let activity_id = ActivityId::from_external_id("testactivity"); - let entity_id = EntityId::from_external_id("testentity"); - let command_line = format!( - r#"chronicle test-activity-activity generate --namespace testns {entity_id} {activity_id} "# - ); - let cmd = get_api_cmd(&command_line); + let activity_id = ActivityId::from_external_id("testactivity"); + let entity_id = EntityId::from_external_id("testentity"); + let command_line = format!( + r#"chronicle test-activity-activity generate --namespace testns {entity_id} {activity_id} "# + ); + let cmd = get_api_cmd(&command_line); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &api.dispatch(cmd, AuthId::chronicle()).await.unwrap().unwrap().0.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" @@ -632,31 +632,31 @@ async fn activity_generate() { #[tokio::test] async fn activity_use() { - let mut api = test_api().await; + let mut api = test_api().await; - let command_line = r#"chronicle test-agent-agent define testagent --namespace testns --test-string-attr "test" --test-bool-attr true --test-int-attr 40 "#; - let cmd = get_api_cmd(command_line); + let command_line = r#"chronicle test-agent-agent define testagent --namespace testns --test-string-attr "test" --test-bool-attr true --test-int-attr 40 "#; + let cmd = get_api_cmd(command_line); - api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); + api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); - let id = ChronicleIri::from(AgentId::from_external_id("testagent")); - let command_line = format!(r#"chronicle test-agent-agent use --namespace testns {id} "#); - let cmd = get_api_cmd(&command_line); - api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); + let id = ChronicleIri::from(AgentId::from_external_id("testagent")); + let command_line = format!(r#"chronicle test-agent-agent use --namespace testns {id} "#); + let cmd = get_api_cmd(&command_line); + api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); - let command_line = r#"chronicle test-activity-activity define testactivity --namespace testns --test-string-attr "test" --test-bool-attr true --test-int-attr 40 "#; - let cmd = get_api_cmd(command_line); - api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); + let command_line = r#"chronicle test-activity-activity define testactivity --namespace testns --test-string-attr "test" --test-bool-attr true --test-int-attr 40 "#; + let cmd = get_api_cmd(command_line); + api.dispatch(cmd, AuthId::chronicle()).await.unwrap(); - let activity_id = ActivityId::from_external_id("testactivity"); - let entity_id = EntityId::from_external_id("testentity"); - let command_line = format!( - r#"chronicle test-activity-activity use --namespace testns {entity_id} {activity_id} "# - ); + let activity_id = ActivityId::from_external_id("testactivity"); + let entity_id = EntityId::from_external_id("testentity"); + let command_line = format!( + r#"chronicle test-activity-activity use --namespace testns {entity_id} {activity_id} "# + ); - let cmd = get_api_cmd(&command_line); + let cmd = get_api_cmd(&command_line); - insta::assert_snapshot!( + insta::assert_snapshot!( serde_json::to_string_pretty( &api.dispatch(cmd, AuthId::chronicle()).await.unwrap().unwrap().0.to_json().compact_stable_order().await.unwrap() ).unwrap() , @r###" diff --git a/crates/chronicle-test-infrastructure/src/substitutes/mockchain.rs b/crates/chronicle-test-infrastructure/src/substitutes/mockchain.rs index 604ae9914..1032ea03d 100644 --- a/crates/chronicle-test-infrastructure/src/substitutes/mockchain.rs +++ b/crates/chronicle-test-infrastructure/src/substitutes/mockchain.rs @@ -1,8 +1,8 @@ use frame_support::traits::{ConstU16, ConstU64}; use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, }; type Block = frame_system::mocking::MockBlock; @@ -17,38 +17,38 @@ frame_support::construct_runtime!( ); impl frame_system::Config for Test { - type AccountData = (); - type AccountId = u64; - type BaseCallFilter = frame_support::traits::Everything; - type Block = Block; - type BlockHashCount = ConstU64<250>; - type BlockLength = (); - type BlockWeights = (); - type DbWeight = (); - type Hash = H256; - type Hashing = BlakeTwo256; - type Lookup = IdentityLookup; - type MaxConsumers = frame_support::traits::ConstU32<16>; - type Nonce = u64; - type OnKilledAccount = (); - type OnNewAccount = (); - type OnSetCode = (); - type PalletInfo = PalletInfo; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type RuntimeOrigin = RuntimeOrigin; - type SS58Prefix = ConstU16<42>; - type SystemWeightInfo = (); - type Version = (); + type AccountData = (); + type AccountId = u64; + type BaseCallFilter = frame_support::traits::Everything; + type Block = Block; + type BlockHashCount = ConstU64<250>; + type BlockLength = (); + type BlockWeights = (); + type DbWeight = (); + type Hash = H256; + type Hashing = BlakeTwo256; + type Lookup = IdentityLookup; + type MaxConsumers = frame_support::traits::ConstU32<16>; + type Nonce = u64; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = (); + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = ConstU16<42>; + type SystemWeightInfo = (); + type Version = (); } impl pallet_chronicle::Config for Test { - type OperationSubmission = protocol_substrate_chronicle::common::ledger::OperationSubmission; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); + type OperationSubmission = protocol_substrate_chronicle::common::ledger::OperationSubmission; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } // Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - frame_system::GenesisConfig::::default().build_storage().unwrap().into() + frame_system::GenesisConfig::::default().build_storage().unwrap().into() } diff --git a/crates/chronicle-test-infrastructure/src/substitutes/mod.rs b/crates/chronicle-test-infrastructure/src/substitutes/mod.rs index b002e0c13..2fc550c87 100644 --- a/crates/chronicle-test-infrastructure/src/substitutes/mod.rs +++ b/crates/chronicle-test-infrastructure/src/substitutes/mod.rs @@ -1,171 +1,173 @@ mod mockchain; mod stubstrate; + use crate::substitutes::stubstrate::Stubstrate; use api::{ - commands::{ApiCommand, ApiResponse}, - Api, ApiDispatch, ApiError, UuidGen, + ApiError, commands::{ApiCommand, ApiResponse}, }; use common::{ - identity::AuthId, - prov::{ChronicleTransactionId, ProvModel}, + identity::AuthId, + prov::{ChronicleTransactionId, ProvModel}, }; use pallet_chronicle::NamespaceId; use uuid::Uuid; use chronicle_signing::{ - chronicle_secret_names, ChronicleSecretsOptions, ChronicleSigning, BATCHER_NAMESPACE, - CHRONICLE_NAMESPACE, + BATCHER_NAMESPACE, CHRONICLE_NAMESPACE, chronicle_secret_names, ChronicleSecretsOptions, + ChronicleSigning, }; use diesel::{ - r2d2::{ConnectionManager, Pool}, - Connection, PgConnection, + Connection, + PgConnection, r2d2::{ConnectionManager, Pool}, }; -use testcontainers::{images::postgres::Postgres, Container}; +use testcontainers::{Container, images::postgres::Postgres}; use lazy_static::lazy_static; use testcontainers::clients; +use api::{Api, UuidGen}; +use api::ApiDispatch; lazy_static! { static ref CLIENT: clients::Cli = clients::Cli::default(); } pub struct TemporaryDatabase<'a> { - db_uris: Vec, - container: Container<'a, Postgres>, + db_uris: Vec, + container: Container<'a, Postgres>, } impl<'a> Drop for TemporaryDatabase<'a> { - #[tracing::instrument(skip(self))] - fn drop(&mut self) { - self.container.stop(); - } + #[tracing::instrument(skip(self))] + fn drop(&mut self) { + self.container.stop(); + } } impl<'a> TemporaryDatabase<'a> { - pub fn connection_pool(&self) -> Result>, r2d2::Error> { - let db_uri = self - .db_uris - .iter() - .find(|db_uri| PgConnection::establish(db_uri).is_ok()) - .expect("cannot establish connection"); - Pool::builder().build(ConnectionManager::::new(db_uri)) - } + pub fn connection_pool(&self) -> Result>, r2d2::Error> { + let db_uri = self + .db_uris + .iter() + .find(|db_uri| PgConnection::establish(db_uri).is_ok()) + .expect("cannot establish connection"); + Pool::builder().build(ConnectionManager::::new(db_uri)) + } } impl<'a> Default for TemporaryDatabase<'a> { - fn default() -> Self { - let container = CLIENT.run(Postgres::default()); - const PORT: u16 = 5432; - Self { - db_uris: vec![ - format!("postgresql://postgres@127.0.0.1:{}/", container.get_host_port_ipv4(PORT)), - format!("postgresql://postgres@{}:{}/", container.get_bridge_ip_address(), PORT), - ], - container, - } - } + fn default() -> Self { + let container = CLIENT.run(Postgres::default()); + const PORT: u16 = 5432; + Self { + db_uris: vec![ + format!("postgresql://postgres@127.0.0.1:{}/", container.get_host_port_ipv4(PORT)), + format!("postgresql://postgres@{}:{}/", container.get_bridge_ip_address(), PORT), + ], + container, + } + } } pub struct TestDispatch<'a> { - api: ApiDispatch, - db: TemporaryDatabase<'a>, - _substrate: Stubstrate, + api: ApiDispatch, + db: TemporaryDatabase<'a>, + _substrate: Stubstrate, } impl<'a> TestDispatch<'a> { - /// Returns a reference to the ApiDispatch. - pub fn api_dispatch(&self) -> &ApiDispatch { - &self.api - } - - /// Returns a reference to the TemporaryDatabase. - pub fn temporary_database(&self) -> &TemporaryDatabase<'a> { - &self.db - } + /// Returns a reference to the ApiDispatch. + pub fn api_dispatch(&self) -> &ApiDispatch { + &self.api + } + + /// Returns a reference to the TemporaryDatabase. + pub fn temporary_database(&self) -> &TemporaryDatabase<'a> { + &self.db + } } impl<'a> TestDispatch<'a> { - pub async fn dispatch( - &mut self, - command: ApiCommand, - identity: AuthId, - ) -> Result, ChronicleTransactionId)>, ApiError> { - // We can sort of get final on chain state here by using a map of subject to model - match self.api.dispatch(command, identity).await? { - ApiResponse::Submission { .. } | ApiResponse::ImportSubmitted { .. } => { - // Recv until we get a commit notification - loop { - let commit = self.api.notify_commit.subscribe().recv().await.unwrap(); - match commit { - common::ledger::SubmissionStage::Submitted(Ok(_)) => continue, - common::ledger::SubmissionStage::Committed(commit, _id) => - return Ok(Some((commit.delta, commit.tx_id))), - common::ledger::SubmissionStage::Submitted(Err(e)) => panic!("{e:?}"), - common::ledger::SubmissionStage::NotCommitted((_, tx, _id)) => { - panic!("{tx:?}") - }, - } - } - }, - ApiResponse::AlreadyRecorded { subject: _, prov } => - Ok(Some((prov, ChronicleTransactionId::default()))), - _ => Ok(None), - } - } + pub async fn dispatch( + &mut self, + command: ApiCommand, + identity: AuthId, + ) -> Result, ChronicleTransactionId)>, ApiError> { + // We can sort of get final on chain state here by using a map of subject to model + match self.api.dispatch(command, identity).await? { + ApiResponse::Submission { .. } | ApiResponse::ImportSubmitted { .. } => { + // Recv until we get a commit notification + loop { + let commit = self.api.notify_commit.subscribe().recv().await.unwrap(); + match commit { + common::ledger::SubmissionStage::Submitted(Ok(_)) => continue, + common::ledger::SubmissionStage::Committed(commit, _id) => + return Ok(Some((commit.delta, commit.tx_id))), + common::ledger::SubmissionStage::Submitted(Err(e)) => panic!("{e:?}"), + common::ledger::SubmissionStage::NotCommitted((_, tx, _id)) => { + panic!("{tx:?}") + } + } + } + } + ApiResponse::AlreadyRecorded { subject: _, prov } => + Ok(Some((prov, ChronicleTransactionId::default()))), + _ => Ok(None), + } + } } #[derive(Debug, Clone)] struct SameUuid; impl UuidGen for SameUuid { - fn uuid() -> Uuid { - Uuid::parse_str("5a0ab5b8-eeb7-4812-9fe3-6dd69bd20cea").unwrap() - } + fn uuid() -> Uuid { + Uuid::parse_str("5a0ab5b8-eeb7-4812-9fe3-6dd69bd20cea").unwrap() + } } pub async fn embed_substrate() -> Stubstrate { - stubstrate::Stubstrate::new() + stubstrate::Stubstrate::new() } pub async fn test_api<'a>() -> TestDispatch<'a> { - chronicle_telemetry::telemetry(None, chronicle_telemetry::ConsoleLogging::Pretty); - - let secrets = ChronicleSigning::new( - chronicle_secret_names(), - vec![ - (CHRONICLE_NAMESPACE.to_string(), ChronicleSecretsOptions::generate_in_memory()), - (BATCHER_NAMESPACE.to_string(), ChronicleSecretsOptions::generate_in_memory()), - ], - ) - .await - .unwrap(); - - let embed_substrate = embed_substrate().await; - let database = TemporaryDatabase::default(); - let pool = database.connection_pool().unwrap(); - - let liveness_check_interval = None; - - let dispatch = Api::new( - pool, - embed_substrate.clone(), - SameUuid, - secrets, - vec![NamespaceId::from_external_id( - "testns", - Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(), - )], - None, - liveness_check_interval, - ) - .await - .unwrap(); - - TestDispatch { - api: dispatch, - db: database, // share the lifetime - _substrate: embed_substrate, - } + chronicle_telemetry::telemetry(false, chronicle_telemetry::ConsoleLogging::Pretty); + + let secrets = ChronicleSigning::new( + chronicle_secret_names(), + vec![ + (CHRONICLE_NAMESPACE.to_string(), ChronicleSecretsOptions::generate_in_memory()), + (BATCHER_NAMESPACE.to_string(), ChronicleSecretsOptions::generate_in_memory()), + ], + ) + .await + .unwrap(); + + let embed_substrate = embed_substrate().await; + let database = TemporaryDatabase::default(); + let pool = database.connection_pool().unwrap(); + + let liveness_check_interval = None; + + let dispatch = Api::new( + pool, + embed_substrate.clone(), + SameUuid, + secrets, + vec![NamespaceId::from_external_id( + "testns", + Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(), + )], + None, + liveness_check_interval, + ) + .await + .unwrap(); + + TestDispatch { + api: dispatch, + db: database, // share the lifetime + _substrate: embed_substrate, + } } diff --git a/crates/chronicle-test-infrastructure/src/substitutes/stubstrate.rs b/crates/chronicle-test-infrastructure/src/substitutes/stubstrate.rs index ceb69f236..a63d1bbe9 100644 --- a/crates/chronicle-test-infrastructure/src/substitutes/stubstrate.rs +++ b/crates/chronicle-test-infrastructure/src/substitutes/stubstrate.rs @@ -3,151 +3,151 @@ use pallet_chronicle::{chronicle_core::OperationSubmission, ChronicleTransaction use super::mockchain::{new_test_ext, ChronicleModule, RuntimeEvent, RuntimeOrigin, System, Test}; use protocol_abstract::{ - BlockId, FromBlock, LedgerEvent, LedgerEventContext, LedgerReader, LedgerWriter, Position, Span, + BlockId, FromBlock, LedgerEvent, LedgerEventContext, LedgerReader, LedgerWriter, Position, Span, }; use protocol_substrate::{PolkadotConfig, SubstrateStateReader, SubxtClientError}; use protocol_substrate_chronicle::{ - protocol::WriteConsistency, ChronicleEvent, ChronicleEventCodec, ChronicleTransaction, + protocol::WriteConsistency, ChronicleEvent, ChronicleEventCodec, ChronicleTransaction, }; use std::sync::{Arc, Mutex}; use subxt::metadata::{DecodeWithMetadata, EncodeWithMetadata}; #[derive(Clone)] pub struct Stubstrate { - rt: Arc>, - tx: tokio::sync::broadcast::Sender, - events: Arc>>, + rt: Arc>, + tx: tokio::sync::broadcast::Sender, + events: Arc>>, } impl Default for Stubstrate { - fn default() -> Self { - Self::new() - } + fn default() -> Self { + Self::new() + } } impl Stubstrate { - pub fn new() -> Self { - let (tx, _rx) = tokio::sync::broadcast::channel(100); - Self { rt: Arc::new(Mutex::new(new_test_ext())), tx, events: Arc::new(Mutex::new(vec![])) } - } - - #[tracing::instrument(skip(self))] - pub fn readable_events(&self) -> Vec { - self.events.lock().unwrap().clone() - } - - pub fn stored_prov(&self) -> Vec { - self.rt.lock().unwrap().execute_with(|| { - pallet_chronicle::Provenance::::iter_values() - .map(|k| k.try_into().unwrap()) - .collect() - }) - } + pub fn new() -> Self { + let (tx, _rx) = tokio::sync::broadcast::channel(100); + Self { rt: Arc::new(Mutex::new(new_test_ext())), tx, events: Arc::new(Mutex::new(vec![])) } + } + + #[tracing::instrument(skip(self))] + pub fn readable_events(&self) -> Vec { + self.events.lock().unwrap().clone() + } + + pub fn stored_prov(&self) -> Vec { + self.rt.lock().unwrap().execute_with(|| { + pallet_chronicle::Provenance::::iter_values() + .map(|k| k.try_into().unwrap()) + .collect() + }) + } } #[async_trait::async_trait] impl LedgerReader for Stubstrate { - type Error = SubxtClientError; - type Event = ChronicleEvent; - type EventCodec = ChronicleEventCodec; - - async fn block_height(&self) -> Result<(Position, BlockId), Self::Error> { - unimplemented!(); - } - - /// Subscribe to state updates from this ledger, starting at `offset`, and - /// ending the stream after `number_of_blocks` blocks have been processed. - async fn state_updates( - &self, - // The block to start from - from_block: FromBlock, - // The number of blocks to process before ending the stream - _number_of_blocks: Option, - ) -> Result>, Self::Error> { - tracing::debug!("Starting state updates stream from block {:?}", from_block); - let rx = self.tx.subscribe(); - let stream = tokio_stream::wrappers::BroadcastStream::new(rx) - .map(|event| { - let event = event.unwrap(); - let correlation_id = event.correlation_id().into(); - (event, correlation_id, BlockId::Unknown, Position::from(0), Span::NotTraced) - }) - .boxed(); - Ok(stream) - } + type Error = SubxtClientError; + type Event = ChronicleEvent; + type EventCodec = ChronicleEventCodec; + + async fn block_height(&self) -> Result<(Position, BlockId), Self::Error> { + unimplemented!(); + } + + /// Subscribe to state updates from this ledger, starting at `offset`, and + /// ending the stream after `number_of_blocks` blocks have been processed. + async fn state_updates( + &self, + // The block to start from + from_block: FromBlock, + // The number of blocks to process before ending the stream + _number_of_blocks: Option, + ) -> Result>, Self::Error> { + tracing::debug!("Starting state updates stream from block {:?}", from_block); + let rx = self.tx.subscribe(); + let stream = tokio_stream::wrappers::BroadcastStream::new(rx) + .map(|event| { + let event = event.unwrap(); + let correlation_id = event.correlation_id().into(); + (event, correlation_id, BlockId::Unknown, Position::from(0), Span::NotTraced) + }) + .boxed(); + Ok(stream) + } } #[async_trait::async_trait] impl LedgerWriter for Stubstrate { - type Error = SubxtClientError; - type Submittable = OperationSubmission; - type Transaction = ChronicleTransaction; - - // Minimally process the transaction offline to get a transaction id and submittable type - async fn pre_submit( - &self, - tx: Self::Transaction, - ) -> Result<(Self::Submittable, ChronicleTransactionId), Self::Error> { - Ok(( - OperationSubmission { - correlation_id: tx.correlation_id.into_bytes(), - identity: tx.identity, - items: tx.operations, - }, - tx.correlation_id.into(), - )) - } - - // Submit is used to submit a transaction to the ledger - async fn do_submit( - &self, - _consistency: WriteConsistency, - submittable: Self::Submittable, - ) -> Result { - let correlation_id = submittable.correlation_id; - self.rt.lock().unwrap().execute_with(|| { - System::set_block_number(1); - ChronicleModule::apply(RuntimeOrigin::signed(1), submittable).unwrap(); - - let ev = System::events().last().unwrap().event.clone(); - - let opa_event = match ev { - RuntimeEvent::ChronicleModule(event) => match event { - Event::::Applied(diff, identity, correlation_id) => - Some(ChronicleEvent::Committed { diff, identity, correlation_id }), - Event::::Contradiction(contradiction, identity, correlation_id) => - Some(ChronicleEvent::Contradicted { - contradiction, - identity, - correlation_id, - }), - _ => None, - }, - _ => None, - }; - - if let Some(event) = opa_event { - self.events.lock().unwrap().push(event.clone()); - self.tx.send(event).unwrap(); - } else { - tracing::warn!("Received an event that is not an OpaEvent"); - } - }); - - Ok(correlation_id.into()) - } + type Error = SubxtClientError; + type Submittable = OperationSubmission; + type Transaction = ChronicleTransaction; + + // Minimally process the transaction offline to get a transaction id and submittable type + async fn pre_submit( + &self, + tx: Self::Transaction, + ) -> Result<(Self::Submittable, ChronicleTransactionId), Self::Error> { + Ok(( + OperationSubmission { + correlation_id: tx.correlation_id.into_bytes(), + identity: tx.identity, + items: tx.operations, + }, + tx.correlation_id.into(), + )) + } + + // Submit is used to submit a transaction to the ledger + async fn do_submit( + &self, + _consistency: WriteConsistency, + submittable: Self::Submittable, + ) -> Result { + let correlation_id = submittable.correlation_id; + self.rt.lock().unwrap().execute_with(|| { + System::set_block_number(1); + ChronicleModule::apply(RuntimeOrigin::signed(1), submittable).unwrap(); + + let ev = System::events().last().unwrap().event.clone(); + + let opa_event = match ev { + RuntimeEvent::ChronicleModule(event) => match event { + Event::::Applied(diff, identity, correlation_id) => + Some(ChronicleEvent::Committed { diff, identity, correlation_id }), + Event::::Contradiction(contradiction, identity, correlation_id) => + Some(ChronicleEvent::Contradicted { + contradiction, + identity, + correlation_id, + }), + _ => None, + }, + _ => None, + }; + + if let Some(event) = opa_event { + self.events.lock().unwrap().push(event.clone()); + self.tx.send(event).unwrap(); + } else { + tracing::warn!("Received an event that is not an OpaEvent"); + } + }); + + Ok(correlation_id.into()) + } } #[async_trait::async_trait] impl SubstrateStateReader for Stubstrate { - type Error = SubxtClientError; - - async fn get_state_entry( - &self, - _pallet_name: &str, - _entry_name: &str, - _address: K, - ) -> Result, Self::Error> { - unimplemented!() - } + type Error = SubxtClientError; + + async fn get_state_entry( + &self, + _pallet_name: &str, + _entry_name: &str, + _address: K, + ) -> Result, Self::Error> { + unimplemented!() + } } diff --git a/crates/chronicle/Cargo.toml b/crates/chronicle/Cargo.toml index fe3c1bb66..2baf7d639 100644 --- a/crates/chronicle/Cargo.toml +++ b/crates/chronicle/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "chronicle" +name = "chronicle" version = "0.7.5" @@ -24,7 +24,7 @@ futures = { workspace = true } genco = { workspace = true } hex = { workspace = true } iri-string = { version = "^0.7", default-features = false, features = [ - "alloc", + "alloc", ] } is-terminal = { workspace = true } jsonschema = { workspace = true } @@ -56,10 +56,10 @@ chronicle-arrow = { path = "../chronicle-arrow" } chronicle-persistence = { path = "../chronicle-persistence" } chronicle-telemetry = { path = "../chronicle-telemetry" } common = { path = "../common", features = [ - "json-ld", - "std", - "parity-encoding", - "graphql-bindings", + "json-ld", + "std", + "parity-encoding", + "graphql-bindings", ] } embedded-substrate = { path = "../embedded-substrate", optional = true } protocol-substrate = { path = "../protocol-substrate" } @@ -68,17 +68,17 @@ protocol-substrate-opa = { path = "../protocol-substrate-opa" } [features] devmode = ["dep:embedded-substrate"] -strict = [] +strict = [] [build-dependencies] [dev-dependencies] -assert_fs = { workspace = true } -embedded-substrate = { path = "../embedded-substrate" } -insta = { workspace = true, features = ["yaml"] } -mockito = { version = "*" } -protocol-abstract = { path = "../protocol-abstract" } -protocol-substrate = { path = "../protocol-substrate" } +assert_fs = { workspace = true } +embedded-substrate = { path = "../embedded-substrate" } +insta = { workspace = true, features = ["yaml"] } +mockito = { version = "*" } +protocol-abstract = { path = "../protocol-abstract" } +protocol-substrate = { path = "../protocol-substrate" } protocol-substrate-chronicle = { path = "../protocol-substrate-chronicle" } -protocol-substrate-opa = { path = "../protocol-substrate-opa" } -tempfile = { workspace = true } +protocol-substrate-opa = { path = "../protocol-substrate-opa" } +tempfile = { workspace = true } diff --git a/crates/chronicle/schema/domain.json b/crates/chronicle/schema/domain.json index db13d0aa8..6a29418ee 100644 --- a/crates/chronicle/schema/domain.json +++ b/crates/chronicle/schema/domain.json @@ -1,163 +1,163 @@ { - "$schema": "http://json-schema.org/draft-07/schema", - "$id": "http://chronicle.works/schema/chronicle-1.json", - "title": "Chronicle Domain", - "description": "a domain for Chronicle's blockchain-backed provenance", - "type": "object", - "properties": { - "name": { - "description": "the name of this application domain", - "type": "string", - "minLength": 1 - }, - "attributes": { - "description": "attributes of agents, entities, or activities", - "type": "object", - "patternProperties": { - "^[A-Z][A-Za-z0-9]*$": { - "description": "details of an attribute", - "type": "object", - "properties": { - "type": { - "description": "the type of the attribute's value", - "type": "string", - "enum": [ - "String", - "Bool", - "Int", - "JSON" - ] - }, - "doc": { - "description": "optional documentation about an attribute", - "type": "string", - "minLength": 1 - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - }, - "additionalProperties": false - }, - "agents": { - "description": "agents and their attributes, these play some part in causing entities or activities", - "type": "object", - "patternProperties": { - "^[A-Z][A-Za-z0-9]*$": { - "type": "object", - "properties": { - "attributes": { - "description": "the agent's attributes", - "type": "array", - "items": { - "description": "the name of an attribute", - "type": "string", - "pattern": "^[A-Z][A-Za-z0-9]*$" - }, - "uniqueItems": true - }, - "doc": { - "description": "optional documentation about an agent", - "type": "string", - "minLength": 1 - } - }, - "required": [ - "attributes" - ], - "additionalProperties": false - } + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "http://chronicle.works/schema/chronicle-1.json", + "title": "Chronicle Domain", + "description": "a domain for Chronicle's blockchain-backed provenance", + "type": "object", + "properties": { + "name": { + "description": "the name of this application domain", + "type": "string", + "minLength": 1 + }, + "attributes": { + "description": "attributes of agents, entities, or activities", + "type": "object", + "patternProperties": { + "^[A-Z][A-Za-z0-9]*$": { + "description": "details of an attribute", + "type": "object", + "properties": { + "type": { + "description": "the type of the attribute's value", + "type": "string", + "enum": [ + "String", + "Bool", + "Int", + "JSON" + ] }, - "additionalProperties": false - }, - "entities": { - "description": "entities and their attributes", - "type": "object", - "patternProperties": { - "^[A-Z][A-Za-z0-9]*$": { - "type": "object", - "properties": { - "attributes": { - "description": "the entity's attributes", - "type": "array", - "items": { - "description": "the name of an attribute", - "type": "string", - "pattern": "^[A-Z][A-Za-z0-9]*$" - }, - "uniqueItems": true - }, - "doc": { - "description": "optional documentation about an entity", - "type": "string", - "minLength": 1 - } - }, - "required": [ - "attributes" - ], - "additionalProperties": false - } + "doc": { + "description": "optional documentation about an attribute", + "type": "string", + "minLength": 1 + } + }, + "required": [ + "type" + ], + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "agents": { + "description": "agents and their attributes, these play some part in causing entities or activities", + "type": "object", + "patternProperties": { + "^[A-Z][A-Za-z0-9]*$": { + "type": "object", + "properties": { + "attributes": { + "description": "the agent's attributes", + "type": "array", + "items": { + "description": "the name of an attribute", + "type": "string", + "pattern": "^[A-Z][A-Za-z0-9]*$" + }, + "uniqueItems": true }, - "additionalProperties": false - }, - "activities": { - "description": "activities and their attributes, these happen with or to entities", - "type": "object", - "patternProperties": { - "^[A-Z][A-Za-z0-9]*$": { - "type": "object", - "properties": { - "attributes": { - "description": "the activity's attributes", - "type": "array", - "items": { - "description": "the name of an attribute", - "type": "string", - "pattern": "^[A-Z][A-Za-z0-9]*$" - }, - "uniqueItems": true - }, - "doc": { - "description": "optional documentation about an activity", - "type": "string", - "minLength": 1 - } - }, - "required": [ - "attributes" - ], - "additionalProperties": false - } + "doc": { + "description": "optional documentation about an agent", + "type": "string", + "minLength": 1 + } + }, + "required": [ + "attributes" + ], + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "entities": { + "description": "entities and their attributes", + "type": "object", + "patternProperties": { + "^[A-Z][A-Za-z0-9]*$": { + "type": "object", + "properties": { + "attributes": { + "description": "the entity's attributes", + "type": "array", + "items": { + "description": "the name of an attribute", + "type": "string", + "pattern": "^[A-Z][A-Za-z0-9]*$" + }, + "uniqueItems": true }, - "additionalProperties": false - }, - "roles_doc": { - "description": "optional documentation about roles in this application domain", - "type": "string", - "minLength": 1 - }, - "roles": { - "description": "roles, which are functions of agents or entities with respect to activities", - "type": "array", - "items": { - "description": "the name of a role", + "doc": { + "description": "optional documentation about an entity", + "type": "string", + "minLength": 1 + } + }, + "required": [ + "attributes" + ], + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "activities": { + "description": "activities and their attributes, these happen with or to entities", + "type": "object", + "patternProperties": { + "^[A-Z][A-Za-z0-9]*$": { + "type": "object", + "properties": { + "attributes": { + "description": "the activity's attributes", + "type": "array", + "items": { + "description": "the name of an attribute", "type": "string", - "pattern": "^[A-Z][A-Z0-9_]*$" + "pattern": "^[A-Z][A-Za-z0-9]*$" + }, + "uniqueItems": true }, - "uniqueItems": true + "doc": { + "description": "optional documentation about an activity", + "type": "string", + "minLength": 1 + } + }, + "required": [ + "attributes" + ], + "additionalProperties": false } + }, + "additionalProperties": false + }, + "roles_doc": { + "description": "optional documentation about roles in this application domain", + "type": "string", + "minLength": 1 }, - "required": [ - "name", - "attributes", - "agents", - "entities", - "activities", - "roles" - ], - "additionalProperties": false + "roles": { + "description": "roles, which are functions of agents or entities with respect to activities", + "type": "array", + "items": { + "description": "the name of a role", + "type": "string", + "pattern": "^[A-Z][A-Z0-9_]*$" + }, + "uniqueItems": true + } + }, + "required": [ + "name", + "attributes", + "agents", + "entities", + "activities", + "roles" + ], + "additionalProperties": false } diff --git a/crates/chronicle/src/bootstrap/cli.rs b/crates/chronicle/src/bootstrap/cli.rs index a8a7138fe..3eedbcf42 100644 --- a/crates/chronicle/src/bootstrap/cli.rs +++ b/crates/chronicle/src/bootstrap/cli.rs @@ -1,27 +1,26 @@ use std::convert::Infallible; -use api::{ - commands::{ActivityCommand, AgentCommand, ApiCommand, EntityCommand}, - ApiError, -}; -use chronicle_signing::SecretError; use clap::{ - builder::{PossibleValuesParser, StringValueParser}, *, + builder::{PossibleValuesParser, StringValueParser}, }; +use thiserror::Error; +use tokio::sync::broadcast::error::RecvError; +use tracing::info; +use user_error::UFE; + +use api::ApiError; +use api::commands::{ActivityCommand, AgentCommand, ApiCommand, EntityCommand}; +use chronicle_signing::SecretError; use common::{ attributes::{Attribute, Attributes}, opa::std::{FromUrlError, OpaExecutorError, PolicyLoaderError}, prov::{ - json_ld::CompactionError, operations::DerivationType, ActivityId, AgentId, DomaintypeId, - EntityId, ExternalId, ExternalIdPart, ParseIriError, + ActivityId, AgentId, DomaintypeId, EntityId, ExternalId, + ExternalIdPart, json_ld::CompactionError, operations::DerivationType, ParseIriError, }, }; use protocol_substrate::SubxtClientError; -use thiserror::Error; -use tokio::sync::broadcast::error::RecvError; -use tracing::info; -use user_error::UFE; use crate::{ codegen::{ @@ -32,796 +31,796 @@ use crate::{ #[derive(Debug, Error)] pub enum CliError { - #[error("Missing argument: {arg}")] - MissingArgument { arg: String }, - - #[error("Invalid argument {arg} expected {expected} got {got}")] - InvalidArgument { arg: String, expected: String, got: String }, - - #[error("Bad argument: {0}")] - ArgumentParsing( - #[from] - #[source] - clap::Error, - ), - - #[error("Invalid IRI: {0}")] - InvalidIri( - #[from] - #[source] - iri_string::validate::Error, - ), - - #[error("Invalid Chronicle IRI: {0}")] - InvalidChronicleIri( - #[from] - #[source] - ParseIriError, - ), - - #[error("Invalid JSON: {0}")] - InvalidJson( - #[from] - #[source] - serde_json::Error, - ), - - #[error("Invalid URI: {0}")] - InvalidUri( - #[from] - #[source] - url::ParseError, - ), - - #[error("Invalid timestamp: {0}")] - InvalidTimestamp( - #[from] - #[source] - chrono::ParseError, - ), - - #[error("Invalid coercion: {arg}")] - InvalidCoercion { arg: String }, - - #[error("API failure: {0}")] - ApiError( - #[from] - #[source] - ApiError, - ), - - #[error("Secrets : {0}")] - Secrets( - #[from] - #[source] - SecretError, - ), - - #[error("IO error: {0}")] - InputOutput( - #[from] - #[source] - std::io::Error, - ), - - #[error("Invalid configuration file: {0}")] - ConfigInvalid( - #[from] - #[source] - toml::de::Error, - ), - - #[error("Invalid path: {path}")] - InvalidPath { path: String }, - - #[error("Invalid JSON-LD: {0}")] - Ld( - #[from] - #[source] - CompactionError, - ), - - #[error("Failure in commit notification stream: {0}")] - CommitNoticiationStream( - #[from] - #[source] - RecvError, - ), - - #[error("Policy loader error: {0}")] - OpaPolicyLoader( - #[from] - #[source] - PolicyLoaderError, - ), - - #[error("OPA executor error: {0}")] - OpaExecutor( - #[from] - #[source] - OpaExecutorError, - ), - - #[error("Sawtooth communication error: {source}")] - SubstrateError { - #[from] - #[source] - source: SubxtClientError, - }, - - #[error("UTF-8 error: {0}")] - Utf8Error( - #[from] - #[source] - std::str::Utf8Error, - ), - - #[error("Url conversion: {0}")] - FromUrlError( - #[from] - #[source] - FromUrlError, - ), - - #[error("No on chain settings, but they are required by Chronicle")] - NoOnChainSettings, + #[error("Missing argument: {arg}")] + MissingArgument { arg: String }, + + #[error("Invalid argument {arg} expected {expected} got {got}")] + InvalidArgument { arg: String, expected: String, got: String }, + + #[error("Bad argument: {0}")] + ArgumentParsing( + #[from] + #[source] + clap::Error, + ), + + #[error("Invalid IRI: {0}")] + InvalidIri( + #[from] + #[source] + iri_string::validate::Error, + ), + + #[error("Invalid Chronicle IRI: {0}")] + InvalidChronicleIri( + #[from] + #[source] + ParseIriError, + ), + + #[error("Invalid JSON: {0}")] + InvalidJson( + #[from] + #[source] + serde_json::Error, + ), + + #[error("Invalid URI: {0}")] + InvalidUri( + #[from] + #[source] + url::ParseError, + ), + + #[error("Invalid timestamp: {0}")] + InvalidTimestamp( + #[from] + #[source] + chrono::ParseError, + ), + + #[error("Invalid coercion: {arg}")] + InvalidCoercion { arg: String }, + + #[error("API failure: {0}")] + ApiError( + #[from] + #[source] + ApiError, + ), + + #[error("Secrets : {0}")] + Secrets( + #[from] + #[source] + SecretError, + ), + + #[error("IO error: {0}")] + InputOutput( + #[from] + #[source] + std::io::Error, + ), + + #[error("Invalid configuration file: {0}")] + ConfigInvalid( + #[from] + #[source] + toml::de::Error, + ), + + #[error("Invalid path: {path}")] + InvalidPath { path: String }, + + #[error("Invalid JSON-LD: {0}")] + Ld( + #[from] + #[source] + CompactionError, + ), + + #[error("Failure in commit notification stream: {0}")] + CommitNoticiationStream( + #[from] + #[source] + RecvError, + ), + + #[error("Policy loader error: {0}")] + OpaPolicyLoader( + #[from] + #[source] + PolicyLoaderError, + ), + + #[error("OPA executor error: {0}")] + OpaExecutor( + #[from] + #[source] + OpaExecutorError, + ), + + #[error("Sawtooth communication error: {source}")] + SubstrateError { + #[from] + #[source] + source: SubxtClientError, + }, + + #[error("UTF-8 error: {0}")] + Utf8Error( + #[from] + #[source] + std::str::Utf8Error, + ), + + #[error("Url conversion: {0}")] + FromUrlError( + #[from] + #[source] + FromUrlError, + ), + + #[error("No on chain settings, but they are required by Chronicle")] + NoOnChainSettings, } impl CliError { - pub fn missing_argument(arg: impl Into) -> Self { - Self::MissingArgument { arg: arg.into() } - } + pub fn missing_argument(arg: impl Into) -> Self { + Self::MissingArgument { arg: arg.into() } + } } /// Ugly but we need this until ! is stable, see impl From for CliError { - fn from(_: Infallible) -> Self { - unreachable!() - } + fn from(_: Infallible) -> Self { + unreachable!() + } } impl UFE for CliError {} pub trait SubCommand { - fn as_cmd(&self) -> Command; - fn matches(&self, matches: &ArgMatches) -> Result, CliError>; + fn as_cmd(&self) -> Command; + fn matches(&self, matches: &ArgMatches) -> Result, CliError>; } pub struct AttributeCliModel { - pub attribute: AttributeDef, - pub attribute_name: String, - pub attribute_help: String, + pub attribute: AttributeDef, + pub attribute_name: String, + pub attribute_help: String, } impl AttributeCliModel { - pub fn new(attribute: AttributeDef) -> Self { - Self { - attribute_name: format!("{}-attr", attribute.as_cli_name()), - attribute_help: format!("The value of the {} attribute", attribute.as_type_name()), - attribute, - } - } - - pub fn as_arg(&self) -> Arg { - Arg::new(&*self.attribute_name) - .long(&self.attribute_name) - .help(&*self.attribute_help) - .takes_value(true) - .required(true) - } + pub fn new(attribute: AttributeDef) -> Self { + Self { + attribute_name: format!("{}-attr", attribute.as_cli_name()), + attribute_help: format!("The value of the {} attribute", attribute.as_type_name()), + attribute, + } + } + + pub fn as_arg(&self) -> Arg { + Arg::new(&*self.attribute_name) + .long(&self.attribute_name) + .help(&*self.attribute_help) + .takes_value(true) + .required(true) + } } pub struct AgentCliModel { - pub agent: AgentDef, - pub attributes: Vec, - pub about: String, - pub define_about: String, - pub external_id: String, + pub agent: AgentDef, + pub attributes: Vec, + pub about: String, + pub define_about: String, + pub external_id: String, } impl AgentCliModel { - pub fn new(agent: &AgentDef) -> Self { - let attributes = agent - .attributes - .iter() - .map(|attr| AttributeCliModel::new(attr.clone())) - .collect(); - Self { + pub fn new(agent: &AgentDef) -> Self { + let attributes = agent + .attributes + .iter() + .map(|attr| AttributeCliModel::new(attr.clone())) + .collect(); + Self { agent: agent.clone(), attributes, external_id: agent.as_cli_name(), about: format!("Operations on {} agents", agent.as_type_name()), - define_about: format!("Define an agent of type {} with the given external_id or IRI, redefinition with different attribute values is not allowed", agent.as_type_name()) - } - } + define_about: format!("Define an agent of type {} with the given external_id or IRI, redefinition with different attribute values is not allowed", agent.as_type_name()), + } + } } fn name_from<'a, Id>( - args: &'a ArgMatches, - name_param: &str, - id_param: &str, + args: &'a ArgMatches, + name_param: &str, + id_param: &str, ) -> Result -where - Id: 'a + TryFrom + ExternalIdPart, + where + Id: 'a + TryFrom + ExternalIdPart, { - if let Some(external_id) = args.get_one::(name_param) { - Ok(ExternalId::from(external_id)) - } else if let Some(iri) = args.get_one::(id_param) { - let id = Id::try_from(iri.to_string())?; - Ok(id.external_id_part().to_owned()) - } else { - Err(CliError::MissingArgument { arg: format!("Missing {name_param} and {id_param}") }) - } + if let Some(external_id) = args.get_one::(name_param) { + Ok(ExternalId::from(external_id)) + } else if let Some(iri) = args.get_one::(id_param) { + let id = Id::try_from(iri.to_string())?; + Ok(id.external_id_part().to_owned()) + } else { + Err(CliError::MissingArgument { arg: format!("Missing {name_param} and {id_param}") }) + } } fn id_from<'a, Id>(args: &'a ArgMatches, id_param: &str) -> Result -where - Id: 'a + TryFrom + ExternalIdPart, + where + Id: 'a + TryFrom + ExternalIdPart, { - if let Some(id) = args.get_one::(id_param) { - Ok(Id::try_from(id.to_string())?) - } else { - Err(CliError::MissingArgument { arg: format!("Missing {id_param} ") }) - } + if let Some(id) = args.get_one::(id_param) { + Ok(Id::try_from(id.to_string())?) + } else { + Err(CliError::MissingArgument { arg: format!("Missing {id_param} ") }) + } } fn id_from_option<'a, Id>(args: &'a ArgMatches, id_param: &str) -> Result, CliError> -where - Id: 'a + TryFrom + ExternalIdPart, + where + Id: 'a + TryFrom + ExternalIdPart, { - match id_from(args, id_param) { - Err(CliError::MissingArgument { .. }) => Ok(None), - Err(e) => Err(e), - Ok(id) => Ok(Some(id)), - } + match id_from(args, id_param) { + Err(CliError::MissingArgument { .. }) => Ok(None), + Err(e) => Err(e), + Ok(id) => Ok(Some(id)), + } } fn namespace_from(args: &ArgMatches) -> Result { - if let Some(namespace) = args.get_one::("namespace") { - Ok(ExternalId::from(namespace)) - } else { - Err(CliError::MissingArgument { arg: "namespace".to_owned() }) - } + if let Some(namespace) = args.get_one::("namespace") { + Ok(ExternalId::from(namespace)) + } else { + Err(CliError::MissingArgument { arg: "namespace".to_owned() }) + } } /// Deserialize to a JSON value and ensure that it matches the specified primitive type, we need to /// force any bare literal text to be quoted use of coercion afterwards will produce a proper json /// value type for non strings fn attribute_value_from_param( - arg: &str, - value: &str, - typ: PrimitiveType, + arg: &str, + value: &str, + typ: PrimitiveType, ) -> Result { - let value = { - if !value.contains('"') { - format!(r#""{value}""#) - } else { - value.to_owned() - } - }; - - let mut value = serde_json::from_str(&value)?; - match typ { - PrimitiveType::Bool => { - if let Some(coerced) = valico::json_dsl::boolean() - .coerce(&mut value, ".") - .map_err(|_e| CliError::InvalidCoercion { arg: arg.to_owned() })? - { - Ok(coerced) - } else { - Ok(value) - } - }, - PrimitiveType::String => { - if let Some(coerced) = valico::json_dsl::string() - .coerce(&mut value, ".") - .map_err(|_e| CliError::InvalidCoercion { arg: arg.to_owned() })? - { - Ok(coerced) - } else { - Ok(value) - } - }, - PrimitiveType::Int => { - if let Some(coerced) = valico::json_dsl::i64() - .coerce(&mut value, ".") - .map_err(|_e| CliError::InvalidCoercion { arg: arg.to_owned() })? - { - Ok(coerced) - } else { - Ok(value) - } - }, - PrimitiveType::JSON => { - if let Some(coerced) = valico::json_dsl::object() - .coerce(&mut value, ".") - .map_err(|_e| CliError::InvalidCoercion { arg: arg.to_owned() })? - { - Ok(coerced) - } else { - Ok(value) - } - }, - } + let value = { + if !value.contains('"') { + format!(r#""{value}""#) + } else { + value.to_owned() + } + }; + + let mut value = serde_json::from_str(&value)?; + match typ { + PrimitiveType::Bool => { + if let Some(coerced) = valico::json_dsl::boolean() + .coerce(&mut value, ".") + .map_err(|_e| CliError::InvalidCoercion { arg: arg.to_owned() })? + { + Ok(coerced) + } else { + Ok(value) + } + } + PrimitiveType::String => { + if let Some(coerced) = valico::json_dsl::string() + .coerce(&mut value, ".") + .map_err(|_e| CliError::InvalidCoercion { arg: arg.to_owned() })? + { + Ok(coerced) + } else { + Ok(value) + } + } + PrimitiveType::Int => { + if let Some(coerced) = valico::json_dsl::i64() + .coerce(&mut value, ".") + .map_err(|_e| CliError::InvalidCoercion { arg: arg.to_owned() })? + { + Ok(coerced) + } else { + Ok(value) + } + } + PrimitiveType::JSON => { + if let Some(coerced) = valico::json_dsl::object() + .coerce(&mut value, ".") + .map_err(|_e| CliError::InvalidCoercion { arg: arg.to_owned() })? + { + Ok(coerced) + } else { + Ok(value) + } + } + } } fn attributes_from( - args: &ArgMatches, - typ: impl AsRef, - attributes: &[AttributeCliModel], + args: &ArgMatches, + typ: impl AsRef, + attributes: &[AttributeCliModel], ) -> Result { - Ok(Attributes::new( - Some(DomaintypeId::from_external_id(typ)), - attributes - .iter() - .map(|attr| { - let value = attribute_value_from_param( - &attr.attribute_name, - args.get_one::(&attr.attribute_name).unwrap(), - attr.attribute.primitive_type, - )?; - Ok::<_, CliError>(Attribute { - typ: attr.attribute.as_type_name(), - value: value.into(), - }) - }) - .collect::, _>>()?, - )) + Ok(Attributes::new( + Some(DomaintypeId::from_external_id(typ)), + attributes + .iter() + .map(|attr| { + let value = attribute_value_from_param( + &attr.attribute_name, + args.get_one::(&attr.attribute_name).unwrap(), + attr.attribute.primitive_type, + )?; + Ok::<_, CliError>(Attribute { + typ: attr.attribute.as_type_name(), + value: value.into(), + }) + }) + .collect::, _>>()?, + )) } impl SubCommand for AgentCliModel { - fn as_cmd(&self) -> Command { - let cmd = Command::new(&*self.external_id).about(&*self.about); - - let mut define = Command::new("define") - .about(&*self.define_about) - .arg(Arg::new("external_id") - .help("An externally meaningful identifier for the agent, e.g. a URI or relational id") - .takes_value(true)) - .arg(Arg::new("id") - .help("A valid chronicle agent IRI") - .long("id") - .takes_value(true)) - .group(ArgGroup::new("identifier") - .args(&["external_id","id"]) - .required(true)) - .arg( - Arg::new("namespace") - .short('n') - .long("namespace") - .default_value("default") - .required(false) - .takes_value(true), - ); - - for attr in &self.attributes { - define = define.arg(attr.as_arg()); - } + fn as_cmd(&self) -> Command { + let cmd = Command::new(&*self.external_id).about(&*self.about); + + let mut define = Command::new("define") + .about(&*self.define_about) + .arg(Arg::new("external_id") + .help("An externally meaningful identifier for the agent, e.g. a URI or relational id") + .takes_value(true)) + .arg(Arg::new("id") + .help("A valid chronicle agent IRI") + .long("id") + .takes_value(true)) + .group(ArgGroup::new("identifier") + .args(&["external_id", "id"]) + .required(true)) + .arg( + Arg::new("namespace") + .short('n') + .long("namespace") + .default_value("default") + .required(false) + .takes_value(true), + ); - cmd.subcommand(define).subcommand( - Command::new("use") - .about("Make the specified agent the context for activities and entities") - .arg( - Arg::new("id") - .help("A valid chronicle agent IRI") - .required(true) - .takes_value(true), - ) - .arg( - Arg::new("namespace") - .short('n') - .long("namespace") - .default_value("default") - .required(false) - .takes_value(true), - ), - ) - } - - fn matches(&self, matches: &ArgMatches) -> Result, CliError> { - if let Some(matches) = matches.subcommand_matches("define") { - return Ok(Some(ApiCommand::Agent(AgentCommand::Create { - id: name_from::(matches, "external_id", "id")?, - namespace: namespace_from(matches)?, - attributes: attributes_from(matches, &self.agent.external_id, &self.attributes)?, - }))); - } + for attr in &self.attributes { + define = define.arg(attr.as_arg()); + } + + cmd.subcommand(define).subcommand( + Command::new("use") + .about("Make the specified agent the context for activities and entities") + .arg( + Arg::new("id") + .help("A valid chronicle agent IRI") + .required(true) + .takes_value(true), + ) + .arg( + Arg::new("namespace") + .short('n') + .long("namespace") + .default_value("default") + .required(false) + .takes_value(true), + ), + ) + } + + fn matches(&self, matches: &ArgMatches) -> Result, CliError> { + if let Some(matches) = matches.subcommand_matches("define") { + return Ok(Some(ApiCommand::Agent(AgentCommand::Create { + id: name_from::(matches, "external_id", "id")?, + namespace: namespace_from(matches)?, + attributes: attributes_from(matches, &self.agent.external_id, &self.attributes)?, + }))); + } - if let Some(matches) = matches.subcommand_matches("use") { - return Ok(Some(ApiCommand::Agent(AgentCommand::UseInContext { - id: id_from(matches, "id")?, - namespace: namespace_from(matches)?, - }))); - }; + if let Some(matches) = matches.subcommand_matches("use") { + return Ok(Some(ApiCommand::Agent(AgentCommand::UseInContext { + id: id_from(matches, "id")?, + namespace: namespace_from(matches)?, + }))); + }; - Ok(None) - } + Ok(None) + } } pub struct ActivityCliModel { - pub activity: ActivityDef, - pub attributes: Vec, - pub about: String, - pub define_about: String, - pub external_id: String, + pub activity: ActivityDef, + pub attributes: Vec, + pub about: String, + pub define_about: String, + pub external_id: String, } impl ActivityCliModel { - fn new(activity: &ActivityDef) -> Self { - let attributes = activity - .attributes - .iter() - .map(|attr| AttributeCliModel::new(attr.clone())) - .collect(); - Self { + fn new(activity: &ActivityDef) -> Self { + let attributes = activity + .attributes + .iter() + .map(|attr| AttributeCliModel::new(attr.clone())) + .collect(); + Self { activity: activity.clone(), attributes, external_id: activity.as_cli_name(), about: format!("Operations on {} activities", activity.as_type_name()), define_about: format!("Define an activity of type {} with the given external_id or IRI, redefinition with different attribute values is not allowed", activity.as_type_name()), } - } + } } impl SubCommand for ActivityCliModel { - fn as_cmd(&self) -> Command { - let cmd = Command::new(&*self.external_id).about(&*self.about); - - let mut define = - Command::new("define") - .about(&*self.define_about) - .arg(Arg::new("external_id") - .help("An externally meaningful identifier for the activity , e.g. a URI or relational id") - .takes_value(true)) - .arg(Arg::new("id") - .long("id") - .help("A valid chronicle activity IRI") - .takes_value(true)) - .group(ArgGroup::new("identifier") - .args(&["external_id","id"]) - .required(true)) - .arg( - Arg::new("namespace") - .short('n') - .long("namespace") - .default_value("default") - .required(false) - .takes_value(true), - ); - - for attr in &self.attributes { - define = define.arg(attr.as_arg()); - } + fn as_cmd(&self) -> Command { + let cmd = Command::new(&*self.external_id).about(&*self.about); + + let mut define = + Command::new("define") + .about(&*self.define_about) + .arg(Arg::new("external_id") + .help("An externally meaningful identifier for the activity , e.g. a URI or relational id") + .takes_value(true)) + .arg(Arg::new("id") + .long("id") + .help("A valid chronicle activity IRI") + .takes_value(true)) + .group(ArgGroup::new("identifier") + .args(&["external_id", "id"]) + .required(true)) + .arg( + Arg::new("namespace") + .short('n') + .long("namespace") + .default_value("default") + .required(false) + .takes_value(true), + ); + + for attr in &self.attributes { + define = define.arg(attr.as_arg()); + } - cmd.subcommand(define) - .subcommand( - Command::new("start") - .about("Record this activity as started at the specified time, if no time is specified the current time is used") - .arg(Arg::new("id") - .help("A valid chronicle activity IRI") - .takes_value(true) - .required(true) - ) - .arg(Arg::new("agent_id") - .help("A valid chronicle agent IRI") - .long("agent") - .takes_value(true) + cmd.subcommand(define) + .subcommand( + Command::new("start") + .about("Record this activity as started at the specified time, if no time is specified the current time is used") + .arg(Arg::new("id") + .help("A valid chronicle activity IRI") + .takes_value(true) + .required(true) + ) + .arg(Arg::new("agent_id") + .help("A valid chronicle agent IRI") + .long("agent") + .takes_value(true) + .required(false) + ) + .arg( + Arg::new("namespace") + .short('n') + .long("namespace") + .default_value("default") .required(false) - ) - .arg( - Arg::new("namespace") - .short('n') - .long("namespace") - .default_value("default") - .required(false) - .takes_value(true), - ) - .arg( - Arg::new("time") - .long("time") - .help("A valid RFC3339 timestamp") - .required(false) - .takes_value(true) - ) - ) - .subcommand( - Command::new("end") - .about("Record this activity as ended at the specified time, if no time is specified the current time is used") - .arg(Arg::new("id") - .help("A valid chronicle activity IRI") - .takes_value(true) - .required(true) - ) - .arg(Arg::new("agent_id") - .long("agent") - .help("A valid chronicle agent IRI") - .takes_value(true) + .takes_value(true), + ) + .arg( + Arg::new("time") + .long("time") + .help("A valid RFC3339 timestamp") .required(false) - ) - .arg( - Arg::new("namespace") - .short('n') - .long("namespace") - .default_value("default") - .required(false) - .takes_value(true), - ) - .arg( - Arg::new("time") - .long("time") - .help("A valid RFC3339 timestamp") - .required(false) - .takes_value(true) - ) - ) - .subcommand( - Command::new("instant") - .about("Record this activity as taking place at the specified time, if no time is specified the current time is used") - .arg(Arg::new("id") - .help("A valid chronicle activity IRI") - .takes_value(true) - .required(true) - ) - .arg(Arg::new("agent_id") - .long("agent") - .help("A valid chronicle agent IRI") .takes_value(true) + ) + ) + .subcommand( + Command::new("end") + .about("Record this activity as ended at the specified time, if no time is specified the current time is used") + .arg(Arg::new("id") + .help("A valid chronicle activity IRI") + .takes_value(true) + .required(true) + ) + .arg(Arg::new("agent_id") + .long("agent") + .help("A valid chronicle agent IRI") + .takes_value(true) + .required(false) + ) + .arg( + Arg::new("namespace") + .short('n') + .long("namespace") + .default_value("default") + .required(false) + .takes_value(true), + ) + .arg( + Arg::new("time") + .long("time") + .help("A valid RFC3339 timestamp") .required(false) - ) - .arg( - Arg::new("namespace") - .short('n') - .long("namespace") - .default_value("default") - .required(false) - .takes_value(true), - ) - .arg( - Arg::new("time") - .long("time") - .help("A valid RFC3339 timestamp") - .required(false) - .takes_value(true) - ) - ) - .subcommand( - Command::new("use") - .about("Record this activity as having used the specified entity, creating it if required") - .arg(Arg::new("entity_id") - .help("A valid chronicle entity IRI") - .takes_value(true) - .required(true) - ) - .arg(Arg::new("activity_id") - .help("A valid chronicle activity IRI") - .takes_value(true) - .required(true) - ) - .arg( - Arg::new("namespace") - .short('n') - .long("namespace") - .default_value("default") - .required(false) - .takes_value(true), - ) - ) - .subcommand( - Command::new("generate") - .about("Records this activity as having generated the specified entity, creating it if required") - .arg(Arg::new("entity_id") - .help("A valid chronicle entity IRI") .takes_value(true) - .required(true) - ) - .arg(Arg::new("activity_id") - .help("A valid chronicle activity IRI") + ) + ) + .subcommand( + Command::new("instant") + .about("Record this activity as taking place at the specified time, if no time is specified the current time is used") + .arg(Arg::new("id") + .help("A valid chronicle activity IRI") + .takes_value(true) + .required(true) + ) + .arg(Arg::new("agent_id") + .long("agent") + .help("A valid chronicle agent IRI") + .takes_value(true) + .required(false) + ) + .arg( + Arg::new("namespace") + .short('n') + .long("namespace") + .default_value("default") + .required(false) + .takes_value(true), + ) + .arg( + Arg::new("time") + .long("time") + .help("A valid RFC3339 timestamp") + .required(false) .takes_value(true) - .required(true) - ) - .arg( - Arg::new("namespace") - .short('n') - .long("namespace") - .default_value("default") - .required(false) - .takes_value(true), - ) ) - } - - fn matches(&self, matches: &ArgMatches) -> Result, CliError> { - if let Some(matches) = matches.subcommand_matches("define") { - return Ok(Some(ApiCommand::Activity(ActivityCommand::Create { - id: name_from::(matches, "external_id", "id")?, - namespace: namespace_from(matches)?, - attributes: attributes_from(matches, &self.activity.external_id, &self.attributes)?, - }))); - } + ) + .subcommand( + Command::new("use") + .about("Record this activity as having used the specified entity, creating it if required") + .arg(Arg::new("entity_id") + .help("A valid chronicle entity IRI") + .takes_value(true) + .required(true) + ) + .arg(Arg::new("activity_id") + .help("A valid chronicle activity IRI") + .takes_value(true) + .required(true) + ) + .arg( + Arg::new("namespace") + .short('n') + .long("namespace") + .default_value("default") + .required(false) + .takes_value(true), + ) + ) + .subcommand( + Command::new("generate") + .about("Records this activity as having generated the specified entity, creating it if required") + .arg(Arg::new("entity_id") + .help("A valid chronicle entity IRI") + .takes_value(true) + .required(true) + ) + .arg(Arg::new("activity_id") + .help("A valid chronicle activity IRI") + .takes_value(true) + .required(true) + ) + .arg( + Arg::new("namespace") + .short('n') + .long("namespace") + .default_value("default") + .required(false) + .takes_value(true), + ) + ) + } + + fn matches(&self, matches: &ArgMatches) -> Result, CliError> { + if let Some(matches) = matches.subcommand_matches("define") { + return Ok(Some(ApiCommand::Activity(ActivityCommand::Create { + id: name_from::(matches, "external_id", "id")?, + namespace: namespace_from(matches)?, + attributes: attributes_from(matches, &self.activity.external_id, &self.attributes)?, + }))); + } - if let Some(matches) = matches.subcommand_matches("start") { - return Ok(Some(ApiCommand::Activity(ActivityCommand::Start { - id: id_from(matches, "id")?, - namespace: namespace_from(matches)?, - time: matches.get_one::("time").map(|t| t.parse()).transpose()?, - agent: id_from_option(matches, "agent_id")?, - }))); - }; - - if let Some(matches) = matches.subcommand_matches("end") { - return Ok(Some(ApiCommand::Activity(ActivityCommand::End { - id: id_from(matches, "id")?, - namespace: namespace_from(matches)?, - time: matches.get_one::("time").map(|t| t.parse()).transpose()?, - agent: id_from_option(matches, "agent_id")?, - }))); - }; - - if let Some(matches) = matches.subcommand_matches("instant") { - return Ok(Some(ApiCommand::Activity(ActivityCommand::Instant { - id: id_from(matches, "id")?, - namespace: namespace_from(matches)?, - time: matches.get_one::("time").map(|t| t.parse()).transpose()?, - agent: id_from_option(matches, "agent_id")?, - }))); - }; - - if let Some(matches) = matches.subcommand_matches("use") { - return Ok(Some(ApiCommand::Activity(ActivityCommand::Use { - id: id_from(matches, "entity_id")?, - namespace: namespace_from(matches)?, - activity: id_from(matches, "activity_id")?, - }))); - }; - - if let Some(matches) = matches.subcommand_matches("generate") { - return Ok(Some(ApiCommand::Activity(ActivityCommand::Generate { - id: id_from(matches, "entity_id")?, - namespace: namespace_from(matches)?, - activity: id_from(matches, "activity_id")?, - }))); - }; - - Ok(None) - } + if let Some(matches) = matches.subcommand_matches("start") { + return Ok(Some(ApiCommand::Activity(ActivityCommand::Start { + id: id_from(matches, "id")?, + namespace: namespace_from(matches)?, + time: matches.get_one::("time").map(|t| t.parse()).transpose()?, + agent: id_from_option(matches, "agent_id")?, + }))); + }; + + if let Some(matches) = matches.subcommand_matches("end") { + return Ok(Some(ApiCommand::Activity(ActivityCommand::End { + id: id_from(matches, "id")?, + namespace: namespace_from(matches)?, + time: matches.get_one::("time").map(|t| t.parse()).transpose()?, + agent: id_from_option(matches, "agent_id")?, + }))); + }; + + if let Some(matches) = matches.subcommand_matches("instant") { + return Ok(Some(ApiCommand::Activity(ActivityCommand::Instant { + id: id_from(matches, "id")?, + namespace: namespace_from(matches)?, + time: matches.get_one::("time").map(|t| t.parse()).transpose()?, + agent: id_from_option(matches, "agent_id")?, + }))); + }; + + if let Some(matches) = matches.subcommand_matches("use") { + return Ok(Some(ApiCommand::Activity(ActivityCommand::Use { + id: id_from(matches, "entity_id")?, + namespace: namespace_from(matches)?, + activity: id_from(matches, "activity_id")?, + }))); + }; + + if let Some(matches) = matches.subcommand_matches("generate") { + return Ok(Some(ApiCommand::Activity(ActivityCommand::Generate { + id: id_from(matches, "entity_id")?, + namespace: namespace_from(matches)?, + activity: id_from(matches, "activity_id")?, + }))); + }; + + Ok(None) + } } pub struct EntityCliModel { - pub entity: EntityDef, - pub attributes: Vec, - pub about: String, - pub define_about: String, - pub external_id: String, + pub entity: EntityDef, + pub attributes: Vec, + pub about: String, + pub define_about: String, + pub external_id: String, } impl EntityCliModel { - pub fn new(entity: &EntityDef) -> Self { - let attributes = entity - .attributes - .iter() - .map(|attr| AttributeCliModel::new(attr.clone())) - .collect(); - Self { + pub fn new(entity: &EntityDef) -> Self { + let attributes = entity + .attributes + .iter() + .map(|attr| AttributeCliModel::new(attr.clone())) + .collect(); + Self { entity: entity.clone(), attributes, external_id: entity.as_cli_name(), about: format!("Operations on {} entities", entity.as_type_name()), define_about: format!("Define an entity of type {} with the given external_id or IRI, redefinition with different attribute values is not allowed", entity.as_type_name()), } - } + } } impl SubCommand for EntityCliModel { - fn as_cmd(&self) -> Command { - let cmd = Command::new(&self.external_id).about(&*self.about); - - let mut define = - Command::new("define") - .about(&*self.define_about) - .arg(Arg::new("external_id") - .help("An externally meaningful identifier for the entity, e.g. a URI or relational id") - .takes_value(true)) - .arg(Arg::new("id") - .long("id") - .help("A valid chronicle entity IRI") - .takes_value(true)) - .group(ArgGroup::new("identifier") - .args(&["external_id","id"]) - .required(true)) - .arg( - Arg::new("namespace") - .short('n') - .long("namespace") - .default_value("default") - .required(false) - .takes_value(true), - ); - - for attr in &self.attributes { - define = define.arg(attr.as_arg()); - } + fn as_cmd(&self) -> Command { + let cmd = Command::new(&self.external_id).about(&*self.about); + + let mut define = + Command::new("define") + .about(&*self.define_about) + .arg(Arg::new("external_id") + .help("An externally meaningful identifier for the entity, e.g. a URI or relational id") + .takes_value(true)) + .arg(Arg::new("id") + .long("id") + .help("A valid chronicle entity IRI") + .takes_value(true)) + .group(ArgGroup::new("identifier") + .args(&["external_id", "id"]) + .required(true)) + .arg( + Arg::new("namespace") + .short('n') + .long("namespace") + .default_value("default") + .required(false) + .takes_value(true), + ); + + for attr in &self.attributes { + define = define.arg(attr.as_arg()); + } - cmd.subcommand(define).subcommand( - Command::new("derive") - .about("Derivation of entities from other entities") - .arg( - Arg::new("subtype") - .help("The derivation subtype") - .long("subtype") - .required(false) - .takes_value(true) - .value_parser(PossibleValuesParser::new([ - "revision", - "quotation", - "primary-source", - ])), - ) - .arg( - Arg::new("generated_entity_id") - .help("A valid chronicle entity IRI for the generated entity") - .takes_value(true) - .required(true), - ) - .arg( - Arg::new("used_entity_id") - .help("A valid chronicle entity IRI for the used entity") - .takes_value(true) - .required(true), - ) - .arg( - Arg::new("activity_id") - .help("The activity IRI that generated the entity") - .long("activity") - .takes_value(true) - .required(false), - ) - .arg( - Arg::new("namespace") - .short('n') - .long("namespace") - .default_value("default") - .required(false) - .takes_value(true), - ), - ) - } - - fn matches(&self, matches: &ArgMatches) -> Result, CliError> { - if let Some(matches) = matches.subcommand_matches("define") { - return Ok(Some(ApiCommand::Entity(EntityCommand::Create { - id: name_from::(matches, "external_id", "id")?, - namespace: namespace_from(matches)?, - attributes: attributes_from(matches, &self.entity.external_id, &self.attributes)?, - }))); - } + cmd.subcommand(define).subcommand( + Command::new("derive") + .about("Derivation of entities from other entities") + .arg( + Arg::new("subtype") + .help("The derivation subtype") + .long("subtype") + .required(false) + .takes_value(true) + .value_parser(PossibleValuesParser::new([ + "revision", + "quotation", + "primary-source", + ])), + ) + .arg( + Arg::new("generated_entity_id") + .help("A valid chronicle entity IRI for the generated entity") + .takes_value(true) + .required(true), + ) + .arg( + Arg::new("used_entity_id") + .help("A valid chronicle entity IRI for the used entity") + .takes_value(true) + .required(true), + ) + .arg( + Arg::new("activity_id") + .help("The activity IRI that generated the entity") + .long("activity") + .takes_value(true) + .required(false), + ) + .arg( + Arg::new("namespace") + .short('n') + .long("namespace") + .default_value("default") + .required(false) + .takes_value(true), + ), + ) + } + + fn matches(&self, matches: &ArgMatches) -> Result, CliError> { + if let Some(matches) = matches.subcommand_matches("define") { + return Ok(Some(ApiCommand::Entity(EntityCommand::Create { + id: name_from::(matches, "external_id", "id")?, + namespace: namespace_from(matches)?, + attributes: attributes_from(matches, &self.entity.external_id, &self.attributes)?, + }))); + } - if let Some(matches) = matches.subcommand_matches("derive") { - return Ok(Some(ApiCommand::Entity(EntityCommand::Derive { - namespace: namespace_from(matches)?, - id: id_from(matches, "generated_entity_id")?, - derivation: matches - .get_one::("subtype") - .map(|v| match v.as_str() { - "revision" => DerivationType::Revision, - "quotation" => DerivationType::Quotation, - "primary-source" => DerivationType::PrimarySource, - _ => unreachable!(), // Guaranteed by PossibleValuesParser - }) - .unwrap_or(DerivationType::None), - activity: id_from_option(matches, "activity_id")?, - used_entity: id_from(matches, "used_entity_id")?, - }))); - } + if let Some(matches) = matches.subcommand_matches("derive") { + return Ok(Some(ApiCommand::Entity(EntityCommand::Derive { + namespace: namespace_from(matches)?, + id: id_from(matches, "generated_entity_id")?, + derivation: matches + .get_one::("subtype") + .map(|v| match v.as_str() { + "revision" => DerivationType::Revision, + "quotation" => DerivationType::Quotation, + "primary-source" => DerivationType::PrimarySource, + _ => unreachable!(), // Guaranteed by PossibleValuesParser + }) + .unwrap_or(DerivationType::None), + activity: id_from_option(matches, "activity_id")?, + used_entity: id_from(matches, "used_entity_id")?, + }))); + } - Ok(None) - } + Ok(None) + } } pub struct CliModel { - pub domain: ChronicleDomainDef, - pub agents: Vec, - pub entities: Vec, - pub activities: Vec, + pub domain: ChronicleDomainDef, + pub agents: Vec, + pub entities: Vec, + pub activities: Vec, } pub const LONG_VERSION: &str = const_format::formatcp!( @@ -832,20 +831,20 @@ pub const LONG_VERSION: &str = const_format::formatcp!( ); impl From for CliModel { - fn from(val: ChronicleDomainDef) -> Self { - info!(chronicle_version = LONG_VERSION); - CliModel { - agents: val.agents.iter().map(AgentCliModel::new).collect(), - entities: val.entities.iter().map(EntityCliModel::new).collect(), - activities: val.activities.iter().map(ActivityCliModel::new).collect(), - domain: val, - } - } + fn from(val: ChronicleDomainDef) -> Self { + info!(chronicle_version = LONG_VERSION); + CliModel { + agents: val.agents.iter().map(AgentCliModel::new).collect(), + entities: val.entities.iter().map(EntityCliModel::new).collect(), + activities: val.activities.iter().map(ActivityCliModel::new).collect(), + domain: val, + } + } } impl SubCommand for CliModel { - fn as_cmd(&self) -> Command { - let mut app = Command::new("chronicle") + fn as_cmd(&self) -> Command { + let mut app = Command::new("chronicle") .version(LONG_VERSION) .author("Blockchain Technology Partners") .about("Write and query provenance data to distributed ledgers") @@ -860,17 +859,17 @@ impl SubCommand for CliModel { ) .arg(Arg::new("console-logging").long("console-logging") .takes_value(true) - .possible_values(["pretty","json"]) + .possible_values(["pretty", "json"]) .default_value("pretty") .help( "Instrument using RUST_LOG environment, writing in either human readable format or structured json to stdio", - )) + )) .arg( Arg::new("remote-database") .long("remote-database") .help("connect to a provided PostgreSQL (option is ignored and deprecated)") ) - .arg( + .arg( Arg::new("database-host") .long("database-host") .takes_value(true) @@ -904,9 +903,9 @@ impl SubCommand for CliModel { ) .arg( Arg::new("opa-bundle-address") - .long("opa-bundle-address") - .takes_value(true) - .help("URL or path for loading OPA policy bundle") + .long("opa-bundle-address") + .takes_value(true) + .help("URL or path for loading OPA policy bundle") ) .arg( Arg::with_name("opa-policy-name") @@ -940,7 +939,7 @@ impl SubCommand for CliModel { Command::new("serve-api") .alias("serve-graphql") .about("Start an API server") - .arg( + .arg( Arg::new("arrow-interface") .long("arrow-interface") .takes_value(true) @@ -958,68 +957,67 @@ impl SubCommand for CliModel { .env("API_LISTEN_SOCKET") .help("The API server address"), ).arg( - Arg::new("playground") - .long("playground") - .alias("open") - .required(false) - .takes_value(false) - .help("Deprecated option (after v0.6.0) to make available the GraphQL Playground"), - ).arg( - Arg::new("require-auth") - .long("require-auth") - .requires("oidc-endpoint-address") - .env("REQUIRE_AUTH") - .help("if JWT must be provided, preventing anonymous requests"), - ).arg( - Arg::new("liveness-check") - .long("liveness-check") - .help("Turn on liveness depth charge checks and specify the interval in seconds") - .takes_value(true) - .value_name("interval") - .default_missing_value("1800"), - ).arg( - Arg::new("jwks-address") - .long("jwks-address") - .takes_value(true) - .env("JWKS_URI") - .help("URI of the JSON key set for verifying web tokens"), - - ).arg({ - Arg::new("userinfo-address") - .long("userinfo-address") - .takes_value(true) - .env("USERINFO_URI") - .help("URI of the OIDC UserInfo endpoint") - } - ).group( - ArgGroup::new("oidc-endpoint-address") - .args(&["jwks-address", "userinfo-address"]) - .multiple(true) - ).arg( - Arg::new("id-claims") - .long("id-claims") - .takes_value(true) - .min_values(1) - .default_values(&["iss", "sub"]) - .env("JWT_ID_CLAIMS") - .help("JWT claims that determine Chronicle ID"), - ) + Arg::new("playground") + .long("playground") + .alias("open") + .required(false) + .takes_value(false) + .help("Deprecated option (after v0.6.0) to make available the GraphQL Playground"), + ).arg( + Arg::new("require-auth") + .long("require-auth") + .requires("oidc-endpoint-address") + .env("REQUIRE_AUTH") + .help("if JWT must be provided, preventing anonymous requests"), + ).arg( + Arg::new("liveness-check") + .long("liveness-check") + .help("Turn on liveness depth charge checks and specify the interval in seconds") + .takes_value(true) + .value_name("interval") + .default_missing_value("1800"), + ).arg( + Arg::new("jwks-address") + .long("jwks-address") + .takes_value(true) + .env("JWKS_URI") + .help("URI of the JSON key set for verifying web tokens"), + ).arg({ + Arg::new("userinfo-address") + .long("userinfo-address") + .takes_value(true) + .env("USERINFO_URI") + .help("URI of the OIDC UserInfo endpoint") + } + ).group( + ArgGroup::new("oidc-endpoint-address") + .args(&["jwks-address", "userinfo-address"]) + .multiple(true) + ).arg( + Arg::new("id-claims") + .long("id-claims") + .takes_value(true) + .min_values(1) + .default_values(&["iss", "sub"]) + .env("JWT_ID_CLAIMS") + .help("JWT claims that determine Chronicle ID"), + ) .arg( Arg::new("jwt-must-claim") - .long("jwt-must-claim") - .multiple_occurrences(true) - .multiple_values(true) - .number_of_values(2) - .help("claim name and value that must be present for accepting a JWT") + .long("jwt-must-claim") + .multiple_occurrences(true) + .multiple_values(true) + .number_of_values(2) + .help("claim name and value that must be present for accepting a JWT") ) .arg( Arg::new("offer-endpoints") - .long("offer-endpoints") - .takes_value(true) - .min_values(1) - .value_parser(["data", "graphql"]) - .default_values(&["data", "graphql"]) - .help("which API endpoints to offer") + .long("offer-endpoints") + .takes_value(true) + .min_values(1) + .value_parser(["data", "graphql"]) + .default_values(&["data", "graphql"]) + .help("which API endpoints to offer") ), ) .subcommand(Command::new("verify-keystore").about("Initialize and verify keystore, then exit")) @@ -1048,47 +1046,47 @@ impl SubCommand for CliModel { ) ); - for agent in self.agents.iter() { - app = app.subcommand(agent.as_cmd()); - } - for activity in self.activities.iter() { - app = app.subcommand(activity.as_cmd()); - } - for entity in self.entities.iter() { - app = app.subcommand(entity.as_cmd()); - } + for agent in self.agents.iter() { + app = app.subcommand(agent.as_cmd()); + } + for activity in self.activities.iter() { + app = app.subcommand(activity.as_cmd()); + } + for entity in self.entities.iter() { + app = app.subcommand(entity.as_cmd()); + } + + #[cfg(not(feature = "devmode"))] + { + app = app.arg( + Arg::new("batcher-key-from-path") + .long("batcher-key-from-path") + .takes_value(true) + .value_hint(ValueHint::DirPath) + .help("Path to a directory containing the key for signing batches") + .conflicts_with("batcher-key-from-vault") + .conflicts_with("batcher-key-generated"), + ); + + app = app.arg( + Arg::new("batcher-key-from-vault") + .long("batcher-key-from-vault") + .takes_value(false) + .help("Use Hashicorp Vault to store the batcher key") + .conflicts_with("batcher-key-from-path") + .conflicts_with("batcher-key-generated"), + ); + + app = app.arg( + Arg::new("batcher-key-generated") + .long("batcher-key-generated") + .takes_value(false) + .help("Generate the batcher key in memory") + .conflicts_with("batcher-key-from-path") + .conflicts_with("batcher-key-from-vault"), + ); - #[cfg(not(feature = "devmode"))] - { - app = app.arg( - Arg::new("batcher-key-from-path") - .long("batcher-key-from-path") - .takes_value(true) - .value_hint(ValueHint::DirPath) - .help("Path to a directory containing the key for signing batches") - .conflicts_with("batcher-key-from-vault") - .conflicts_with("batcher-key-generated"), - ); - - app = app.arg( - Arg::new("batcher-key-from-vault") - .long("batcher-key-from-vault") - .takes_value(false) - .help("Use Hashicorp Vault to store the batcher key") - .conflicts_with("batcher-key-from-path") - .conflicts_with("batcher-key-generated"), - ); - - app = app.arg( - Arg::new("batcher-key-generated") - .long("batcher-key-generated") - .takes_value(false) - .help("Generate the batcher key in memory") - .conflicts_with("batcher-key-from-path") - .conflicts_with("batcher-key-from-vault"), - ); - - app = app.arg( + app = app.arg( Arg::new("chronicle-key-from-path") .long("chronicle-key-from-path") .takes_value(true) @@ -1098,103 +1096,103 @@ impl SubCommand for CliModel { .conflicts_with("chronicle-key-generated"), ); - app = app.arg( - Arg::new("chronicle-key-from-vault") - .long("chronicle-key-from-vault") - .takes_value(false) - .help("Use Hashicorp Vault to store the Chronicle key") - .conflicts_with("chronicle-key-from-path") - .conflicts_with("chronicle-key-generated"), - ); - - app = app.arg( - Arg::new("chronicle-key-generated") - .long("chronicle-key-generated") - .takes_value(false) - .help("Generate the Chronicle key in memory") - .conflicts_with("chronicle-key-from-path") - .conflicts_with("chronicle-key-from-vault"), - ); - - app = app.arg( - Arg::new("vault-address") - .long("vault-address") - .takes_value(true) - .value_hint(ValueHint::Url) - .help("URL for connecting to Hashicorp Vault") - .env("VAULT_ADDRESS"), - ); - - app = app.arg( - Arg::new("vault-token") - .long("vault-token") - .takes_value(true) - .help("Token for connecting to Hashicorp Vault") - .env("VAULT_TOKEN"), - ); - - app = app.arg( - Arg::new("vault-mount-path") - .long("vault-mount-path") - .takes_value(true) - .value_hint(ValueHint::DirPath) - .help("Mount path for vault secrets") - .env("VAULT_MOUNT_PATH"), - ); - - app.arg( - // default is provided by cargo.toml - Arg::new("validator") - .long("validator") - .value_name("validator") - .value_hint(ValueHint::Url) - .help("Sets validator address") - .takes_value(true), - ) - .arg( - Arg::new("embedded-opa-policy") - .long("embedded-opa-policy") - .takes_value(false) - .help( - "Operate without an external OPA policy, using an embedded default policy", - ), - ) - } - #[cfg(feature = "devmode")] - { - app - } - } - - /// Iterate our possible subcommands via model and short circuit with the first one that matches - fn matches(&self, matches: &ArgMatches) -> Result, CliError> { - for (agent, matches) in self.agents.iter().filter_map(|agent| { - matches.subcommand_matches(&agent.external_id).map(|matches| (agent, matches)) - }) { - if let Some(cmd) = agent.matches(matches)? { - return Ok(Some(cmd)); - } - } - for (entity, matches) in self.entities.iter().filter_map(|entity| { - matches.subcommand_matches(&entity.external_id).map(|matches| (entity, matches)) - }) { - if let Some(cmd) = entity.matches(matches)? { - return Ok(Some(cmd)); - } - } - for (activity, matches) in self.activities.iter().filter_map(|activity| { - matches - .subcommand_matches(&activity.external_id) - .map(|matches| (activity, matches)) - }) { - if let Some(cmd) = activity.matches(matches)? { - return Ok(Some(cmd)); - } - } - Ok(None) - } + app = app.arg( + Arg::new("chronicle-key-from-vault") + .long("chronicle-key-from-vault") + .takes_value(false) + .help("Use Hashicorp Vault to store the Chronicle key") + .conflicts_with("chronicle-key-from-path") + .conflicts_with("chronicle-key-generated"), + ); + + app = app.arg( + Arg::new("chronicle-key-generated") + .long("chronicle-key-generated") + .takes_value(false) + .help("Generate the Chronicle key in memory") + .conflicts_with("chronicle-key-from-path") + .conflicts_with("chronicle-key-from-vault"), + ); + + app = app.arg( + Arg::new("vault-address") + .long("vault-address") + .takes_value(true) + .value_hint(ValueHint::Url) + .help("URL for connecting to Hashicorp Vault") + .env("VAULT_ADDRESS"), + ); + + app = app.arg( + Arg::new("vault-token") + .long("vault-token") + .takes_value(true) + .help("Token for connecting to Hashicorp Vault") + .env("VAULT_TOKEN"), + ); + + app = app.arg( + Arg::new("vault-mount-path") + .long("vault-mount-path") + .takes_value(true) + .value_hint(ValueHint::DirPath) + .help("Mount path for vault secrets") + .env("VAULT_MOUNT_PATH"), + ); + + app.arg( + // default is provided by cargo.toml + Arg::new("validator") + .long("validator") + .value_name("validator") + .value_hint(ValueHint::Url) + .help("Sets validator address") + .takes_value(true), + ) + .arg( + Arg::new("embedded-opa-policy") + .long("embedded-opa-policy") + .takes_value(false) + .help( + "Operate without an external OPA policy, using an embedded default policy", + ), + ) + } + #[cfg(feature = "devmode")] + { + app + } + } + + /// Iterate our possible subcommands via model and short circuit with the first one that matches + fn matches(&self, matches: &ArgMatches) -> Result, CliError> { + for (agent, matches) in self.agents.iter().filter_map(|agent| { + matches.subcommand_matches(&agent.external_id).map(|matches| (agent, matches)) + }) { + if let Some(cmd) = agent.matches(matches)? { + return Ok(Some(cmd)); + } + } + for (entity, matches) in self.entities.iter().filter_map(|entity| { + matches.subcommand_matches(&entity.external_id).map(|matches| (entity, matches)) + }) { + if let Some(cmd) = entity.matches(matches)? { + return Ok(Some(cmd)); + } + } + for (activity, matches) in self.activities.iter().filter_map(|activity| { + matches + .subcommand_matches(&activity.external_id) + .map(|matches| (activity, matches)) + }) { + if let Some(cmd) = activity.matches(matches)? { + return Ok(Some(cmd)); + } + } + Ok(None) + } } pub fn cli(domain: ChronicleDomainDef) -> CliModel { - CliModel::from(domain) + CliModel::from(domain) } diff --git a/crates/chronicle/src/bootstrap/mod.rs b/crates/chronicle/src/bootstrap/mod.rs index d30858bba..4e582379a 100644 --- a/crates/chronicle/src/bootstrap/mod.rs +++ b/crates/chronicle/src/bootstrap/mod.rs @@ -1,106 +1,105 @@ -mod cli; -pub mod opa; +use std::{ + collections::{BTreeSet, HashMap}, + io::{self}, + net::{SocketAddr, ToSocketAddrs}, + str::FromStr, +}; +use std::io::IsTerminal; + +use async_graphql::ObjectType; +use clap::{ArgMatches, Command}; +use clap_complete::{generate, Generator, Shell}; +use diesel::{ + PgConnection, + r2d2::{ConnectionManager, Pool}, +}; +use futures::{Future, FutureExt, StreamExt}; +use tracing::{debug, error, info, instrument, warn}; +use url::Url; +use user_error::UFE; + use api::{ chronicle_graphql::{ ChronicleApiServer, ChronicleGraphQl, EndpointSecurityConfiguration, JwksUri, SecurityConf, UserInfoUri, - }, - commands::ApiResponse, - Api, ApiDispatch, ApiError, StoreError, UuidGen, + }, commands::ApiResponse, StoreError, }; -use async_graphql::ObjectType; -use chronicle_persistence::database::{get_connection_with_retry, DatabaseConnector}; +use api::{Api, UuidGen}; +use api::ApiDispatch; +use api::ApiError; +use chronicle_persistence::database::{DatabaseConnector, get_connection_with_retry}; +use chronicle_signing::{ + BATCHER_NAMESPACE, CHRONICLE_NAMESPACE, chronicle_secret_names, ChronicleSecretsOptions, + ChronicleSigning, +}; +use chronicle_telemetry::{self, ConsoleLogging}; +pub use cli::*; use common::{ opa::{ - std::{load_bytes_from_stdin, load_bytes_from_url}, PolicyAddress, + std::{load_bytes_from_stdin, load_bytes_from_url}, }, prov::json_ld::ToJson, }; -#[cfg(feature = "devmode")] -use embedded_substrate::EmbeddedSubstrate; -use futures::{Future, FutureExt, StreamExt}; -#[cfg(not(feature = "devmode"))] -use protocol_substrate_chronicle::ChronicleSubstrateClient; - -use chronicle_signing::{ - chronicle_secret_names, ChronicleSecretsOptions, ChronicleSigning, BATCHER_NAMESPACE, - CHRONICLE_NAMESPACE, -}; -use clap::{ArgMatches, Command}; -use clap_complete::{generate, Generator, Shell}; -pub use cli::*; use common::{ identity::AuthId, ledger::SubmissionStage, - opa::{std::ExecutorContext, OpaSettings}, - prov::{operations::ChronicleOperation, NamespaceId}, -}; - -use std::io::IsTerminal; -use tracing::{debug, error, info, instrument, warn}; -use user_error::UFE; - -use diesel::{ - r2d2::{ConnectionManager, Pool}, - PgConnection, -}; - -use chronicle_telemetry::{self, ConsoleLogging}; -use url::Url; - -use std::{ - collections::{BTreeSet, HashMap}, - io::{self}, - net::{SocketAddr, ToSocketAddrs}, - str::FromStr, + opa::{OpaSettings, std::ExecutorContext}, + prov::{NamespaceId, operations::ChronicleOperation}, }; +#[cfg(feature = "devmode")] +use embedded_substrate::EmbeddedSubstrate; +#[cfg(not(feature = "devmode"))] +use protocol_substrate_chronicle::ChronicleSubstrateClient; use crate::codegen::ChronicleDomainDef; use self::opa::opa_executor_from_embedded_policy; +mod cli; +pub mod opa; + #[cfg(not(feature = "devmode"))] fn validator_address(options: &ArgMatches) -> Result, CliError> { - Ok(options - .value_of("validator") - .map(str::to_string) - .ok_or(CliError::MissingArgument { arg: "validator".to_owned() }) - .and_then(|s| Url::parse(&s).map_err(CliError::from)) - .map(|u| u.socket_addrs(|| Some(4004))) - .map_err(CliError::from)??) + Ok(options + .value_of("validator") + .map(str::to_string) + .ok_or(CliError::MissingArgument { arg: "validator".to_owned() }) + .and_then(|s| Url::parse(&s).map_err(CliError::from)) + .map(|u| u.socket_addrs(|| Some(4004))) + .map_err(CliError::from)??) } #[allow(dead_code)] #[cfg(not(feature = "devmode"))] async fn ledger( - options: &ArgMatches, + options: &ArgMatches, ) -> Result, CliError> { - let url = options - .value_of("validator") - .map(str::to_string) - .ok_or_else(|| CliError::MissingArgument { arg: "validator".to_owned() })?; + let url = options + .value_of("validator") + .map(str::to_string) + .ok_or_else(|| CliError::MissingArgument { arg: "validator".to_owned() })?; - let url = Url::parse(&url).map_err(CliError::from)?; + let url = Url::parse(&url).map_err(CliError::from)?; - let addrs = url.socket_addrs(|| Some(9944)).map_err(CliError::from)?; + let addrs = url.socket_addrs(|| Some(9944)).map_err(CliError::from)?; - let client = ChronicleSubstrateClient::::connect( - addrs[0].to_string(), - ) - .await?; + let client = ChronicleSubstrateClient::::connect( + addrs[0].to_string(), + ) + .await?; - Ok(client) + Ok(client) } #[allow(dead_code)] #[cfg(feature = "devmode")] async fn in_mem_ledger( - _options: &ArgMatches, + _options: &ArgMatches, ) -> Result, ApiError> { - embedded_substrate::shared_dev_node_rpc_on_arbitrary_port() - .await - .map_err(|e| ApiError::EmbeddedSubstrate(e.into())) + embedded_substrate::shared_dev_node_rpc_on_arbitrary_port() + .await + .map_err(|e| ApiError::EmbeddedSubstrate(e.into())) } #[derive(Debug, Clone)] @@ -111,40 +110,40 @@ impl UuidGen for UniqueUuid {} type ConnectionPool = Pool>; struct RemoteDatabaseConnector { - db_uri: String, + db_uri: String, } #[async_trait::async_trait] impl DatabaseConnector<(), StoreError> for RemoteDatabaseConnector { - async fn try_connect(&self) -> Result<((), Pool>), StoreError> { - use diesel::Connection; - PgConnection::establish(&self.db_uri)?; - Ok(((), Pool::builder().build(ConnectionManager::::new(&self.db_uri))?)) - } - - fn should_retry(&self, error: &StoreError) -> bool { - matches!(error, StoreError::DbConnection(diesel::ConnectionError::BadConnection(_))) - } + async fn try_connect(&self) -> Result<((), Pool>), StoreError> { + use diesel::Connection; + PgConnection::establish(&self.db_uri)?; + Ok(((), Pool::builder().build(ConnectionManager::::new(&self.db_uri))?)) + } + + fn should_retry(&self, error: &StoreError) -> bool { + matches!(error, StoreError::DbConnection(diesel::ConnectionError::BadConnection(_))) + } } #[instrument(skip(db_uri))] //Do not log db_uri, as it can contain passwords async fn pool_remote(db_uri: impl ToString) -> Result { - let (_, pool) = - get_connection_with_retry(RemoteDatabaseConnector { db_uri: db_uri.to_string() }).await?; - Ok(pool) + let (_, pool) = + get_connection_with_retry(RemoteDatabaseConnector { db_uri: db_uri.to_string() }).await?; + Ok(pool) } #[instrument(skip_all)] pub async fn arrow_api_server( - domain: &ChronicleDomainDef, - api: &ApiDispatch, - pool: &ConnectionPool, - addresses: Option>, - security_conf: EndpointSecurityConfiguration, - record_batch_size: usize, - operation_batch_size: usize, -) -> Result> + Send>, ApiError> { - tracing::info!( + domain: &ChronicleDomainDef, + api: &ApiDispatch, + pool: &ConnectionPool, + addresses: Option>, + security_conf: EndpointSecurityConfiguration, + record_batch_size: usize, + operation_batch_size: usize, +) -> Result> + Send>, ApiError> { + tracing::info!( addresses = ?addresses, allow_anonymous = ?security_conf.allow_anonymous, jwt_must_claim = ?security_conf.must_claim, @@ -153,228 +152,228 @@ pub async fn arrow_api_server( "Starting arrow flight with the provided configuration" ); - match addresses { - Some(addresses) => chronicle_arrow::run_flight_service( - domain, - pool, - api, - security_conf, - &addresses, - record_batch_size, - ) - .await - .map_err(|e| ApiError::ArrowService(e.into())) - .map(|_| Some(futures::future::ready(Ok(())))), - None => Ok(None), - } + match addresses { + Some(addresses) => chronicle_arrow::run_flight_service( + domain, + pool, + api, + security_conf, + &addresses, + record_batch_size, + ) + .await + .map_err(|e| ApiError::ArrowService(e.into())) + .map(|_| Some(futures::future::ready(Ok(())))), + None => Ok(None), + } } pub async fn graphql_api_server( - api: &ApiDispatch, - pool: &ConnectionPool, - gql: ChronicleGraphQl, - graphql_interface: Option>, - security_conf: &SecurityConf, - serve_graphql: bool, - serve_data: bool, -) -> Result> + Send>, ApiError> -where - Query: ObjectType + Copy + Send + 'static, - Mutation: ObjectType + Copy + Send + 'static, + api: &ApiDispatch, + pool: &ConnectionPool, + gql: ChronicleGraphQl, + graphql_interface: Option>, + security_conf: &SecurityConf, + serve_graphql: bool, + serve_data: bool, +) -> Result> + Send>, ApiError> + where + Query: ObjectType + Copy + Send + 'static, + Mutation: ObjectType + Copy + Send + 'static, { - if let Some(addresses) = graphql_interface { - gql.serve_api( - pool.clone(), - api.clone(), - addresses, - security_conf, - serve_graphql, - serve_data, - ) - .await?; - Ok(Some(futures::future::ready(Ok(())))) - } else { - Ok(None) - } + if let Some(addresses) = graphql_interface { + gql.serve_api( + pool.clone(), + api.clone(), + addresses, + security_conf, + serve_graphql, + serve_data, + ) + .await?; + Ok(Some(futures::future::ready(Ok(())))) + } else { + Ok(None) + } } #[allow(dead_code)] fn namespace_bindings(options: &ArgMatches) -> Vec { - options - .values_of("namespace-bindings") - .map(|values| { - values - .map(|value| { - let (id, uuid) = value.split_once(':').unwrap(); - - let uuid = uuid::Uuid::parse_str(uuid).unwrap(); - NamespaceId::from_external_id(id, uuid) - }) - .collect() - }) - .unwrap_or_default() + options + .values_of("namespace-bindings") + .map(|values| { + values + .map(|value| { + let (id, uuid) = value.split_once(':').unwrap(); + + let uuid = uuid::Uuid::parse_str(uuid).unwrap(); + NamespaceId::from_external_id(id, uuid) + }) + .collect() + }) + .unwrap_or_default() } fn vault_secrets_options(options: &ArgMatches) -> Result { - let vault_url = options - .value_of("vault-url") - .ok_or_else(|| CliError::missing_argument("vault-url"))?; - let token = options - .value_of("vault-token") - .ok_or_else(|| CliError::missing_argument("vault-token"))?; - let mount_path = options - .value_of("vault-mount-path") - .ok_or_else(|| CliError::missing_argument("vault-mount-path"))?; - Ok(ChronicleSecretsOptions::stored_in_vault(&Url::parse(vault_url)?, token, mount_path)) + let vault_url = options + .value_of("vault-url") + .ok_or_else(|| CliError::missing_argument("vault-url"))?; + let token = options + .value_of("vault-token") + .ok_or_else(|| CliError::missing_argument("vault-token"))?; + let mount_path = options + .value_of("vault-mount-path") + .ok_or_else(|| CliError::missing_argument("vault-mount-path"))?; + Ok(ChronicleSecretsOptions::stored_in_vault(&Url::parse(vault_url)?, token, mount_path)) } #[cfg(not(feature = "devmode"))] async fn chronicle_signing(options: &ArgMatches) -> Result { - // Determine batcher configuration - - use std::path::PathBuf; - let batcher_options = match ( - options.get_one::("batcher-key-from-path"), - options.get_flag("batcher-key-from-vault"), - options.get_flag("batcher-key-generated"), - ) { - (Some(path), _, _) => ChronicleSecretsOptions::stored_at_path(path), - (_, true, _) => vault_secrets_options(options)?, - (_, _, true) => ChronicleSecretsOptions::generate_in_memory(), - _ => unreachable!("CLI should always set batcher key"), - }; - - let chronicle_options = match ( - options.get_one::("chronicle-key-from-path"), - options.get_flag("chronicle-key-from-vault"), - options.get_flag("chronicle-key-generated"), - ) { - (Some(path), _, _) => ChronicleSecretsOptions::stored_at_path(path), - (_, true, _) => vault_secrets_options(options)?, - (_, _, true) => ChronicleSecretsOptions::generate_in_memory(), - _ => unreachable!("CLI should always set chronicle key"), - }; - - Ok(ChronicleSigning::new( - chronicle_secret_names(), - vec![ - (CHRONICLE_NAMESPACE.to_string(), chronicle_options), - (BATCHER_NAMESPACE.to_string(), batcher_options), - ], - ) - .await?) + // Determine batcher configuration + + use std::path::PathBuf; + let batcher_options = match ( + options.get_one::("batcher-key-from-path"), + options.get_flag("batcher-key-from-vault"), + options.get_flag("batcher-key-generated"), + ) { + (Some(path), _, _) => ChronicleSecretsOptions::stored_at_path(path), + (_, true, _) => vault_secrets_options(options)?, + (_, _, true) => ChronicleSecretsOptions::generate_in_memory(), + _ => unreachable!("CLI should always set batcher key"), + }; + + let chronicle_options = match ( + options.get_one::("chronicle-key-from-path"), + options.get_flag("chronicle-key-from-vault"), + options.get_flag("chronicle-key-generated"), + ) { + (Some(path), _, _) => ChronicleSecretsOptions::stored_at_path(path), + (_, true, _) => vault_secrets_options(options)?, + (_, _, true) => ChronicleSecretsOptions::generate_in_memory(), + _ => unreachable!("CLI should always set chronicle key"), + }; + + Ok(ChronicleSigning::new( + chronicle_secret_names(), + vec![ + (CHRONICLE_NAMESPACE.to_string(), chronicle_options), + (BATCHER_NAMESPACE.to_string(), batcher_options), + ], + ) + .await?) } #[cfg(feature = "devmode")] async fn chronicle_signing(_options: &ArgMatches) -> Result { - Ok(ChronicleSigning::new( - chronicle_secret_names(), - vec![ - (CHRONICLE_NAMESPACE.to_string(), ChronicleSecretsOptions::generate_in_memory()), - (BATCHER_NAMESPACE.to_string(), ChronicleSecretsOptions::generate_in_memory()), - ], - ) - .await?) + Ok(ChronicleSigning::new( + chronicle_secret_names(), + vec![ + (CHRONICLE_NAMESPACE.to_string(), ChronicleSecretsOptions::generate_in_memory()), + (BATCHER_NAMESPACE.to_string(), ChronicleSecretsOptions::generate_in_memory()), + ], + ) + .await?) } #[cfg(not(feature = "devmode"))] pub async fn api( - pool: &ConnectionPool, - options: &ArgMatches, - policy_address: Option, - liveness_check_interval: Option, + pool: &ConnectionPool, + options: &ArgMatches, + policy_address: Option, + liveness_check_interval: Option, ) -> Result { - let ledger = ledger(options).await?; - - Ok(Api::new( - pool.clone(), - ledger, - UniqueUuid, - chronicle_signing(options).await?, - namespace_bindings(options), - policy_address, - liveness_check_interval, - ) - .await?) + let ledger = ledger(options).await?; + + Ok(Api::new( + pool.clone(), + ledger, + UniqueUuid, + chronicle_signing(options).await?, + namespace_bindings(options), + policy_address, + liveness_check_interval, + ) + .await?) } #[cfg(feature = "devmode")] pub async fn api( - pool: &ConnectionPool, - options: &ArgMatches, - remote_opa: Option, - liveness_check_interval: Option, -) -> Result { - use protocol_substrate::PolkadotConfig; - - let embedded_tp = in_mem_ledger(options).await?; - - Ok(Api::new( - pool.clone(), - embedded_tp.connect_chronicle::().await?, - UniqueUuid, - chronicle_signing(options).await?, - vec![], - remote_opa, - liveness_check_interval, - ) - .await?) + pool: &ConnectionPool, + options: &ArgMatches, + remote_opa: Option, + liveness_check_interval: Option, +) -> Result { + use protocol_substrate::PolkadotConfig; + + let embedded_tp = in_mem_ledger(options).await?; + + Ok(Api::new( + pool.clone(), + embedded_tp.connect_chronicle::().await?, + UniqueUuid, + chronicle_signing(options).await?, + vec![], + remote_opa, + liveness_check_interval, + ) + .await?) } fn construct_db_uri(matches: &ArgMatches) -> String { - fn encode(string: &str) -> String { - use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; - utf8_percent_encode(string, NON_ALPHANUMERIC).to_string() - } - - let password = match std::env::var("PGPASSWORD") { - Ok(password) => { - debug!("PGPASSWORD is set, using for DB connection"); - format!(":{}", encode(password.as_str())) - }, - Err(_) => { - debug!("PGPASSWORD is not set, omitting for DB connection"); - String::new() - }, - }; - - format!( - "postgresql://{}{}@{}:{}/{}", - encode( - matches - .value_of("database-username") - .expect("CLI should always set database user") - ), - password, - encode(matches.value_of("database-host").expect("CLI should always set database host")), - encode(matches.value_of("database-port").expect("CLI should always set database port")), - encode(matches.value_of("database-name").expect("CLI should always set database name")) - ) + fn encode(string: &str) -> String { + use percent_encoding::{NON_ALPHANUMERIC, utf8_percent_encode}; + utf8_percent_encode(string, NON_ALPHANUMERIC).to_string() + } + + let password = match std::env::var("PGPASSWORD") { + Ok(password) => { + debug!("PGPASSWORD is set, using for DB connection"); + format!(":{}", encode(password.as_str())) + } + Err(_) => { + debug!("PGPASSWORD is not set, omitting for DB connection"); + String::new() + } + }; + + format!( + "postgresql://{}{}@{}:{}/{}", + encode( + matches + .value_of("database-username") + .expect("CLI should always set database user") + ), + password, + encode(matches.value_of("database-host").expect("CLI should always set database host")), + encode(matches.value_of("database-port").expect("CLI should always set database port")), + encode(matches.value_of("database-name").expect("CLI should always set database name")) + ) } #[derive(Debug, Clone)] pub enum ConfiguredOpa { - Embedded(ExecutorContext), - Remote(ExecutorContext, OpaSettings), - Url(ExecutorContext), + Embedded(ExecutorContext), + Remote(ExecutorContext, OpaSettings), + Url(ExecutorContext), } impl ConfiguredOpa { - pub fn context(&self) -> &ExecutorContext { - match self { - ConfiguredOpa::Embedded(context) => context, - ConfiguredOpa::Remote(context, _) => context, - ConfiguredOpa::Url(context) => context, - } - } - - pub fn remote_settings(&self) -> Option { - match self { - ConfiguredOpa::Embedded(_) => None, - ConfiguredOpa::Remote(_, settings) => Some(settings.policy_address), - ConfiguredOpa::Url(_) => None, - } - } + pub fn context(&self) -> &ExecutorContext { + match self { + ConfiguredOpa::Embedded(context) => context, + ConfiguredOpa::Remote(context, _) => context, + ConfiguredOpa::Url(context) => context, + } + } + + pub fn remote_settings(&self) -> Option { + match self { + ConfiguredOpa::Embedded(_) => None, + ConfiguredOpa::Remote(_, settings) => Some(settings.policy_address), + ConfiguredOpa::Url(_) => None, + } + } } /// If embedded-opa-policy is set, we will use the embedded policy, otherwise we @@ -383,10 +382,10 @@ impl ConfiguredOpa { #[cfg(feature = "devmode")] #[allow(unused_variables)] async fn configure_opa(options: &ArgMatches) -> Result { - let (default_policy_name, entrypoint) = - ("allow_transactions", "allow_transactions.allowed_users"); - let opa = opa_executor_from_embedded_policy(default_policy_name, entrypoint).await?; - Ok(ConfiguredOpa::Embedded(opa)) + let (default_policy_name, entrypoint) = + ("allow_transactions", "allow_transactions.allowed_users"); + let opa = opa_executor_from_embedded_policy(default_policy_name, entrypoint).await?; + Ok(ConfiguredOpa::Embedded(opa)) } // Check if the `embedded-opa-policy` flag is present in the CLI options. @@ -410,276 +409,276 @@ async fn configure_opa(options: &ArgMatches) -> Result #[cfg(not(feature = "devmode"))] #[instrument(skip(options))] async fn configure_opa(options: &ArgMatches) -> Result { - if options.is_present("embedded-opa-policy") { - let (default_policy_name, entrypoint) = - ("allow_transactions", "allow_transactions.allowed_users"); - let opa = opa_executor_from_embedded_policy(default_policy_name, entrypoint).await?; - tracing::warn!( + if options.is_present("embedded-opa-policy") { + let (default_policy_name, entrypoint) = + ("allow_transactions", "allow_transactions.allowed_users"); + let opa = opa_executor_from_embedded_policy(default_policy_name, entrypoint).await?; + tracing::warn!( "Chronicle operating in an insecure mode with an embedded default OPA policy" ); - Ok(ConfiguredOpa::Embedded(opa)) - } else if let Some(url) = options.value_of("opa-bundle-address") { - let (policy_name, entrypoint) = ( - options.value_of("opa-policy-name").unwrap(), - options.value_of("opa-policy-entrypoint").unwrap(), - ); - let opa = self::opa::opa_executor_from_url(url, policy_name, entrypoint).await?; - tracing::info!("Chronicle operating with OPA policy from URL"); - - Ok(ConfiguredOpa::Url(opa)) - } else { - let (opa, settings) = self::opa::opa_executor_from_substrate_state( - &ChronicleSubstrateClient::connect_socket_addr(validator_address(options)?[0]).await?, - &protocol_substrate_opa::OpaSubstrateClient::connect_socket_addr( - validator_address(options)?[0], - ) - .await?, - ) - .await?; - - if let Some(settings) = settings { - tracing::info!(use_on_chain_opa= ?settings, "Chronicle operating in secure mode with on chain OPA policy"); - Ok(ConfiguredOpa::Remote(opa, settings)) - } else { - tracing::warn!( + Ok(ConfiguredOpa::Embedded(opa)) + } else if let Some(url) = options.value_of("opa-bundle-address") { + let (policy_name, entrypoint) = ( + options.value_of("opa-policy-name").unwrap(), + options.value_of("opa-policy-entrypoint").unwrap(), + ); + let opa = self::opa::opa_executor_from_url(url, policy_name, entrypoint).await?; + tracing::info!("Chronicle operating with OPA policy from URL"); + + Ok(ConfiguredOpa::Url(opa)) + } else { + let (opa, settings) = self::opa::opa_executor_from_substrate_state( + &ChronicleSubstrateClient::connect_socket_addr(validator_address(options)?[0]).await?, + &protocol_substrate_opa::OpaSubstrateClient::connect_socket_addr( + validator_address(options)?[0], + ) + .await?, + ) + .await?; + + if let Some(settings) = settings { + tracing::info!(use_on_chain_opa= ?settings, "Chronicle operating in secure mode with on chain OPA policy"); + Ok(ConfiguredOpa::Remote(opa, settings)) + } else { + tracing::warn!( "Chronicle operating in an insecure mode with an embedded default OPA policy" ); - tracing::warn!(use_on_chain_opa= ?settings, "Chronicle operating in secure mode with on chain OPA policy"); - let (default_policy_name, entrypoint) = - ("allow_transactions", "allow_transactions.allowed_users"); - let opa = opa_executor_from_embedded_policy(default_policy_name, entrypoint).await?; - - Ok(ConfiguredOpa::Embedded(opa)) - } - } + tracing::warn!(use_on_chain_opa= ?settings, "Chronicle operating in secure mode with on chain OPA policy"); + let (default_policy_name, entrypoint) = + ("allow_transactions", "allow_transactions.allowed_users"); + let opa = opa_executor_from_embedded_policy(default_policy_name, entrypoint).await?; + + Ok(ConfiguredOpa::Embedded(opa)) + } + } } /// If `--liveness-check` is set, we use either the interval in seconds provided or the default of /// 1800. Otherwise, we use `None` to disable the depth charge. fn configure_depth_charge(matches: &ArgMatches) -> Option { - if let Some(serve_api_matches) = matches.subcommand_matches("serve-api") { - if let Some(interval) = serve_api_matches.value_of("liveness-check") { - let parsed_interval = interval.parse::().unwrap_or_else(|e| { - warn!("Failed to parse '--liveness-check' value: {e}"); - 1800 - }); - - if parsed_interval == 1800 { - debug!("Using default liveness health check interval value: 1800"); - } else { - debug!("Using custom liveness health check interval value: {parsed_interval}"); - } - return Some(parsed_interval); - } - } - debug!("Liveness health check disabled"); - None + if let Some(serve_api_matches) = matches.subcommand_matches("serve-api") { + if let Some(interval) = serve_api_matches.value_of("liveness-check") { + let parsed_interval = interval.parse::().unwrap_or_else(|e| { + warn!("Failed to parse '--liveness-check' value: {e}"); + 1800 + }); + + if parsed_interval == 1800 { + debug!("Using default liveness health check interval value: 1800"); + } else { + debug!("Using custom liveness health check interval value: {parsed_interval}"); + } + return Some(parsed_interval); + } + } + debug!("Liveness health check disabled"); + None } #[instrument(skip(gql, cli))] async fn execute_subcommand( - gql: ChronicleGraphQl, - domain: &ChronicleDomainDef, - cli: CliModel, + gql: ChronicleGraphQl, + domain: &ChronicleDomainDef, + cli: CliModel, ) -> Result<(ApiResponse, ApiDispatch), CliError> -where - Query: ObjectType + Copy, - Mutation: ObjectType + Copy, + where + Query: ObjectType + Copy, + Mutation: ObjectType + Copy, { - dotenvy::dotenv().ok(); - - let matches = cli.as_cmd().get_matches(); - - let pool = pool_remote(&construct_db_uri(&matches)).await?; - - let opa = configure_opa(&matches).await?; - - let liveness_check_interval = configure_depth_charge(&matches); - - let api = api(&pool, &matches, opa.remote_settings(), liveness_check_interval).await?; - let ret_api = api.clone(); - - if let Some(matches) = matches.subcommand_matches("serve-api") { - let interface = match matches.get_many::("interface") { - Some(interface_args) => { - let mut addrs = Vec::new(); - for interface_arg in interface_args { - addrs.extend(interface_arg.to_socket_addrs()?); - } - Some(addrs) - }, - None => None, - }; - - let arrow_interface = match matches.get_many::("arrow-interface") { - Some(interface_args) => { - let mut addrs = Vec::new(); - for interface_arg in interface_args { - addrs.extend(interface_arg.to_socket_addrs()?); - } - Some(addrs) - }, - None => None, - }; - - let jwks_uri = if let Some(uri) = matches.value_of("jwks-address") { - Some(JwksUri::new(Url::from_str(uri)?)) - } else { - None - }; - - let userinfo_uri = if let Some(uri) = matches.value_of("userinfo-address") { - Some(UserInfoUri::new(Url::from_str(uri)?)) - } else { - None - }; - - let allow_anonymous = !matches.is_present("require-auth"); - - let id_claims = matches.get_many::("id-claims").map(|id_claims| { - let mut id_keys = BTreeSet::new(); - for id_claim in id_claims { - id_keys.extend(id_claim.split_whitespace().map(|s| s.to_string())); - } - id_keys - }); - - let mut jwt_must_claim: HashMap = HashMap::new(); - for (name, value) in std::env::vars() { - if let Some(name) = name.strip_prefix("JWT_MUST_CLAIM_") { - jwt_must_claim.insert(name.to_lowercase(), value); - } - } - if let Some(mut claims) = matches.get_many::("jwt-must-claim") { - while let (Some(name), Some(value)) = (claims.next(), claims.next()) { - jwt_must_claim.insert(name.clone(), value.clone()); - } - } - - let endpoints: Vec = - matches.get_many("offer-endpoints").unwrap().map(String::clone).collect(); - - let security_conf = SecurityConf::new( - jwks_uri, - userinfo_uri, - id_claims, - jwt_must_claim.clone(), - allow_anonymous, - opa.context().clone(), - ); + dotenvy::dotenv().ok(); - let arrow = arrow_api_server( - domain, - &api, - &pool, - arrow_interface, - security_conf.as_endpoint_conf(30), - 1000, - 100, - ); + let matches = cli.as_cmd().get_matches(); - let serve_graphql = endpoints.contains(&"graphql".to_string()); - let serve_data = endpoints.contains(&"data".to_string()); - - let gql = graphql_api_server( - &api, - &pool, - gql, - interface, - &security_conf, - serve_graphql, - serve_data, - ); + let pool = pool_remote(&construct_db_uri(&matches)).await?; + + let opa = configure_opa(&matches).await?; + + let liveness_check_interval = configure_depth_charge(&matches); - tokio::task::spawn(async move { - use async_signals::Signals; - - let mut signals = Signals::new(vec![libc::SIGHUP, libc::SIGINT]).unwrap(); - - signals.next().await; - chronicle_arrow::trigger_shutdown(); - api::chronicle_graphql::trigger_shutdown(); - }); - - let (gql_result, arrow_result) = tokio::join!(gql, arrow); - - if let Err(e) = gql_result { - return Err(e.into()); - } - if let Err(e) = arrow_result { - return Err(e.into()); - } - - Ok((ApiResponse::Unit, ret_api)) - } else if let Some(matches) = matches.subcommand_matches("import") { - let data = if let Some(url) = matches.value_of("url") { - let data = load_bytes_from_url(url).await?; - info!("Loaded import data from {:?}", url); - data - } else { - if std::io::stdin().is_terminal() { - eprintln!("Attempting to import data from standard input, press Ctrl-D to finish."); - } - info!("Attempting to read import data from stdin..."); - let data = load_bytes_from_stdin()?; - info!("Loaded {} bytes of import data from stdin", data.len()); - data - }; - - let data = std::str::from_utf8(&data)?; - - if data.trim().is_empty() { - eprintln!("Import data is empty, nothing to import"); - return Ok((ApiResponse::Unit, ret_api)); - } - - let json_array = serde_json::from_str::>(data)?; - - let mut operations = Vec::new(); - for value in json_array.into_iter() { - let op = ChronicleOperation::from_json(&value) - .await - .expect("Failed to parse imported JSON-LD to ChronicleOperation"); - operations.push(op); - } - - info!("Loading import data complete"); - - let identity = AuthId::chronicle(); - - let response = api.handle_import_command(identity, operations).await?; - - Ok((response, ret_api)) - } else if let Some(cmd) = cli.matches(&matches)? { - let identity = AuthId::chronicle(); - Ok((api.dispatch(cmd, identity).await?, ret_api)) - } else { - Ok((ApiResponse::Unit, ret_api)) - } + let api = api(&pool, &matches, opa.remote_settings(), liveness_check_interval).await?; + let ret_api = api.clone(); + + if let Some(matches) = matches.subcommand_matches("serve-api") { + let interface = match matches.get_many::("interface") { + Some(interface_args) => { + let mut addrs = Vec::new(); + for interface_arg in interface_args { + addrs.extend(interface_arg.to_socket_addrs()?); + } + Some(addrs) + } + None => None, + }; + + let arrow_interface = match matches.get_many::("arrow-interface") { + Some(interface_args) => { + let mut addrs = Vec::new(); + for interface_arg in interface_args { + addrs.extend(interface_arg.to_socket_addrs()?); + } + Some(addrs) + } + None => None, + }; + + let jwks_uri = if let Some(uri) = matches.value_of("jwks-address") { + Some(JwksUri::new(Url::from_str(uri)?)) + } else { + None + }; + + let userinfo_uri = if let Some(uri) = matches.value_of("userinfo-address") { + Some(UserInfoUri::new(Url::from_str(uri)?)) + } else { + None + }; + + let allow_anonymous = !matches.is_present("require-auth"); + + let id_claims = matches.get_many::("id-claims").map(|id_claims| { + let mut id_keys = BTreeSet::new(); + for id_claim in id_claims { + id_keys.extend(id_claim.split_whitespace().map(|s| s.to_string())); + } + id_keys + }); + + let mut jwt_must_claim: HashMap = HashMap::new(); + for (name, value) in std::env::vars() { + if let Some(name) = name.strip_prefix("JWT_MUST_CLAIM_") { + jwt_must_claim.insert(name.to_lowercase(), value); + } + } + if let Some(mut claims) = matches.get_many::("jwt-must-claim") { + while let (Some(name), Some(value)) = (claims.next(), claims.next()) { + jwt_must_claim.insert(name.clone(), value.clone()); + } + } + + let endpoints: Vec = + matches.get_many("offer-endpoints").unwrap().map(String::clone).collect(); + + let security_conf = SecurityConf::new( + jwks_uri, + userinfo_uri, + id_claims, + jwt_must_claim.clone(), + allow_anonymous, + opa.context().clone(), + ); + + let arrow = arrow_api_server( + domain, + &api, + &pool, + arrow_interface, + security_conf.as_endpoint_conf(30), + 1000, + 100, + ); + + let serve_graphql = endpoints.contains(&"graphql".to_string()); + let serve_data = endpoints.contains(&"data".to_string()); + + let gql = graphql_api_server( + &api, + &pool, + gql, + interface, + &security_conf, + serve_graphql, + serve_data, + ); + + tokio::task::spawn(async move { + use async_signals::Signals; + + let mut signals = Signals::new(vec![libc::SIGHUP, libc::SIGINT]).unwrap(); + + signals.next().await; + chronicle_arrow::trigger_shutdown(); + api::chronicle_graphql::trigger_shutdown(); + }); + + let (gql_result, arrow_result) = tokio::join!(gql, arrow); + + if let Err(e) = gql_result { + return Err(e.into()); + } + if let Err(e) = arrow_result { + return Err(e.into()); + } + + Ok((ApiResponse::Unit, ret_api)) + } else if let Some(matches) = matches.subcommand_matches("import") { + let data = if let Some(url) = matches.value_of("url") { + let data = load_bytes_from_url(url).await?; + info!("Loaded import data from {:?}", url); + data + } else { + if std::io::stdin().is_terminal() { + eprintln!("Attempting to import data from standard input, press Ctrl-D to finish."); + } + info!("Attempting to read import data from stdin..."); + let data = load_bytes_from_stdin()?; + info!("Loaded {} bytes of import data from stdin", data.len()); + data + }; + + let data = std::str::from_utf8(&data)?; + + if data.trim().is_empty() { + eprintln!("Import data is empty, nothing to import"); + return Ok((ApiResponse::Unit, ret_api)); + } + + let json_array = serde_json::from_str::>(data)?; + + let mut operations = Vec::new(); + for value in json_array.into_iter() { + let op = ChronicleOperation::from_json(&value) + .await + .expect("Failed to parse imported JSON-LD to ChronicleOperation"); + operations.push(op); + } + + info!("Loading import data complete"); + + let identity = AuthId::chronicle(); + + let response = api.handle_import_command(identity, operations).await?; + + Ok((response, ret_api)) + } else if let Some(cmd) = cli.matches(&matches)? { + let identity = AuthId::chronicle(); + Ok((api.dispatch(cmd, identity).await?, ret_api)) + } else { + Ok((ApiResponse::Unit, ret_api)) + } } fn get_namespace(matches: &ArgMatches) -> NamespaceId { - let namespace_id = matches.value_of("namespace-id").unwrap(); - let namespace_uuid = matches.value_of("namespace-uuid").unwrap(); - let uuid = uuid::Uuid::try_parse(namespace_uuid) - .unwrap_or_else(|_| panic!("cannot parse namespace UUID: {}", namespace_uuid)); - NamespaceId::from_external_id(namespace_id, uuid) + let namespace_id = matches.value_of("namespace-id").unwrap(); + let namespace_uuid = matches.value_of("namespace-uuid").unwrap(); + let uuid = uuid::Uuid::try_parse(namespace_uuid) + .unwrap_or_else(|_| panic!("cannot parse namespace UUID: {}", namespace_uuid)); + NamespaceId::from_external_id(namespace_id, uuid) } async fn config_and_exec( - gql: ChronicleGraphQl, - domain: &ChronicleDomainDef, - model: CliModel, + gql: ChronicleGraphQl, + domain: &ChronicleDomainDef, + model: CliModel, ) -> Result<(), CliError> -where - Query: ObjectType + Copy, - Mutation: ObjectType + Copy, + where + Query: ObjectType + Copy, + Mutation: ObjectType + Copy, { - use colored_json::prelude::*; + use colored_json::prelude::*; - let response = execute_subcommand(gql, domain, model).await?; + let response = execute_subcommand(gql, domain, model).await?; - match response { + match response { ( ApiResponse::Submission { subject, @@ -745,8 +744,8 @@ where .unwrap() ); } - (ApiResponse::AlreadyRecordedAll, _api) => { - println!("Import will not result in any data changes"); + (ApiResponse::AlreadyRecordedAll, _api) => { + println!("Import will not result in any data changes"); } (ApiResponse::ImportSubmitted { prov, tx_id }, api) => { let mut tx_notifications = api.notify_commit.subscribe(); @@ -800,60 +799,59 @@ where "DepthChargeSubmitted is an unexpected API response for transaction: {tx_id}. Depth charge not implemented." ), }; - Ok(()) + Ok(()) } fn print_completions(gen: G, app: &mut Command) { - generate(gen, app, app.get_name().to_string(), &mut io::stdout()); + generate(gen, app, app.get_name().to_string(), &mut io::stdout()); } pub async fn bootstrap( - domain: ChronicleDomainDef, - gql: ChronicleGraphQl, + domain: ChronicleDomainDef, + gql: ChronicleGraphQl, ) where - Query: ObjectType + 'static + Copy, - Mutation: ObjectType + 'static + Copy, + Query: ObjectType + 'static + Copy, + Mutation: ObjectType + 'static + Copy, { - let matches = cli(domain.clone()).as_cmd().get_matches(); - - if let Some(generator) = matches.subcommand_matches("completions") { - let shell = generator.get_one::("shell").unwrap().parse::().unwrap(); - print_completions(shell.to_owned(), &mut cli(domain.clone()).as_cmd()); - std::process::exit(0); - } - - if matches.subcommand_matches("export-schema").is_some() { - print!("{}", gql.exportable_schema()); - std::process::exit(0); - } - chronicle_telemetry::telemetry( - matches - .get_one::("instrument") - .map(|s| s.to_socket_addrs().expect("Could not parse as socketaddr").next().unwrap()), - if matches.contains_id("console-logging") { - match matches.get_one::("console-logging") { - Some(level) => match level.as_str() { - "pretty" => ConsoleLogging::Pretty, - "json" => ConsoleLogging::Json, - _ => ConsoleLogging::Off, - }, - _ => ConsoleLogging::Off, - } - } else if matches.subcommand_name() == Some("serve-api") { - ConsoleLogging::Pretty - } else { - ConsoleLogging::Off - }, - ); - - config_and_exec(gql, &domain, domain.clone().into()) - .await - .map_err(|e| { - error!(?e, "Api error"); - e.into_ufe().print(); - std::process::exit(1); - }) - .ok(); - - std::process::exit(0); + let matches = cli(domain.clone()).as_cmd().get_matches(); + + if let Some(generator) = matches.subcommand_matches("completions") { + let shell = generator.get_one::("shell").unwrap().parse::().unwrap(); + print_completions(shell.to_owned(), &mut cli(domain.clone()).as_cmd()); + std::process::exit(0); + } + + if matches.subcommand_matches("export-schema").is_some() { + print!("{}", gql.exportable_schema()); + std::process::exit(0); + } + chronicle_telemetry::telemetry( + matches + .get_one::("instrument").is_some(), + if matches.contains_id("console-logging") { + match matches.get_one::("console-logging") { + Some(level) => match level.as_str() { + "pretty" => ConsoleLogging::Pretty, + "json" => ConsoleLogging::Json, + _ => ConsoleLogging::Off, + }, + _ => ConsoleLogging::Off, + } + } else if matches.subcommand_name() == Some("serve-api") { + ConsoleLogging::Pretty + } else { + ConsoleLogging::Off + }, + ); + + config_and_exec(gql, &domain, domain.clone().into()) + .await + .map_err(|e| { + error!(?e, "Api error"); + e.into_ufe().print(); + std::process::exit(1); + }) + .ok(); + + std::process::exit(0); } diff --git a/crates/chronicle/src/bootstrap/opa.rs b/crates/chronicle/src/bootstrap/opa.rs index 6c4a9651d..bf45300ca 100644 --- a/crates/chronicle/src/bootstrap/opa.rs +++ b/crates/chronicle/src/bootstrap/opa.rs @@ -1,462 +1,465 @@ use clap::ArgMatches; +use opa::bundle::Bundle; +use tracing::{debug, error, info, instrument}; use common::opa::{ - std::{load_bytes_from_url, ExecutorContext, PolicyLoader, PolicyLoaderError}, - OpaSettings, + OpaSettings, + std::{ExecutorContext, load_bytes_from_url, PolicyLoader, PolicyLoaderError}, }; -use opa::bundle::Bundle; use protocol_substrate::SubxtClientError; use protocol_substrate_chronicle::{ChronicleSubstrateClient, SettingsLoader}; -use protocol_substrate_opa::{loader::SubstratePolicyLoader, policy_hash, OpaSubstrateClient}; -use tracing::{debug, error, info, instrument}; +use protocol_substrate_opa::{loader::SubstratePolicyLoader, OpaSubstrateClient, policy_hash}; use super::CliError; /// OPA policy loader for policies passed via CLI or embedded in Chronicle #[derive(Clone, Default)] pub struct CliPolicyLoader { - address: String, - rule_name: String, - entrypoint: String, - policy: Vec, + address: String, + rule_name: String, + entrypoint: String, + policy: Vec, } impl CliPolicyLoader { - pub fn new() -> Self { - Self { ..Default::default() } - } - - #[instrument(level = "trace", skip(self), ret)] - async fn get_policy_from_file(&mut self) -> Result, PolicyLoaderError> { - let bundle = Bundle::from_file(self.get_address())?; - - self.load_policy_from_bundle(&bundle)?; - - Ok(self.get_policy().to_vec()) - } - - /// Create a loaded [`CliPolicyLoader`] from name of an embedded dev policy and entrypoint - pub fn from_embedded_policy(policy: &str, entrypoint: &str) -> Result { - if let Some(file) = common::opa::std::EmbeddedOpaPolicies::get("bundle.tar.gz") { - let bytes = file.data.as_ref(); - let bundle = Bundle::from_bytes(bytes)?; - let mut loader = CliPolicyLoader::new(); - loader.set_rule_name(policy); - loader.set_entrypoint(entrypoint); - loader.load_policy_from_bundle(&bundle)?; - Ok(loader) - } else { - Err(PolicyLoaderError::EmbeddedOpaPolicies) - } - } - - /// Create a loaded [`CliPolicyLoader`] from an OPA policy's bytes and entrypoint - pub fn from_policy_bytes( - policy: &str, - entrypoint: &str, - bytes: &[u8], - ) -> Result { - let mut loader = CliPolicyLoader::new(); - loader.set_rule_name(policy); - loader.set_entrypoint(entrypoint); - let bundle = Bundle::from_bytes(bytes)?; - loader.load_policy_from_bundle(&bundle)?; - Ok(loader) - } + pub fn new() -> Self { + Self { ..Default::default() } + } + + #[instrument(level = "trace", skip(self), ret)] + async fn get_policy_from_file(&mut self) -> Result, PolicyLoaderError> { + let bundle = Bundle::from_file(self.get_address())?; + + self.load_policy_from_bundle(&bundle)?; + + Ok(self.get_policy().to_vec()) + } + + /// Create a loaded [`CliPolicyLoader`] from name of an embedded dev policy and entrypoint + pub fn from_embedded_policy(policy: &str, entrypoint: &str) -> Result { + if let Some(file) = common::opa::std::EmbeddedOpaPolicies::get("bundle.tar.gz") { + let bytes = file.data.as_ref(); + let bundle = Bundle::from_bytes(bytes)?; + let mut loader = CliPolicyLoader::new(); + loader.set_rule_name(policy); + loader.set_entrypoint(entrypoint); + loader.load_policy_from_bundle(&bundle)?; + Ok(loader) + } else { + Err(PolicyLoaderError::EmbeddedOpaPolicies) + } + } + + /// Create a loaded [`CliPolicyLoader`] from an OPA policy's bytes and entrypoint + pub fn from_policy_bytes( + policy: &str, + entrypoint: &str, + bytes: &[u8], + ) -> Result { + let mut loader = CliPolicyLoader::new(); + loader.set_rule_name(policy); + loader.set_entrypoint(entrypoint); + let bundle = Bundle::from_bytes(bytes)?; + loader.load_policy_from_bundle(&bundle)?; + Ok(loader) + } } #[async_trait::async_trait] impl PolicyLoader for CliPolicyLoader { - fn set_address(&mut self, address: &str) { - self.address = address.to_owned() - } - - fn set_rule_name(&mut self, name: &str) { - self.rule_name = name.to_owned() - } - - fn set_entrypoint(&mut self, entrypoint: &str) { - self.entrypoint = entrypoint.to_owned() - } - - fn get_address(&self) -> &str { - &self.address - } - - fn get_rule_name(&self) -> &str { - &self.rule_name - } - - fn get_entrypoint(&self) -> &str { - &self.entrypoint - } - - fn get_policy(&self) -> &[u8] { - &self.policy - } - - fn load_policy_from_bytes(&mut self, policy: &[u8]) { - self.policy = policy.to_vec() - } - - async fn load_policy(&mut self) -> Result<(), PolicyLoaderError> { - self.policy = self.get_policy_from_file().await?; - Ok(()) - } - - fn hash(&self) -> String { - hex::encode(policy_hash(&self.policy)) - } + fn set_address(&mut self, address: &str) { + self.address = address.to_owned() + } + + fn set_rule_name(&mut self, name: &str) { + self.rule_name = name.to_owned() + } + + fn set_entrypoint(&mut self, entrypoint: &str) { + self.entrypoint = entrypoint.to_owned() + } + + fn get_address(&self) -> &str { + &self.address + } + + fn get_rule_name(&self) -> &str { + &self.rule_name + } + + fn get_entrypoint(&self) -> &str { + &self.entrypoint + } + + fn get_policy(&self) -> &[u8] { + &self.policy + } + + fn load_policy_from_bytes(&mut self, policy: &[u8]) { + self.policy = policy.to_vec() + } + + async fn load_policy(&mut self) -> Result<(), PolicyLoaderError> { + self.policy = self.get_policy_from_file().await?; + Ok(()) + } + + fn hash(&self) -> String { + hex::encode(policy_hash(&self.policy)) + } } #[derive(Clone, Default)] pub struct UrlPolicyLoader { - policy_id: String, - address: String, - policy: Vec, - entrypoint: String, + policy_id: String, + address: String, + policy: Vec, + entrypoint: String, } impl UrlPolicyLoader { - pub fn new(url: &str, policy_id: &str, entrypoint: &str) -> Self { - Self { - address: url.into(), - policy_id: policy_id.to_owned(), - entrypoint: entrypoint.to_owned(), - ..Default::default() - } - } + pub fn new(url: &str, policy_id: &str, entrypoint: &str) -> Self { + Self { + address: url.into(), + policy_id: policy_id.to_owned(), + entrypoint: entrypoint.to_owned(), + ..Default::default() + } + } } #[async_trait::async_trait] impl PolicyLoader for UrlPolicyLoader { - fn set_address(&mut self, address: &str) { - self.address = address.to_owned(); - } + fn set_address(&mut self, address: &str) { + self.address = address.to_owned(); + } - fn set_rule_name(&mut self, name: &str) { - self.policy_id = name.to_owned(); - } + fn set_rule_name(&mut self, name: &str) { + self.policy_id = name.to_owned(); + } - fn set_entrypoint(&mut self, entrypoint: &str) { - self.entrypoint = entrypoint.to_owned(); - } + fn set_entrypoint(&mut self, entrypoint: &str) { + self.entrypoint = entrypoint.to_owned(); + } - fn get_address(&self) -> &str { - &self.address - } + fn get_address(&self) -> &str { + &self.address + } - fn get_rule_name(&self) -> &str { - &self.policy_id - } + fn get_rule_name(&self) -> &str { + &self.policy_id + } - fn get_entrypoint(&self) -> &str { - &self.entrypoint - } + fn get_entrypoint(&self) -> &str { + &self.entrypoint + } - fn get_policy(&self) -> &[u8] { - &self.policy - } + fn get_policy(&self) -> &[u8] { + &self.policy + } - fn load_policy_from_bytes(&mut self, policy: &[u8]) { - self.policy = policy.to_vec(); - } + fn load_policy_from_bytes(&mut self, policy: &[u8]) { + self.policy = policy.to_vec(); + } - async fn load_policy(&mut self) -> Result<(), PolicyLoaderError> { - let address = &self.address; - let bundle = load_bytes_from_url(address).await?; + async fn load_policy(&mut self) -> Result<(), PolicyLoaderError> { + let address = &self.address; + let bundle = load_bytes_from_url(address).await?; - info!(loaded_policy_bytes=?bundle.len(), "Loaded policy bundle"); + info!(loaded_policy_bytes=?bundle.len(), "Loaded policy bundle"); - if bundle.is_empty() { - error!("Policy not found: {}", self.get_rule_name()); - return Err(PolicyLoaderError::MissingPolicy(self.get_rule_name().to_string())); - } + if bundle.is_empty() { + error!("Policy not found: {}", self.get_rule_name()); + return Err(PolicyLoaderError::MissingPolicy(self.get_rule_name().to_string())); + } - self.load_policy_from_bundle(&Bundle::from_bytes(&*bundle)?) - } + self.load_policy_from_bundle(&Bundle::from_bytes(&*bundle)?) + } - fn hash(&self) -> String { - hex::encode(policy_hash(&self.policy)) - } + fn hash(&self) -> String { + hex::encode(policy_hash(&self.policy)) + } } trait SetRuleOptions { - fn rule_addr(&mut self, options: &ArgMatches) -> Result<(), CliError>; - fn rule_entrypoint(&mut self, options: &ArgMatches) -> Result<(), CliError>; - fn set_addr_and_entrypoint(&mut self, options: &ArgMatches) -> Result<(), CliError> { - self.rule_addr(options)?; - self.rule_entrypoint(options)?; - Ok(()) - } + fn rule_addr(&mut self, options: &ArgMatches) -> Result<(), CliError>; + fn rule_entrypoint(&mut self, options: &ArgMatches) -> Result<(), CliError>; + fn set_addr_and_entrypoint(&mut self, options: &ArgMatches) -> Result<(), CliError> { + self.rule_addr(options)?; + self.rule_entrypoint(options)?; + Ok(()) + } } impl SetRuleOptions for CliPolicyLoader { - fn rule_addr(&mut self, options: &ArgMatches) -> Result<(), CliError> { - if let Some(val) = options.get_one::("opa-rule") { - self.set_address(val); - Ok(()) - } else { - Err(CliError::MissingArgument { arg: "opa-rule".to_string() }) - } - } - - fn rule_entrypoint(&mut self, options: &ArgMatches) -> Result<(), CliError> { - if let Some(val) = options.get_one::("opa-entrypoint") { - self.set_entrypoint(val); - Ok(()) - } else { - Err(CliError::MissingArgument { arg: "opa-entrypoint".to_string() }) - } - } + fn rule_addr(&mut self, options: &ArgMatches) -> Result<(), CliError> { + if let Some(val) = options.get_one::("opa-rule") { + self.set_address(val); + Ok(()) + } else { + Err(CliError::MissingArgument { arg: "opa-rule".to_string() }) + } + } + + fn rule_entrypoint(&mut self, options: &ArgMatches) -> Result<(), CliError> { + if let Some(val) = options.get_one::("opa-entrypoint") { + self.set_entrypoint(val); + Ok(()) + } else { + Err(CliError::MissingArgument { arg: "opa-entrypoint".to_string() }) + } + } } #[instrument()] pub async fn opa_executor_from_embedded_policy( - policy_name: &str, - entrypoint: &str, + policy_name: &str, + entrypoint: &str, ) -> Result { - let loader = CliPolicyLoader::from_embedded_policy(policy_name, entrypoint)?; - Ok(ExecutorContext::from_loader(&loader)?) + let loader = CliPolicyLoader::from_embedded_policy(policy_name, entrypoint)?; + Ok(ExecutorContext::from_loader(&loader)?) } pub async fn read_opa_settings( - client: &ChronicleSubstrateClient, + client: &ChronicleSubstrateClient, ) -> Result, SubxtClientError> { - client.load_settings_from_storage().await + client.load_settings_from_storage().await } #[instrument(skip(chronicle_client, opa_client))] pub async fn opa_executor_from_substrate_state( - chronicle_client: &ChronicleSubstrateClient, - opa_client: &OpaSubstrateClient, + chronicle_client: &ChronicleSubstrateClient, + opa_client: &OpaSubstrateClient, ) -> Result<(ExecutorContext, Option), CliError> { - let opa_settings = read_opa_settings(chronicle_client).await?; - debug!(on_chain_opa_policy = ?opa_settings); - if let Some(opa_settings) = opa_settings { - let mut loader = SubstratePolicyLoader::new(opa_settings.clone(), opa_client); - loader.load_policy().await?; - - Ok((ExecutorContext::from_loader(&loader)?, Some(opa_settings))) - } else { - Err(CliError::NoOnChainSettings) - } + let opa_settings = read_opa_settings(chronicle_client).await?; + debug!(on_chain_opa_policy = ?opa_settings); + if let Some(opa_settings) = opa_settings { + let mut loader = SubstratePolicyLoader::new(opa_settings.clone(), opa_client); + loader.load_policy().await?; + + Ok((ExecutorContext::from_loader(&loader)?, Some(opa_settings))) + } else { + Err(CliError::NoOnChainSettings) + } } #[instrument()] pub async fn opa_executor_from_url( - url: &str, - policy_name: &str, - entrypoint: &str, + url: &str, + policy_name: &str, + entrypoint: &str, ) -> Result { - let mut loader = UrlPolicyLoader::new(url, policy_name, entrypoint); - loader.load_policy().await?; - Ok(ExecutorContext::from_loader(&loader)?) + let mut loader = UrlPolicyLoader::new(url, policy_name, entrypoint); + loader.load_policy().await?; + Ok(ExecutorContext::from_loader(&loader)?) } #[cfg(test)] mod tests { - use super::*; - use common::{ - identity::{AuthId, IdentityContext, JwtClaims, OpaData}, - opa::std::{EmbeddedOpaPolicies, OpaExecutor, OpaExecutorError, WasmtimeOpaExecutor}, - }; - use serde_json::Value; - use std::{collections::BTreeSet, io::Write}; - - fn chronicle_id() -> AuthId { - AuthId::chronicle() - } - - fn chronicle_user_opa_data() -> OpaData { - OpaData::Operation(IdentityContext::new( - AuthId::chronicle(), - Value::default(), - Value::default(), - )) - } - - fn allow_all_users() -> (String, String) { - let policy_name = "allow_transactions".to_string(); - let entrypoint = "allow_transactions/allowed_users".to_string(); - (policy_name, entrypoint) - } - - fn anonymous_user() -> AuthId { - AuthId::anonymous() - } - - fn anonymous_user_opa_data() -> OpaData { - OpaData::Operation(IdentityContext::new( - AuthId::anonymous(), - Value::default(), - Value::default(), - )) - } - - fn jwt_user() -> AuthId { - let claims = JwtClaims( - serde_json::json!({ + use std::{collections::BTreeSet, io::Write}; + + use serde_json::Value; + + use common::{ + identity::{AuthId, IdentityContext, JwtClaims, OpaData}, + opa::std::{EmbeddedOpaPolicies, OpaExecutor, OpaExecutorError, WasmtimeOpaExecutor}, + }; + + use super::*; + + fn chronicle_id() -> AuthId { + AuthId::chronicle() + } + + fn chronicle_user_opa_data() -> OpaData { + OpaData::Operation(IdentityContext::new( + AuthId::chronicle(), + Value::default(), + Value::default(), + )) + } + + fn allow_all_users() -> (String, String) { + let policy_name = "allow_transactions".to_string(); + let entrypoint = "allow_transactions/allowed_users".to_string(); + (policy_name, entrypoint) + } + + fn anonymous_user() -> AuthId { + AuthId::anonymous() + } + + fn anonymous_user_opa_data() -> OpaData { + OpaData::Operation(IdentityContext::new( + AuthId::anonymous(), + Value::default(), + Value::default(), + )) + } + + fn jwt_user() -> AuthId { + let claims = JwtClaims( + serde_json::json!({ "sub": "abcdef", }) - .as_object() - .unwrap() - .to_owned(), - ); - AuthId::from_jwt_claims(&claims, &BTreeSet::from(["sub".to_string()])).unwrap() - } - - fn jwt_user_opa_data() -> OpaData { - OpaData::Operation(IdentityContext::new(jwt_user(), Value::default(), Value::default())) - } - - #[test] - fn policy_loader_invalid_rule() { - let (_policy, entrypoint) = allow_all_users(); - let invalid_rule = "a_rule_that_does_not_exist"; - match CliPolicyLoader::from_embedded_policy(invalid_rule, &entrypoint) { - Err(e) => { - insta::assert_snapshot!(e.to_string(), @"Policy not found: a_rule_that_does_not_exist") - }, - _ => panic!("expected error"), - } - } - - #[tokio::test] - async fn opa_executor_allow_chronicle_users() -> Result<(), OpaExecutorError> { - let (policy, entrypoint) = allow_all_users(); - let loader = CliPolicyLoader::from_embedded_policy(&policy, &entrypoint)?; - let mut executor = WasmtimeOpaExecutor::from_loader(&loader).unwrap(); - assert!(executor.evaluate(&chronicle_id(), &chronicle_user_opa_data()).await.is_ok()); - Ok(()) - } - - #[tokio::test] - async fn opa_executor_allow_anonymous_users() -> Result<(), OpaExecutorError> { - let (policy, entrypoint) = allow_all_users(); - let loader = CliPolicyLoader::from_embedded_policy(&policy, &entrypoint)?; - let mut executor = WasmtimeOpaExecutor::from_loader(&loader).unwrap(); - executor.evaluate(&anonymous_user(), &anonymous_user_opa_data()).await.unwrap(); - Ok(()) - } - - #[tokio::test] - async fn opa_executor_allow_jwt_users() -> Result<(), OpaExecutorError> { - let (policy, entrypoint) = allow_all_users(); - let loader = CliPolicyLoader::from_embedded_policy(&policy, &entrypoint)?; - let mut executor = WasmtimeOpaExecutor::from_loader(&loader)?; - assert!(executor.evaluate(&jwt_user(), &jwt_user_opa_data()).await.is_ok()); - Ok(()) - } - - const BUNDLE_FILE: &str = "bundle.tar.gz"; - - fn embedded_policy_bundle() -> Result, PolicyLoaderError> { - EmbeddedOpaPolicies::get(BUNDLE_FILE) - .map(|file| file.data.to_vec()) - .ok_or(PolicyLoaderError::EmbeddedOpaPolicies) - } - - #[tokio::test] - async fn test_load_policy_from_http_url() { - let embedded_bundle = embedded_policy_bundle().unwrap(); - let (rule, entrypoint) = allow_all_users(); - - let mut server = mockito::Server::new_async().await; - // Start the mock server and define the response - let _m = server.mock("GET", "/bundle.tar.gz").with_body(&embedded_bundle).create(); - - // Create the URL policy loader - let mut loader = - UrlPolicyLoader::new(&format!("{}/bundle.tar.gz", server.url()), &rule, &entrypoint); - - // Load the policy - let result = loader.load_policy().await; - assert!(result.is_ok()); - - let bundle = Bundle::from_bytes(&embedded_bundle).unwrap(); - - // Extract the policy from the bundle we embedded in the binary - let policy_from_embedded_bundle = bundle - .wasm_policies - .iter() - .find(|p| p.entrypoint == rule) - .map(|p| p.bytes.as_ref()) - .ok_or(PolicyLoaderError::MissingPolicy(rule.to_string())) - .unwrap(); - - // Get the loaded policy from the url - let policy_from_url = loader.get_policy(); - - assert_eq!(&policy_from_url, &policy_from_embedded_bundle); - } - - #[tokio::test] - async fn test_load_policy_from_file_url() { - let embedded_bundle = embedded_policy_bundle().unwrap(); - let (rule, entrypoint) = allow_all_users(); - - let temp_dir = tempfile::tempdir().unwrap(); - let policy_path = temp_dir.path().join("bundle.tar.gz"); - let mut file = std::fs::File::create(&policy_path).unwrap(); - file.write_all(&embedded_bundle).unwrap(); - - // Create the file URL policy loader - let file_url = format!("file://{}", policy_path.to_string_lossy()); - let mut loader = UrlPolicyLoader::new(&file_url, &rule, &entrypoint); - - // Load the policy - let result = loader.load_policy().await; - assert!(result.is_ok()); - - let bundle = Bundle::from_bytes(&embedded_bundle).unwrap(); - - // Extract the policy from the bundle we embedded in the binary - let policy_from_embedded_bundle = bundle - .wasm_policies - .iter() - .find(|p| p.entrypoint == rule) - .map(|p| p.bytes.as_ref()) - .ok_or(PolicyLoaderError::MissingPolicy(rule.to_string())) - .unwrap(); - - // Get the loaded policy from the file URL - let policy_from_file_url = loader.get_policy(); - - assert_eq!(policy_from_embedded_bundle, policy_from_file_url); - } - - #[tokio::test] - async fn test_load_policy_from_bare_path() { - let embedded_bundle = embedded_policy_bundle().unwrap(); - let (rule, entrypoint) = allow_all_users(); - - let temp_dir = tempfile::tempdir().unwrap(); - let policy_path = temp_dir.path().join("bundle.tar.gz"); - let mut file = std::fs::File::create(&policy_path).unwrap(); - file.write_all(&embedded_bundle).unwrap(); - - // Create the bare path policy loader - let mut loader = UrlPolicyLoader::new(&policy_path.to_string_lossy(), &rule, &entrypoint); - - // Load the policy - let result = loader.load_policy().await; - assert!(result.is_ok()); - - let bundle = Bundle::from_bytes(&embedded_bundle).unwrap(); - - // Extract the policy from the bundle we embedded in the binary - let policy_from_embedded_bundle = bundle - .wasm_policies - .iter() - .find(|p| p.entrypoint == rule) - .map(|p| p.bytes.as_ref()) - .ok_or(PolicyLoaderError::MissingPolicy(rule.to_string())) - .unwrap(); - - // Get the loaded policy from the url - let policy_from_bare_path_url = loader.get_policy(); - - assert_eq!(policy_from_embedded_bundle, policy_from_bare_path_url); - } + .as_object() + .unwrap() + .to_owned(), + ); + AuthId::from_jwt_claims(&claims, &BTreeSet::from(["sub".to_string()])).unwrap() + } + + fn jwt_user_opa_data() -> OpaData { + OpaData::Operation(IdentityContext::new(jwt_user(), Value::default(), Value::default())) + } + + #[test] + fn policy_loader_invalid_rule() { + let (_policy, entrypoint) = allow_all_users(); + let invalid_rule = "a_rule_that_does_not_exist"; + match CliPolicyLoader::from_embedded_policy(invalid_rule, &entrypoint) { + Err(e) => { + insta::assert_snapshot!(e.to_string(), @"Policy not found: a_rule_that_does_not_exist") + } + _ => panic!("expected error"), + } + } + + #[tokio::test] + async fn opa_executor_allow_chronicle_users() -> Result<(), OpaExecutorError> { + let (policy, entrypoint) = allow_all_users(); + let loader = CliPolicyLoader::from_embedded_policy(&policy, &entrypoint)?; + let mut executor = WasmtimeOpaExecutor::from_loader(&loader).unwrap(); + assert!(executor.evaluate(&chronicle_id(), &chronicle_user_opa_data()).await.is_ok()); + Ok(()) + } + + #[tokio::test] + async fn opa_executor_allow_anonymous_users() -> Result<(), OpaExecutorError> { + let (policy, entrypoint) = allow_all_users(); + let loader = CliPolicyLoader::from_embedded_policy(&policy, &entrypoint)?; + let mut executor = WasmtimeOpaExecutor::from_loader(&loader).unwrap(); + executor.evaluate(&anonymous_user(), &anonymous_user_opa_data()).await.unwrap(); + Ok(()) + } + + #[tokio::test] + async fn opa_executor_allow_jwt_users() -> Result<(), OpaExecutorError> { + let (policy, entrypoint) = allow_all_users(); + let loader = CliPolicyLoader::from_embedded_policy(&policy, &entrypoint)?; + let mut executor = WasmtimeOpaExecutor::from_loader(&loader)?; + assert!(executor.evaluate(&jwt_user(), &jwt_user_opa_data()).await.is_ok()); + Ok(()) + } + + const BUNDLE_FILE: &str = "bundle.tar.gz"; + + fn embedded_policy_bundle() -> Result, PolicyLoaderError> { + EmbeddedOpaPolicies::get(BUNDLE_FILE) + .map(|file| file.data.to_vec()) + .ok_or(PolicyLoaderError::EmbeddedOpaPolicies) + } + + #[tokio::test] + async fn test_load_policy_from_http_url() { + let embedded_bundle = embedded_policy_bundle().unwrap(); + let (rule, entrypoint) = allow_all_users(); + + let mut server = mockito::Server::new_async().await; + // Start the mock server and define the response + let _m = server.mock("GET", "/bundle.tar.gz").with_body(&embedded_bundle).create(); + + // Create the URL policy loader + let mut loader = + UrlPolicyLoader::new(&format!("{}/bundle.tar.gz", server.url()), &rule, &entrypoint); + + // Load the policy + let result = loader.load_policy().await; + assert!(result.is_ok()); + + let bundle = Bundle::from_bytes(&embedded_bundle).unwrap(); + + // Extract the policy from the bundle we embedded in the binary + let policy_from_embedded_bundle = bundle + .wasm_policies + .iter() + .find(|p| p.entrypoint == rule) + .map(|p| p.bytes.as_ref()) + .ok_or(PolicyLoaderError::MissingPolicy(rule.to_string())) + .unwrap(); + + // Get the loaded policy from the url + let policy_from_url = loader.get_policy(); + + assert_eq!(&policy_from_url, &policy_from_embedded_bundle); + } + + #[tokio::test] + async fn test_load_policy_from_file_url() { + let embedded_bundle = embedded_policy_bundle().unwrap(); + let (rule, entrypoint) = allow_all_users(); + + let temp_dir = tempfile::tempdir().unwrap(); + let policy_path = temp_dir.path().join("bundle.tar.gz"); + let mut file = std::fs::File::create(&policy_path).unwrap(); + file.write_all(&embedded_bundle).unwrap(); + + // Create the file URL policy loader + let file_url = format!("file://{}", policy_path.to_string_lossy()); + let mut loader = UrlPolicyLoader::new(&file_url, &rule, &entrypoint); + + // Load the policy + let result = loader.load_policy().await; + assert!(result.is_ok()); + + let bundle = Bundle::from_bytes(&embedded_bundle).unwrap(); + + // Extract the policy from the bundle we embedded in the binary + let policy_from_embedded_bundle = bundle + .wasm_policies + .iter() + .find(|p| p.entrypoint == rule) + .map(|p| p.bytes.as_ref()) + .ok_or(PolicyLoaderError::MissingPolicy(rule.to_string())) + .unwrap(); + + // Get the loaded policy from the file URL + let policy_from_file_url = loader.get_policy(); + + assert_eq!(policy_from_embedded_bundle, policy_from_file_url); + } + + #[tokio::test] + async fn test_load_policy_from_bare_path() { + let embedded_bundle = embedded_policy_bundle().unwrap(); + let (rule, entrypoint) = allow_all_users(); + + let temp_dir = tempfile::tempdir().unwrap(); + let policy_path = temp_dir.path().join("bundle.tar.gz"); + let mut file = std::fs::File::create(&policy_path).unwrap(); + file.write_all(&embedded_bundle).unwrap(); + + // Create the bare path policy loader + let mut loader = UrlPolicyLoader::new(&policy_path.to_string_lossy(), &rule, &entrypoint); + + // Load the policy + let result = loader.load_policy().await; + assert!(result.is_ok()); + + let bundle = Bundle::from_bytes(&embedded_bundle).unwrap(); + + // Extract the policy from the bundle we embedded in the binary + let policy_from_embedded_bundle = bundle + .wasm_policies + .iter() + .find(|p| p.entrypoint == rule) + .map(|p| p.bytes.as_ref()) + .ok_or(PolicyLoaderError::MissingPolicy(rule.to_string())) + .unwrap(); + + // Get the loaded policy from the url + let policy_from_bare_path_url = loader.get_policy(); + + assert_eq!(policy_from_embedded_bundle, policy_from_bare_path_url); + } } diff --git a/crates/chronicle/src/codegen/linter.rs b/crates/chronicle/src/codegen/linter.rs index 069c0701b..2b509f81e 100644 --- a/crates/chronicle/src/codegen/linter.rs +++ b/crates/chronicle/src/codegen/linter.rs @@ -1,151 +1,153 @@ -use common::domain::{DomainFileInput, ResourceDef}; -use jsonschema::{error::ValidationErrorKind, JSONSchema}; use std::{collections::HashSet, path::Path, process::exit}; +use jsonschema::{error::ValidationErrorKind, JSONSchema}; + +use common::domain::{DomainFileInput, ResourceDef}; + fn bad_filename(filename: &str) { - println!("JSON or YAML filename extension required for {filename}"); - exit(2); + println!("JSON or YAML filename extension required for {filename}"); + exit(2); } fn build_json_validator(domain: &str) -> JSONSchema { - let json = match serde_json::from_str(domain) { - Ok(json) => json, - Err(error) => { - println!("failed to parse valid JSON from domain schema: {error}"); - exit(2); - }, - }; - match JSONSchema::options().with_draft(jsonschema::Draft::Draft7).compile(&json) { - Ok(json_schema) => json_schema, - Err(error) => { - println!("failed to interpret JSON as a domain schema: {error}"); - exit(2); - }, - } + let json = match serde_json::from_str(domain) { + Ok(json) => json, + Err(error) => { + println!("failed to parse valid JSON from domain schema: {error}"); + exit(2); + } + }; + match JSONSchema::options().with_draft(jsonschema::Draft::Draft7).compile(&json) { + Ok(json_schema) => json_schema, + Err(error) => { + println!("failed to interpret JSON as a domain schema: {error}"); + exit(2); + } + } } fn check_json_valid(json_validator: &JSONSchema, json_data: &str) { - let json = match serde_json::from_str(json_data) { - Ok(json) => json, - Err(error) => { - println!("failed to parse valid JSON: {error}"); - exit(2); - }, - }; - let validation = json_validator.validate(&json); - if let Err(errors) = validation { - for error in errors { - println!("path {} contains invalid data: {}", error.instance_path, error); - if let ValidationErrorKind::Pattern { pattern } = error.kind { - match pattern.as_str() { - "^[A-Z][A-Z0-9_]*$" => { - println!("hint: start with capital letter, use only CAPITALS_UNDERSCORES_NUM8ER5"); - }, - "[A-Z][A-Za-z0-9]*$" => { - println!("hint: start with capital letter, use only LettersAndNum8er5"); - }, - _ => {}, - } - } - } - exit(2); - } + let json = match serde_json::from_str(json_data) { + Ok(json) => json, + Err(error) => { + println!("failed to parse valid JSON: {error}"); + exit(2); + } + }; + let validation = json_validator.validate(&json); + if let Err(errors) = validation { + for error in errors { + println!("path {} contains invalid data: {}", error.instance_path, error); + if let ValidationErrorKind::Pattern { pattern } = error.kind { + match pattern.as_str() { + "^[A-Z][A-Z0-9_]*$" => { + println!("hint: start with capital letter, use only CAPITALS_UNDERSCORES_NUM8ER5"); + } + "[A-Z][A-Za-z0-9]*$" => { + println!("hint: start with capital letter, use only LettersAndNum8er5"); + } + _ => {} + } + } + } + exit(2); + } } fn check_yaml_valid(json_validator: &JSONSchema, yaml_data: &str) { - let json = match serde_yaml::from_str::(yaml_data) { - Ok(json) => json, - Err(error) => { - println!("failed to parse valid YAML: {error}"); - exit(2); - }, - }; - let json_data = match serde_json::to_string(&json) { - Ok(json_data) => json_data, - Err(error) => { - println!("failed to write valid JSON from YAML: {error}"); - exit(2); - }, - }; - check_json_valid(json_validator, &json_data); + let json = match serde_yaml::from_str::(yaml_data) { + Ok(json) => json, + Err(error) => { + println!("failed to parse valid YAML: {error}"); + exit(2); + } + }; + let json_data = match serde_json::to_string(&json) { + Ok(json_data) => json_data, + Err(error) => { + println!("failed to write valid JSON from YAML: {error}"); + exit(2); + } + }; + check_json_valid(json_validator, &json_data); } fn read_json_domain(data: &str) -> DomainFileInput { - match serde_json::from_str(data) { - Ok(domain) => domain, - Err(error) => { - println!("failed to interpret JSON as a domain: {error}"); - exit(2); - }, - } + match serde_json::from_str(data) { + Ok(domain) => domain, + Err(error) => { + println!("failed to interpret JSON as a domain: {error}"); + exit(2); + } + } } fn read_yaml_domain(data: &str) -> DomainFileInput { - match serde_yaml::from_str(data) { - Ok(domain) => domain, - Err(error) => { - println!("failed to interpret YAML as a domain: {error}"); - exit(2); - }, - } + match serde_yaml::from_str(data) { + Ok(domain) => domain, + Err(error) => { + println!("failed to interpret YAML as a domain: {error}"); + exit(2); + } + } } fn check_domain_attributes( - element: &str, - attributes: &HashSet, - named_resources: Vec<(&String, &ResourceDef)>, + element: &str, + attributes: &HashSet, + named_resources: Vec<(&String, &ResourceDef)>, ) { - let mut is_error = false; - for (name, resource) in named_resources { - for attribute in resource.attributes.iter() { - if !(attributes.contains(&attribute.0)) { - println!("{} named {} has unknown attribute {}", element, name, attribute.0); - is_error = true; - } - } - } - if is_error { - exit(2); - } + let mut is_error = false; + for (name, resource) in named_resources { + for attribute in resource.attributes.iter() { + if !(attributes.contains(&attribute.0)) { + println!("{} named {} has unknown attribute {}", element, name, attribute.0); + is_error = true; + } + } + } + if is_error { + exit(2); + } } fn check_domain(domain: DomainFileInput) { - let attributes = domain.attributes.keys().map(std::clone::Clone::clone).collect(); - check_domain_attributes("agent", &attributes, domain.agents.iter().collect()); - check_domain_attributes("entity", &attributes, domain.entities.iter().collect()); - check_domain_attributes("activity", &attributes, domain.activities.iter().collect()); + let attributes = domain.attributes.keys().map(std::clone::Clone::clone).collect(); + check_domain_attributes("agent", &attributes, domain.agents.iter().collect()); + check_domain_attributes("entity", &attributes, domain.entities.iter().collect()); + check_domain_attributes("activity", &attributes, domain.activities.iter().collect()); } pub fn check_files(filenames: Vec<&str>) { - let json_validator = build_json_validator(include_str!("../../schema/domain.json")); - for filename in filenames { - let filepath = Path::new(filename); - let data = match std::fs::read_to_string(filepath) { - Ok(data) => data, - Err(error) => { - println!("failed to read {filename}: {error}"); - exit(2); - }, - }; - match filepath.extension() { - Some(extension) => { - match extension.to_ascii_lowercase().to_str() { - Some("json") | Some("jsn") => { - check_json_valid(&json_validator, data.as_str()); - check_domain(read_json_domain(&data)); - }, - Some("yaml") | Some("yml") => { - check_yaml_valid(&json_validator, data.as_str()); - check_domain(read_yaml_domain(&data)); - }, - _ => { - bad_filename(filename); - }, - }; - }, - None => { - bad_filename(filename); - }, - }; - } + let json_validator = build_json_validator(include_str!("../../schema/domain.json")); + for filename in filenames { + let filepath = Path::new(filename); + let data = match std::fs::read_to_string(filepath) { + Ok(data) => data, + Err(error) => { + println!("failed to read {filename}: {error}"); + exit(2); + } + }; + match filepath.extension() { + Some(extension) => { + match extension.to_ascii_lowercase().to_str() { + Some("json") | Some("jsn") => { + check_json_valid(&json_validator, data.as_str()); + check_domain(read_json_domain(&data)); + } + Some("yaml") | Some("yml") => { + check_yaml_valid(&json_validator, data.as_str()); + check_domain(read_yaml_domain(&data)); + } + _ => { + bad_filename(filename); + } + }; + } + None => { + bad_filename(filename); + } + }; + } } diff --git a/crates/chronicle/src/codegen/mod.rs b/crates/chronicle/src/codegen/mod.rs index 3a0bdf5b2..ec58ace81 100644 --- a/crates/chronicle/src/codegen/mod.rs +++ b/crates/chronicle/src/codegen/mod.rs @@ -1,29 +1,30 @@ #![allow(dead_code)] -pub mod linter; + use std::{io::Write, path::Path}; use genco::prelude::*; pub use common::domain::{AttributesTypeName, Builder, CliName, PrimitiveType, Property, TypeName}; - pub use common::domain::{ActivityDef, AgentDef, AttributeDef, ChronicleDomainDef, EntityDef}; +pub mod linter; + fn agent_union_type_name() -> String { - "Agent".to_owned() + "Agent".to_owned() } fn entity_union_type_name() -> String { - "Entity".to_owned() + "Entity".to_owned() } fn activity_union_type_name() -> String { - "Activity".to_owned() + "Activity".to_owned() } fn gen_attribute_scalars(attributes: &[AttributeDef]) -> rust::Tokens { - let graphql_new_type = &rust::import("chronicle::async_graphql", "NewType"); - let chronicle_json = &rust::import("chronicle::common::prov", "ChronicleJSON"); - quote! { + let graphql_new_type = &rust::import("chronicle::async_graphql", "NewType"); + let chronicle_json = &rust::import("chronicle::common::prov", "ChronicleJSON"); + quote! { #(for attribute in attributes.iter() => #[derive(Clone, #graphql_new_type)] #[graphql(name = #_(#(attribute.as_scalar_type())), visible=true)] @@ -42,14 +43,14 @@ fn gen_attribute_scalars(attributes: &[AttributeDef]) -> rust::Tokens { } fn gen_association_and_attribution_unions() -> rust::Tokens { - let simple_object = &rust::import("chronicle::async_graphql", "SimpleObject").qualified(); + let simple_object = &rust::import("chronicle::async_graphql", "SimpleObject").qualified(); - let agent_ref_doc = include_str!("../../../../domain_docs/agent_ref.md"); - let association_doc = include_str!("../../../../domain_docs/association.md"); - let attribution_doc = include_str!("../../../../domain_docs/attribution.md"); - let entity_ref_doc = include_str!("../../../../domain_docs/entity_ref.md"); + let agent_ref_doc = include_str!("../../../../domain_docs/agent_ref.md"); + let association_doc = include_str!("../../../../domain_docs/association.md"); + let attribution_doc = include_str!("../../../../domain_docs/attribution.md"); + let entity_ref_doc = include_str!("../../../../domain_docs/entity_ref.md"); - quote! { + quote! { #[doc = #_(#agent_ref_doc)] #[derive(#simple_object)] @@ -87,20 +88,20 @@ fn gen_association_and_attribution_unions() -> rust::Tokens { } fn gen_type_enums(domain: &ChronicleDomainDef) -> rust::Tokens { - let graphql_enum = &rust::import("chronicle::async_graphql", "Enum"); - let domain_type_id = &rust::import("chronicle::common::prov", "DomaintypeId"); - let prov_role = &rust::import("chronicle::common::prov", "Role").qualified(); - - let activity_type_doc = include_str!("../../../../domain_docs/activity_type.md"); - let agent_type_doc = include_str!("../../../../domain_docs/agent_type.md"); - let entity_type_doc = include_str!("../../../../domain_docs/entity_type.md"); - let prov_activity_doc = include_str!("../../../../domain_docs/prov_activity.md"); - let prov_agent_doc = include_str!("../../../../domain_docs/prov_agent.md"); - let prov_entity_doc = include_str!("../../../../domain_docs/prov_entity.md"); - let role_doc = include_str!("../../../../domain_docs/role.md"); - let unspecified_doc = include_str!("../../../../domain_docs/unspecified.md"); - - quote! { + let graphql_enum = &rust::import("chronicle::async_graphql", "Enum"); + let domain_type_id = &rust::import("chronicle::common::prov", "DomaintypeId"); + let prov_role = &rust::import("chronicle::common::prov", "Role").qualified(); + + let activity_type_doc = include_str!("../../../../domain_docs/activity_type.md"); + let agent_type_doc = include_str!("../../../../domain_docs/agent_type.md"); + let entity_type_doc = include_str!("../../../../domain_docs/entity_type.md"); + let prov_activity_doc = include_str!("../../../../domain_docs/prov_activity.md"); + let prov_agent_doc = include_str!("../../../../domain_docs/prov_agent.md"); + let prov_entity_doc = include_str!("../../../../domain_docs/prov_entity.md"); + let role_doc = include_str!("../../../../domain_docs/role.md"); + let unspecified_doc = include_str!("../../../../domain_docs/unspecified.md"); + + quote! { #[derive(#graphql_enum, Copy, Clone, Eq, PartialEq)] #[allow(clippy::upper_case_acronyms)] #[doc = #_(#role_doc)] @@ -234,12 +235,12 @@ fn gen_type_enums(domain: &ChronicleDomainDef) -> rust::Tokens { } fn gen_agent_union(agents: &[AgentDef]) -> rust::Tokens { - let union_macro = rust::import("chronicle::async_graphql", "Union").qualified(); + let union_macro = rust::import("chronicle::async_graphql", "Union").qualified(); - let agent_doc = include_str!("../../../../domain_docs/agent.md"); - let prov_agent_doc = include_str!("../../../../domain_docs/prov_agent.md"); + let agent_doc = include_str!("../../../../domain_docs/agent.md"); + let prov_agent_doc = include_str!("../../../../domain_docs/prov_agent.md"); - quote! { + quote! { #[doc = #_(#agent_doc)] #[allow(clippy::enum_variant_names)] #[allow(clippy::upper_case_acronyms)] @@ -258,12 +259,12 @@ fn gen_agent_union(agents: &[AgentDef]) -> rust::Tokens { } fn gen_entity_union(entities: &[EntityDef]) -> rust::Tokens { - let union_macro = rust::import("chronicle::async_graphql", "Union").qualified(); + let union_macro = rust::import("chronicle::async_graphql", "Union").qualified(); - let entity_doc = include_str!("../../../../domain_docs/entity.md"); - let prov_entity_doc = include_str!("../../../../domain_docs/prov_entity.md"); + let entity_doc = include_str!("../../../../domain_docs/entity.md"); + let prov_entity_doc = include_str!("../../../../domain_docs/prov_entity.md"); - quote! { + quote! { #[doc = #_(#entity_doc)] #[allow(clippy::enum_variant_names)] #[allow(clippy::upper_case_acronyms)] @@ -282,12 +283,12 @@ fn gen_entity_union(entities: &[EntityDef]) -> rust::Tokens { } fn gen_activity_union(activities: &[ActivityDef]) -> rust::Tokens { - let union_macro = rust::import("chronicle::async_graphql", "Union").qualified(); + let union_macro = rust::import("chronicle::async_graphql", "Union").qualified(); - let activity_doc = include_str!("../../../../domain_docs/activity.md"); - let prov_activity_doc = include_str!("../../../../domain_docs/prov_activity.md"); + let activity_doc = include_str!("../../../../domain_docs/activity.md"); + let prov_activity_doc = include_str!("../../../../domain_docs/prov_activity.md"); - quote! { + quote! { #[doc = #_(#activity_doc)] #[allow(clippy::enum_variant_names)] #[allow(clippy::upper_case_acronyms)] @@ -306,35 +307,35 @@ fn gen_activity_union(activities: &[ActivityDef]) -> rust::Tokens { } fn gen_activity_definition(activity: &ActivityDef) -> rust::Tokens { - let abstract_activity = - &rust::import("chronicle::persistence::queryable", "Activity").qualified(); - let activity_impl = &rust::import("chronicle::api::chronicle_graphql", "activity").qualified(); - let namespace = &rust::import("chronicle::persistence::queryable", "Namespace").qualified(); - let activity_id = &rust::import("chronicle::common::prov", "ActivityId").qualified(); - let async_graphql_error_extensions = - &rust::import("chronicle::async_graphql", "ErrorExtensions").qualified(); - - let timezone = &rust::import("chronicle::chrono", "TimeZone").direct(); - let object = rust::import("chronicle::async_graphql", "Object").qualified(); - let async_result = &rust::import("chronicle::async_graphql", "Result").qualified(); - let context = &rust::import("chronicle::async_graphql", "Context").qualified(); - let domain_type_id = &rust::import("chronicle::common::prov", "DomaintypeId"); - let date_time = &rust::import("chronicle::chrono", "DateTime"); - let utc = &rust::import("chronicle::chrono", "Utc"); - let chronicle_json = &rust::import("chronicle::common::prov", "ChronicleJSON"); - - let end_doc = include_str!("../../../../domain_docs/end.md"); - let external_id_doc = include_str!("../../../../domain_docs/external_id.md"); - let generated_doc = include_str!("../../../../domain_docs/generated.md"); - let id_doc = include_str!("../../../../domain_docs/id.md"); - let namespace_doc = include_str!("../../../../domain_docs/namespace.md"); - let start_doc = include_str!("../../../../domain_docs/start.md"); - let type_doc = include_str!("../../../../domain_docs/type.md"); - let used_doc = include_str!("../../../../domain_docs/used.md"); - let was_associated_with_doc = include_str!("../../../../domain_docs/was_associated_with.md"); - let was_informed_by_doc = include_str!("../../../../domain_docs/was_informed_by.md"); - - quote! { + let abstract_activity = + &rust::import("chronicle::persistence::queryable", "Activity").qualified(); + let activity_impl = &rust::import("chronicle::api::chronicle_graphql", "activity").qualified(); + let namespace = &rust::import("chronicle::persistence::queryable", "Namespace").qualified(); + let activity_id = &rust::import("chronicle::common::prov", "ActivityId").qualified(); + let async_graphql_error_extensions = + &rust::import("chronicle::async_graphql", "ErrorExtensions").qualified(); + + let timezone = &rust::import("chronicle::chrono", "TimeZone").direct(); + let object = rust::import("chronicle::async_graphql", "Object").qualified(); + let async_result = &rust::import("chronicle::async_graphql", "Result").qualified(); + let context = &rust::import("chronicle::async_graphql", "Context").qualified(); + let domain_type_id = &rust::import("chronicle::common::prov", "DomaintypeId"); + let date_time = &rust::import("chronicle::chrono", "DateTime"); + let utc = &rust::import("chronicle::chrono", "Utc"); + let chronicle_json = &rust::import("chronicle::common::prov", "ChronicleJSON"); + + let end_doc = include_str!("../../../../domain_docs/end.md"); + let external_id_doc = include_str!("../../../../domain_docs/external_id.md"); + let generated_doc = include_str!("../../../../domain_docs/generated.md"); + let id_doc = include_str!("../../../../domain_docs/id.md"); + let namespace_doc = include_str!("../../../../domain_docs/namespace.md"); + let start_doc = include_str!("../../../../domain_docs/start.md"); + let type_doc = include_str!("../../../../domain_docs/type.md"); + let used_doc = include_str!("../../../../domain_docs/used.md"); + let was_associated_with_doc = include_str!("../../../../domain_docs/was_associated_with.md"); + let was_informed_by_doc = include_str!("../../../../domain_docs/was_informed_by.md"); + + quote! { #(register(activity_impl)) #[allow(clippy::upper_case_acronyms)] @@ -462,31 +463,31 @@ fn gen_activity_definition(activity: &ActivityDef) -> rust::Tokens { } fn gen_entity_definition(entity: &EntityDef) -> rust::Tokens { - let abstract_entity = &rust::import("chronicle::persistence::queryable", "Entity").qualified(); - let entity_impl = &rust::import("chronicle::api::chronicle_graphql", "entity").qualified(); - let namespace = &rust::import("chronicle::persistence::queryable", "Namespace").qualified(); - let entity_id = &rust::import("chronicle::common::prov", "EntityId").qualified(); - - let object = rust::import("chronicle::async_graphql", "Object").qualified(); - let async_result = &rust::import("chronicle::async_graphql", "Result").qualified(); - let context = &rust::import("chronicle::async_graphql", "Context").qualified(); - let domain_type_id = &rust::import("chronicle::common::prov", "DomaintypeId"); - let chronicle_json = &rust::import("chronicle::common::prov", "ChronicleJSON"); - let async_graphql_error_extensions = - &rust::import("chronicle::async_graphql", "ErrorExtensions").qualified(); - - let external_id_doc = include_str!("../../../../domain_docs/external_id.md"); - let had_primary_source_doc = include_str!("../../../../domain_docs/had_primary_source.md"); - let id_doc = include_str!("../../../../domain_docs/id.md"); - let namespace_doc = include_str!("../../../../domain_docs/namespace.md"); - let type_doc = include_str!("../../../../domain_docs/type.md"); - let was_attributed_to_doc = include_str!("../../../../domain_docs/was_attributed_to.md"); - let was_derived_from_doc = include_str!("../../../../domain_docs/was_derived_from.md"); - let was_generated_by_doc = include_str!("../../../../domain_docs/was_generated_by.md"); - let was_quoted_from_doc = include_str!("../../../../domain_docs/was_quoted_from.md"); - let was_revision_of_doc = include_str!("../../../../domain_docs/was_revision_of.md"); - - quote! { + let abstract_entity = &rust::import("chronicle::persistence::queryable", "Entity").qualified(); + let entity_impl = &rust::import("chronicle::api::chronicle_graphql", "entity").qualified(); + let namespace = &rust::import("chronicle::persistence::queryable", "Namespace").qualified(); + let entity_id = &rust::import("chronicle::common::prov", "EntityId").qualified(); + + let object = rust::import("chronicle::async_graphql", "Object").qualified(); + let async_result = &rust::import("chronicle::async_graphql", "Result").qualified(); + let context = &rust::import("chronicle::async_graphql", "Context").qualified(); + let domain_type_id = &rust::import("chronicle::common::prov", "DomaintypeId"); + let chronicle_json = &rust::import("chronicle::common::prov", "ChronicleJSON"); + let async_graphql_error_extensions = + &rust::import("chronicle::async_graphql", "ErrorExtensions").qualified(); + + let external_id_doc = include_str!("../../../../domain_docs/external_id.md"); + let had_primary_source_doc = include_str!("../../../../domain_docs/had_primary_source.md"); + let id_doc = include_str!("../../../../domain_docs/id.md"); + let namespace_doc = include_str!("../../../../domain_docs/namespace.md"); + let type_doc = include_str!("../../../../domain_docs/type.md"); + let was_attributed_to_doc = include_str!("../../../../domain_docs/was_attributed_to.md"); + let was_derived_from_doc = include_str!("../../../../domain_docs/was_derived_from.md"); + let was_generated_by_doc = include_str!("../../../../domain_docs/was_generated_by.md"); + let was_quoted_from_doc = include_str!("../../../../domain_docs/was_quoted_from.md"); + let was_revision_of_doc = include_str!("../../../../domain_docs/was_revision_of.md"); + + quote! { #(register(entity_impl)) #[allow(clippy::upper_case_acronyms)] @@ -629,27 +630,27 @@ fn gen_entity_definition(entity: &EntityDef) -> rust::Tokens { } fn gen_agent_definition(agent: &AgentDef) -> rust::Tokens { - let abstract_agent = &rust::import("chronicle::persistence::queryable", "Agent").qualified(); - let agent_impl = &rust::import("chronicle::api::chronicle_graphql", "agent").qualified(); - let namespace = &rust::import("chronicle::persistence::queryable", "Namespace").qualified(); - let agent_union_type = &agent_union_type_name(); - let object = rust::import("chronicle::async_graphql", "Object").qualified(); - let async_result = &rust::import("chronicle::async_graphql", "Result").qualified(); - let context = &rust::import("chronicle::async_graphql", "Context").qualified(); - let agent_id = &rust::import("chronicle::common::prov", "AgentId"); - let domain_type_id = &rust::import("chronicle::common::prov", "DomaintypeId"); - let chronicle_json = &rust::import("chronicle::common::prov", "ChronicleJSON"); - let async_graphql_error_extensions = - &rust::import("chronicle::async_graphql", "ErrorExtensions").qualified(); - - let acted_on_behalf_of_doc = include_str!("../../../../domain_docs/acted_on_behalf_of.md"); - let attribution_doc = include_str!("../../../../domain_docs/attribution.md"); - let external_id_doc = include_str!("../../../../domain_docs/external_id.md"); - let id_doc = include_str!("../../../../domain_docs/id.md"); - let namespace_doc = include_str!("../../../../domain_docs/namespace.md"); - let type_doc = include_str!("../../../../domain_docs/type.md"); - - quote! { + let abstract_agent = &rust::import("chronicle::persistence::queryable", "Agent").qualified(); + let agent_impl = &rust::import("chronicle::api::chronicle_graphql", "agent").qualified(); + let namespace = &rust::import("chronicle::persistence::queryable", "Namespace").qualified(); + let agent_union_type = &agent_union_type_name(); + let object = rust::import("chronicle::async_graphql", "Object").qualified(); + let async_result = &rust::import("chronicle::async_graphql", "Result").qualified(); + let context = &rust::import("chronicle::async_graphql", "Context").qualified(); + let agent_id = &rust::import("chronicle::common::prov", "AgentId"); + let domain_type_id = &rust::import("chronicle::common::prov", "DomaintypeId"); + let chronicle_json = &rust::import("chronicle::common::prov", "ChronicleJSON"); + let async_graphql_error_extensions = + &rust::import("chronicle::async_graphql", "ErrorExtensions").qualified(); + + let acted_on_behalf_of_doc = include_str!("../../../../domain_docs/acted_on_behalf_of.md"); + let attribution_doc = include_str!("../../../../domain_docs/attribution.md"); + let external_id_doc = include_str!("../../../../domain_docs/external_id.md"); + let id_doc = include_str!("../../../../domain_docs/id.md"); + let namespace_doc = include_str!("../../../../domain_docs/namespace.md"); + let type_doc = include_str!("../../../../domain_docs/type.md"); + + quote! { #(register(agent_impl)) @@ -743,12 +744,12 @@ fn gen_agent_definition(agent: &AgentDef) -> rust::Tokens { } fn gen_abstract_prov_attributes() -> rust::Tokens { - let input_object = &rust::import("chronicle::async_graphql", "InputObject").qualified(); - let abstract_attributes = - &rust::import("chronicle::common::attributes", "Attributes").qualified(); - let domain_type_id = &rust::import("chronicle::common::prov", "DomaintypeId"); + let input_object = &rust::import("chronicle::async_graphql", "InputObject").qualified(); + let abstract_attributes = + &rust::import("chronicle::common::attributes", "Attributes").qualified(); + let domain_type_id = &rust::import("chronicle::common::prov", "DomaintypeId"); - quote! { + quote! { #[derive(#input_object, Clone)] pub struct ProvAgentAttributes { #[graphql(name = "type")] @@ -799,19 +800,19 @@ fn gen_abstract_prov_attributes() -> rust::Tokens { } fn gen_attribute_definition(typ: impl TypeName, attributes: &[AttributeDef]) -> rust::Tokens { - let abstract_attribute = - &rust::import("chronicle::common::attributes", "Attribute").qualified(); - let abstract_attributes = - &rust::import("chronicle::common::attributes", "Attributes").qualified(); - let input_object = rust::import("chronicle::async_graphql", "InputObject").qualified(); - let domain_type_id = rust::import("chronicle::common::prov", "DomaintypeId"); - let serde_value = &rust::import("chronicle::serde_json", "Value"); - - if attributes.is_empty() { - return quote! {}; - } - - quote! { + let abstract_attribute = + &rust::import("chronicle::common::attributes", "Attribute").qualified(); + let abstract_attributes = + &rust::import("chronicle::common::attributes", "Attributes").qualified(); + let input_object = rust::import("chronicle::async_graphql", "InputObject").qualified(); + let domain_type_id = rust::import("chronicle::common::prov", "DomaintypeId"); + let serde_value = &rust::import("chronicle::serde_json", "Value"); + + if attributes.is_empty() { + return quote! {}; + } + + quote! { #[derive(#input_object)] #[graphql(name = #_(#(typ.attributes_type_name_preserve_inflection())))] pub struct #(typ.attributes_type_name_preserve_inflection()) { @@ -848,12 +849,12 @@ fn gen_attribute_definition(typ: impl TypeName, attributes: &[AttributeDef]) -> } fn gen_mappers(domain: &ChronicleDomainDef) -> rust::Tokens { - let agent_impl = &rust::import("chronicle::persistence::queryable", "Agent").qualified(); - let role = &rust::import("chronicle::common::prov", "Role").qualified(); - let entity_impl = &rust::import("chronicle::persistence::queryable", "Entity").qualified(); - let activity_impl = &rust::import("chronicle::persistence::queryable", "Activity").qualified(); + let agent_impl = &rust::import("chronicle::persistence::queryable", "Agent").qualified(); + let role = &rust::import("chronicle::common::prov", "Role").qualified(); + let entity_impl = &rust::import("chronicle::persistence::queryable", "Entity").qualified(); + let activity_impl = &rust::import("chronicle::persistence::queryable", "Activity").qualified(); - quote! { + quote! { #[allow(clippy::match_single_binding)] fn map_agent_to_domain_type(agent: #agent_impl) -> #(agent_union_type_name()) { match agent.domaintype.as_deref() { @@ -957,35 +958,36 @@ fn gen_mappers(domain: &ChronicleDomainDef) -> rust::Tokens { } } } + fn gen_query() -> rust::Tokens { - let query_impl = &rust::import("chronicle::api::chronicle_graphql", "query").qualified(); - - let graphql_object = &rust::import("chronicle::async_graphql", "Object"); - let graphql_result = &rust::import("chronicle::async_graphql", "Result"); - let graphql_id = &rust::import("chronicle::async_graphql", "ID"); - let graphql_context = &rust::import("chronicle::async_graphql", "Context"); - let graphql_connection = &rust::import("chronicle::async_graphql::connection", "Connection"); - let async_graphql_error_extensions = - &rust::import("chronicle::async_graphql", "ErrorExtensions").qualified(); - - let agent_id = &rust::import("chronicle::common::prov", "AgentIdOrExternal"); - let entity_id = &rust::import("chronicle::common::prov", "EntityIdOrExternal"); - let activity_id = &rust::import("chronicle::common::prov", "ActivityIdOrExternal"); - let empty_fields = - &rust::import("chronicle::async_graphql::connection", "EmptyFields").qualified(); - - let timeline_order = - &rust::import("chronicle::api::chronicle_graphql", "TimelineOrder").qualified(); - - let activities_by_type_doc = include_str!("../../../../domain_docs/activities_by_type.md"); - let activity_by_id_doc = include_str!("../../../../domain_docs/activity_by_id.md"); - let activity_timeline_doc = include_str!("../../../../domain_docs/activity_timeline.md"); - let agent_by_id_doc = include_str!("../../../../domain_docs/agent_by_id.md"); - let agents_by_type_doc = include_str!("../../../../domain_docs/agents_by_type.md"); - let entities_by_type_doc = include_str!("../../../../domain_docs/entities_by_type.md"); - let entity_by_id_doc = include_str!("../../../../domain_docs/entity_by_id.md"); - - quote! { + let query_impl = &rust::import("chronicle::api::chronicle_graphql", "query").qualified(); + + let graphql_object = &rust::import("chronicle::async_graphql", "Object"); + let graphql_result = &rust::import("chronicle::async_graphql", "Result"); + let graphql_id = &rust::import("chronicle::async_graphql", "ID"); + let graphql_context = &rust::import("chronicle::async_graphql", "Context"); + let graphql_connection = &rust::import("chronicle::async_graphql::connection", "Connection"); + let async_graphql_error_extensions = + &rust::import("chronicle::async_graphql", "ErrorExtensions").qualified(); + + let agent_id = &rust::import("chronicle::common::prov", "AgentIdOrExternal"); + let entity_id = &rust::import("chronicle::common::prov", "EntityIdOrExternal"); + let activity_id = &rust::import("chronicle::common::prov", "ActivityIdOrExternal"); + let empty_fields = + &rust::import("chronicle::async_graphql::connection", "EmptyFields").qualified(); + + let timeline_order = + &rust::import("chronicle::api::chronicle_graphql", "TimelineOrder").qualified(); + + let activities_by_type_doc = include_str!("../../../../domain_docs/activities_by_type.md"); + let activity_by_id_doc = include_str!("../../../../domain_docs/activity_by_id.md"); + let activity_timeline_doc = include_str!("../../../../domain_docs/activity_timeline.md"); + let agent_by_id_doc = include_str!("../../../../domain_docs/agent_by_id.md"); + let agents_by_type_doc = include_str!("../../../../domain_docs/agents_by_type.md"); + let entities_by_type_doc = include_str!("../../../../domain_docs/entities_by_type.md"); + let entity_by_id_doc = include_str!("../../../../domain_docs/entity_by_id.md"); + + quote! { #[derive(Copy, Clone)] pub struct Query; @@ -1206,43 +1208,43 @@ fn gen_query() -> rust::Tokens { } fn gen_mutation(domain: &ChronicleDomainDef) -> rust::Tokens { - let graphql_object = &rust::import("chronicle::async_graphql", "Object"); - - let graphql_result = &rust::import("chronicle::async_graphql", "Result"); - let graphql_context = &rust::import("chronicle::async_graphql", "Context"); - let async_graphql_error_extensions = - &rust::import("chronicle::async_graphql", "ErrorExtensions").qualified(); - - let submission = &rust::import("chronicle::api::chronicle_graphql", "Submission"); - let impls = &rust::import("chronicle::api::chronicle_graphql", "mutation"); - - let entity_id = &rust::import("chronicle::common::prov", "EntityIdOrExternal"); - let agent_id = &rust::import("chronicle::common::prov", "AgentIdOrExternal"); - let activity_id = &rust::import("chronicle::common::prov", "ActivityIdOrExternal"); - let domain_type_id = &rust::import("chronicle::common::prov", "DomaintypeId"); - - let abstract_attributes = - &rust::import("chronicle::common::attributes", "Attributes").qualified(); - - let acted_on_behalf_of_doc = include_str!("../../../../domain_docs/acted_on_behalf_of.md"); - let define_doc = include_str!("../../../../domain_docs/define.md"); - let end_doc = include_str!("../../../../domain_docs/end_activity.md"); - let had_primary_source_doc = include_str!("../../../../domain_docs/had_primary_source.md"); - let instant_activity_doc = include_str!("../../../../domain_docs/instant_activity.md"); - let prov_activity_doc = include_str!("../../../../domain_docs/prov_activity.md"); - let prov_agent_doc = include_str!("../../../../domain_docs/prov_agent.md"); - let prov_entity_doc = include_str!("../../../../domain_docs/prov_entity.md"); - let start_doc = include_str!("../../../../domain_docs/start_activity.md"); - let used_doc = include_str!("../../../../domain_docs/used.md"); - let was_associated_with_doc = include_str!("../../../../domain_docs/was_associated_with.md"); - let was_attributed_to_doc = include_str!("../../../../domain_docs/was_attributed_to.md"); - let was_derived_from_doc = include_str!("../../../../domain_docs/was_derived_from.md"); - let was_generated_by_doc = include_str!("../../../../domain_docs/was_generated_by.md"); - let was_informed_by_doc = include_str!("../../../../domain_docs/was_informed_by.md"); - let was_quoted_from_doc = include_str!("../../../../domain_docs/was_quoted_from.md"); - let was_revision_of_doc = include_str!("../../../../domain_docs/was_revision_of.md"); - - quote! { + let graphql_object = &rust::import("chronicle::async_graphql", "Object"); + + let graphql_result = &rust::import("chronicle::async_graphql", "Result"); + let graphql_context = &rust::import("chronicle::async_graphql", "Context"); + let async_graphql_error_extensions = + &rust::import("chronicle::async_graphql", "ErrorExtensions").qualified(); + + let submission = &rust::import("chronicle::api::chronicle_graphql", "Submission"); + let impls = &rust::import("chronicle::api::chronicle_graphql", "mutation"); + + let entity_id = &rust::import("chronicle::common::prov", "EntityIdOrExternal"); + let agent_id = &rust::import("chronicle::common::prov", "AgentIdOrExternal"); + let activity_id = &rust::import("chronicle::common::prov", "ActivityIdOrExternal"); + let domain_type_id = &rust::import("chronicle::common::prov", "DomaintypeId"); + + let abstract_attributes = + &rust::import("chronicle::common::attributes", "Attributes").qualified(); + + let acted_on_behalf_of_doc = include_str!("../../../../domain_docs/acted_on_behalf_of.md"); + let define_doc = include_str!("../../../../domain_docs/define.md"); + let end_doc = include_str!("../../../../domain_docs/end_activity.md"); + let had_primary_source_doc = include_str!("../../../../domain_docs/had_primary_source.md"); + let instant_activity_doc = include_str!("../../../../domain_docs/instant_activity.md"); + let prov_activity_doc = include_str!("../../../../domain_docs/prov_activity.md"); + let prov_agent_doc = include_str!("../../../../domain_docs/prov_agent.md"); + let prov_entity_doc = include_str!("../../../../domain_docs/prov_entity.md"); + let start_doc = include_str!("../../../../domain_docs/start_activity.md"); + let used_doc = include_str!("../../../../domain_docs/used.md"); + let was_associated_with_doc = include_str!("../../../../domain_docs/was_associated_with.md"); + let was_attributed_to_doc = include_str!("../../../../domain_docs/was_attributed_to.md"); + let was_derived_from_doc = include_str!("../../../../domain_docs/was_derived_from.md"); + let was_generated_by_doc = include_str!("../../../../domain_docs/was_generated_by.md"); + let was_informed_by_doc = include_str!("../../../../domain_docs/was_informed_by.md"); + let was_quoted_from_doc = include_str!("../../../../domain_docs/was_quoted_from.md"); + let was_revision_of_doc = include_str!("../../../../domain_docs/was_revision_of.md"); + + quote! { #[derive(Copy, Clone)] pub struct Mutation; @@ -1559,29 +1561,29 @@ fn gen_mutation(domain: &ChronicleDomainDef) -> rust::Tokens { } fn gen_graphql_type(domain: &ChronicleDomainDef) -> rust::Tokens { - let prov_agent = AgentDef { - external_id: "ProvAgent".to_owned(), - doc: Some(include_str!("../../../../domain_docs/prov_agent.md").to_string()), - attributes: vec![], - }; - let prov_activity = ActivityDef { - external_id: "ProvActivity".to_owned(), - doc: Some(include_str!("../../../../domain_docs/prov_activity.md").to_string()), - attributes: vec![], - }; - let prov_entity = EntityDef { - external_id: "ProvEntity".to_owned(), - doc: Some(include_str!("../../../../domain_docs/prov_entity.md").to_string()), - attributes: vec![], - }; - - let chronicledomaindef = &rust::import("chronicle::codegen", "ChronicleDomainDef"); - let tokio = &rust::import("chronicle", "tokio"); - - let bootstrap = rust::import("chronicle::bootstrap", "bootstrap"); - let chronicle_graphql = rust::import("chronicle::api::chronicle_graphql", "ChronicleGraphQl"); - - quote! { + let prov_agent = AgentDef { + external_id: "ProvAgent".to_owned(), + doc: Some(include_str!("../../../../domain_docs/prov_agent.md").to_string()), + attributes: vec![], + }; + let prov_activity = ActivityDef { + external_id: "ProvActivity".to_owned(), + doc: Some(include_str!("../../../../domain_docs/prov_activity.md").to_string()), + attributes: vec![], + }; + let prov_entity = EntityDef { + external_id: "ProvEntity".to_owned(), + doc: Some(include_str!("../../../../domain_docs/prov_entity.md").to_string()), + attributes: vec![], + }; + + let chronicledomaindef = &rust::import("chronicle::codegen", "ChronicleDomainDef"); + let tokio = &rust::import("chronicle", "tokio"); + + let bootstrap = rust::import("chronicle::bootstrap", "bootstrap"); + let chronicle_graphql = rust::import("chronicle::api::chronicle_graphql", "ChronicleGraphQl"); + + quote! { #(gen_attribute_scalars(&domain.attributes)) #(gen_type_enums(domain)) #(gen_association_and_attribution_unions()) @@ -1615,11 +1617,11 @@ fn gen_graphql_type(domain: &ChronicleDomainDef) -> rust::Tokens { } pub fn generate_chronicle_domain_schema(domain: ChronicleDomainDef, path: impl AsRef) { - let tokens = gen_graphql_type(&domain); + let tokens = gen_graphql_type(&domain); - path.as_ref().parent().map(std::fs::create_dir_all); - let mut f = std::fs::File::create(path).unwrap(); - f.write_all(tokens.to_file_string().unwrap().as_bytes()).unwrap(); + path.as_ref().parent().map(std::fs::create_dir_all); + let mut f = std::fs::File::create(path).unwrap(); + f.write_all(tokens.to_file_string().unwrap().as_bytes()).unwrap(); - f.flush().unwrap(); + f.flush().unwrap(); } diff --git a/crates/chronicle/src/lib.rs b/crates/chronicle/src/lib.rs index 506d04240..c8910253a 100644 --- a/crates/chronicle/src/lib.rs +++ b/crates/chronicle/src/lib.rs @@ -1,15 +1,19 @@ #![cfg_attr(feature = "strict", deny(warnings))] -pub mod bootstrap; -pub mod codegen; -/// Re-export dependencies for generated code -pub use api; + pub use async_graphql; -pub use chronicle_persistence as persistence; pub use chrono; -pub use common; pub use serde_json; pub use tokio; pub use uuid; +/// Re-export dependencies for generated code +pub use api; +pub use chronicle_persistence as persistence; +pub use codegen::{Builder, generate_chronicle_domain_schema, PrimitiveType}; +pub use common; + pub use crate::bootstrap::bootstrap; -pub use codegen::{generate_chronicle_domain_schema, Builder, PrimitiveType}; + +pub mod bootstrap; +pub mod codegen; + diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index e16f9b7ab..40e0bfe67 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -1,7 +1,7 @@ [package] -build = "build.rs" +build = "build.rs" edition = "2021" -name = "common" +name = "common" version = "0.7.5" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -10,38 +10,38 @@ version = "0.7.5" Inflector = { workspace = true, optional = true } anyhow = { version = "^1", default-features = false } async-graphql = { version = "^7", features = [ - "opentelemetry", - "chrono", - "unblock", - "default", - "uuid", + "opentelemetry", + "chrono", + "unblock", + "default", + "uuid", ], optional = true } async-trait = { workspace = true } chrono = { version = "^0.4", default-features = false, features = [ - "serde", - "alloc", + "serde", + "alloc", ] } diesel = { version = "2.1", features = [ - "postgres", - "uuid", - "chrono", - "r2d2", + "postgres", + "uuid", + "chrono", + "r2d2", ], optional = true } futures = { version = "0.3", default-features = false } hashbrown = { version = "0.13", optional = true } hex = { version = "0.4", default-features = false, features = ["alloc"] } iref = { version = "2.2", optional = true } iri-string = { version = "^0.7", default-features = false, features = [ - "alloc", + "alloc", ] } json-ld = { version = "0.14", optional = true } json-syntax = { version = "0.9", features = [ - "serde", - "serde_json", + "serde", + "serde_json", ], optional = true } k256 = { version = "0.11.3", default-features = false, features = [ - "ecdsa", - "pkcs8", + "ecdsa", + "pkcs8", ] } lazy_static = { version = "1.4" } locspan = { version = "0.7", optional = true } @@ -50,32 +50,32 @@ mime = { version = "0.3", optional = true } newtype-derive-2018 = { workspace = true } opa = { git = "https://github.com/chronicleworks/opa-rs", rev = "9fa2fbce", optional = true } parity-scale-codec = { version = "^3.4.0", default-features = false, features = [ - "derive", - "max-encoded-len", + "derive", + "max-encoded-len", ], optional = true } percent-encoding = { version = "^2.1", default-features = false, features = [ - "alloc", + "alloc", ] } rdf-types = { version = "0.14", optional = true } reqwest = { version = "0.11", optional = true } rust-embed = { version = "6", features = [ - "debug-embed", - "include-exclude", + "debug-embed", + "include-exclude", ], optional = true } scale-decode = { version = "^0.10.0", default-features = false, features = [ - "derive", + "derive", ], optional = true } scale-encode = { version = "^0.5.0", default-features = false, features = [ - "derive", - "primitive-types", - "bits", + "derive", + "primitive-types", + "bits", ], optional = true } scale-info = { version = "^2.10.0", default-features = false, features = [ - "derive", + "derive", ], optional = true } serde = { version = "1.0", default-features = false, features = [ - "rc", - "derive", + "rc", + "derive", ] } serde_derive = { version = "1.0", default-features = false } serde_json = { version = "^1.0", default-features = false } @@ -85,70 +85,70 @@ sp-std = { version = "11.0.0", optional = true } thiserror = { workspace = true } thiserror-no-std = { version = "2.0.2" } tracing = { version = "0.1", default-features = false, features = [ - "attributes", + "attributes", ] } url = { version = "2", optional = true } uuid = { version = "1.5.0", default-features = false, features = ["serde"] } [build-dependencies] -glob = { workspace = true } +glob = { workspace = true } lazy_static = { workspace = true } -serde_json = { workspace = true } +serde_json = { workspace = true } [dev-dependencies] -assert_fs = { workspace = true } -criterion = { workspace = true } -insta = { workspace = true, features = ["json"] } -mockito = { workspace = true } -proptest = { workspace = true } -tempfile = { workspace = true } +assert_fs = { workspace = true } +criterion = { workspace = true } +insta = { workspace = true, features = ["json"] } +mockito = { workspace = true } +proptest = { workspace = true } +tempfile = { workspace = true } testcontainers = { workspace = true } -tokio = { workspace = true } +tokio = { workspace = true } [features] default = [] std = [ - "k256/std", - "sp-core/std", - "tracing/std", - "serde/std", - "serde_json/std", - "hex/std", - "scale-encode/std", - "futures/std", - "iri-string/std", - "chrono/std", - "anyhow/std", - "percent-encoding/std", - "opa", - "sp-core/full_crypto", - "url", - "reqwest", - "rust-embed", - "scale-encode/std", - "scale-decode/std", - "scale-info/std", - "uuid/v4", - "Inflector", - "serde_yaml", + "k256/std", + "sp-core/std", + "tracing/std", + "serde/std", + "serde_json/std", + "hex/std", + "scale-encode/std", + "futures/std", + "iri-string/std", + "chrono/std", + "anyhow/std", + "percent-encoding/std", + "opa", + "sp-core/full_crypto", + "url", + "reqwest", + "rust-embed", + "scale-encode/std", + "scale-decode/std", + "scale-info/std", + "uuid/v4", + "Inflector", + "serde_yaml", ] # Enable parity support, annoyingly lazy_static has a non standard way of enabling non_std parity-encoding = [ - "lazy_static/spin_no_std", - "parity-scale-codec", - "scale-info", - "scale-encode", - "scale-decode", + "lazy_static/spin_no_std", + "parity-scale-codec", + "scale-info", + "scale-encode", + "scale-decode", ] # At this point, LD should be a seperate crate diesel-bindings = ["diesel"] graphql-bindings = ["async-graphql"] json-ld = [ - "dep:json-ld", - "dep:json-syntax", - "dep:rdf-types", - "dep:hashbrown", - "dep:mime", - "dep:locspan", - "dep:iref", + "dep:json-ld", + "dep:json-syntax", + "dep:rdf-types", + "dep:hashbrown", + "dep:mime", + "dep:locspan", + "dep:iref", ] diff --git a/crates/common/build.rs b/crates/common/build.rs index 2c02a6c5c..441139bb0 100644 --- a/crates/common/build.rs +++ b/crates/common/build.rs @@ -3,21 +3,21 @@ use std::{env, fs, io::Result, path::PathBuf}; include!("./src/context.rs"); fn main() -> Result<()> { - let out_str = env::var("OUT_DIR").unwrap(); - let out_path = PathBuf::from(&out_str); - let mut out_path = out_path.ancestors().nth(3).unwrap().to_owned(); - out_path.push("assets"); + let out_str = env::var("OUT_DIR").unwrap(); + let out_path = PathBuf::from(&out_str); + let mut out_path = out_path.ancestors().nth(3).unwrap().to_owned(); + out_path.push("assets"); - if !out_path.exists() { - fs::create_dir(&out_path).expect("Could not create assets dir"); - } + if !out_path.exists() { + fs::create_dir(&out_path).expect("Could not create assets dir"); + } - let context = &*PROV; + let context = &*PROV; - std::fs::write( - std::path::Path::new(&format!("{}/context.json", out_path.as_os_str().to_string_lossy(),)), - serde_json::to_string_pretty(context)?, - )?; + std::fs::write( + std::path::Path::new(&format!("{}/context.json", out_path.as_os_str().to_string_lossy(), )), + serde_json::to_string_pretty(context)?, + )?; - Ok(()) + Ok(()) } diff --git a/crates/common/src/attributes.rs b/crates/common/src/attributes.rs index 2b8c88869..102aa57c3 100644 --- a/crates/common/src/attributes.rs +++ b/crates/common/src/attributes.rs @@ -1,15 +1,14 @@ +#[cfg(feature = "std")] +use std::collections::BTreeSet; + +#[cfg(not(feature = "std"))] +use parity_scale_codec::{alloc::collections::BTreeMap, alloc::collections::BTreeSet, alloc::string::String, alloc::vec::Vec}; #[cfg(feature = "parity-encoding")] use parity_scale_codec::Encode; -#[cfg(not(feature = "std"))] -use parity_scale_codec::{alloc::collections::BTreeMap,alloc::collections::BTreeSet, alloc::string::String, alloc::vec::Vec}; #[cfg(feature = "parity-encoding")] use scale_encode::error::Kind; #[cfg(not(feature = "std"))] -use scale_info::{prelude::borrow::ToOwned, prelude::string::ToString, prelude::*}; -#[cfg(feature = "std")] -use std::collections::BTreeSet; - - +use scale_info::{prelude::*, prelude::borrow::ToOwned, prelude::string::ToString}; use serde_json::Value; use crate::prov::DomaintypeId; @@ -18,180 +17,180 @@ use crate::prov::DomaintypeId; pub struct SerdeWrapper(pub Value); impl core::fmt::Display for SerdeWrapper { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match serde_json::to_string(&self.0) { - Ok(json_string) => write!(f, "{}", json_string), - Err(e) => { - tracing::error!("Failed to serialize Value to JSON string: {}", e); - Err(core::fmt::Error) - }, - } - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match serde_json::to_string(&self.0) { + Ok(json_string) => write!(f, "{}", json_string), + Err(e) => { + tracing::error!("Failed to serialize Value to JSON string: {}", e); + Err(core::fmt::Error) + } + } + } } impl From for SerdeWrapper { - fn from(value: Value) -> Self { - SerdeWrapper(value) - } + fn from(value: Value) -> Self { + SerdeWrapper(value) + } } #[cfg(feature = "parity-encoding")] impl scale_encode::EncodeAsType for SerdeWrapper { - fn encode_as_type_to( - &self, - type_id: u32, - _types: &scale_info::PortableRegistry, - out: &mut scale_encode::Vec, - ) -> Result<(), scale_encode::Error> { - let json_string = match serde_json::to_string(&self.0) { - Ok(json_string) => json_string, - Err(e) => { - tracing::error!("Failed to serialize Value to JSON string: {}", e); - return Err(scale_encode::Error::new(scale_encode::error::ErrorKind::WrongShape { - actual: Kind::Str, - expected: type_id, - })); - }, - }; - json_string.encode_to(out); - Ok(()) - } + fn encode_as_type_to( + &self, + type_id: u32, + _types: &scale_info::PortableRegistry, + out: &mut scale_encode::Vec, + ) -> Result<(), scale_encode::Error> { + let json_string = match serde_json::to_string(&self.0) { + Ok(json_string) => json_string, + Err(e) => { + tracing::error!("Failed to serialize Value to JSON string: {}", e); + return Err(scale_encode::Error::new(scale_encode::error::ErrorKind::WrongShape { + actual: Kind::Str, + expected: type_id, + })); + } + }; + json_string.encode_to(out); + Ok(()) + } } #[cfg(feature = "parity-encoding")] impl parity_scale_codec::Encode for SerdeWrapper { - fn encode_to(&self, dest: &mut T) { - let json_string = - serde_json::to_string(&self.0).expect("Failed to serialize Value to JSON string"); - json_string.encode_to(dest); - } + fn encode_to(&self, dest: &mut T) { + let json_string = + serde_json::to_string(&self.0).expect("Failed to serialize Value to JSON string"); + json_string.encode_to(dest); + } } #[cfg(feature = "parity-encoding")] impl parity_scale_codec::Decode for SerdeWrapper { - fn decode( - input: &mut I, - ) -> Result { - let json_string = String::decode(input)?; - let value = serde_json::from_str(&json_string).map_err(|_| { - parity_scale_codec::Error::from("Failed to deserialize JSON string to Value") - })?; - Ok(SerdeWrapper(value)) - } + fn decode( + input: &mut I, + ) -> Result { + let json_string = String::decode(input)?; + let value = serde_json::from_str(&json_string).map_err(|_| { + parity_scale_codec::Error::from("Failed to deserialize JSON string to Value") + })?; + Ok(SerdeWrapper(value)) + } } #[cfg(feature = "parity-encoding")] impl scale_info::TypeInfo for SerdeWrapper { - type Identity = Self; + type Identity = Self; - fn type_info() -> scale_info::Type { - scale_info::Type::builder() - .path(scale_info::Path::new("SerdeWrapper", module_path!())) - .composite(scale_info::build::Fields::unnamed().field(|f| f.ty::())) - } + fn type_info() -> scale_info::Type { + scale_info::Type::builder() + .path(scale_info::Path::new("SerdeWrapper", module_path!())) + .composite(scale_info::build::Fields::unnamed().field(|f| f.ty::())) + } } impl From for Value { - fn from(wrapper: SerdeWrapper) -> Self { - wrapper.0 - } + fn from(wrapper: SerdeWrapper) -> Self { + wrapper.0 + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct Attribute { - pub typ: String, - pub value: SerdeWrapper, + pub typ: String, + pub value: SerdeWrapper, } impl core::fmt::Display for Attribute { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!( - f, - "Type: {}, Value: {}", - self.typ, - serde_json::to_string(&self.value.0).unwrap_or_else(|_| String::from("Invalid Value")) - ) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "Type: {}, Value: {}", + self.typ, + serde_json::to_string(&self.value.0).unwrap_or_else(|_| String::from("Invalid Value")) + ) + } } impl Attribute { - pub fn get_type(&self) -> &String { - &self.typ - } + pub fn get_type(&self) -> &String { + &self.typ + } - pub fn get_value(&self) -> &Value { - &self.value.0 - } + pub fn get_value(&self) -> &Value { + &self.value.0 + } - pub fn new(typ: impl AsRef, value: Value) -> Self { - Self { typ: typ.as_ref().to_owned(), value: value.into() } - } + pub fn new(typ: impl AsRef, value: Value) -> Self { + Self { typ: typ.as_ref().to_owned(), value: value.into() } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_encode::EncodeAsType, - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - ) + feature = "parity-encoding", + derive( + scale_encode::EncodeAsType, + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + ) )] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)] pub struct Attributes { - typ: Option, - items: Vec, + typ: Option, + items: Vec, } impl Attributes { - pub fn new(typ: Option, mut items: Vec) -> Self { - let mut seen_types = BTreeSet::new(); - items.retain(|attr| seen_types.insert(attr.typ.clone())); - items.sort_by(|a, b| a.typ.cmp(&b.typ)); - Self { typ, items } - } - - pub fn get_attribute(&self, key: &str) -> Option<&Attribute> { - self.items.iter().find(|&attribute| attribute.typ == key) - } - - #[tracing::instrument(skip(self))] - pub fn get_values(&self) -> Vec<&Attribute> { - self.items.iter().collect() - } - - pub fn type_only(typ: Option) -> Self { - Self { typ, items: Vec::new() } - } - - pub fn get_typ(&self) -> &Option { - &self.typ - } - - pub fn get_items(&self) -> &[Attribute] { - &self.items - } - - pub fn into_items(self) -> Vec { - self.items - } - - pub fn add_item(&mut self, value: Attribute) { - if !self.items.iter().any(|item| item.typ == value.typ) { - if let Some(pos) = self.items.iter().position(|item| item.typ > value.typ) { - self.items.insert(pos, value); - } else { - self.items.push(value); - } - } - } + pub fn new(typ: Option, mut items: Vec) -> Self { + let mut seen_types = BTreeSet::new(); + items.retain(|attr| seen_types.insert(attr.typ.clone())); + items.sort_by(|a, b| a.typ.cmp(&b.typ)); + Self { typ, items } + } + + pub fn get_attribute(&self, key: &str) -> Option<&Attribute> { + self.items.iter().find(|&attribute| attribute.typ == key) + } + + #[tracing::instrument(skip(self))] + pub fn get_values(&self) -> Vec<&Attribute> { + self.items.iter().collect() + } + + pub fn type_only(typ: Option) -> Self { + Self { typ, items: Vec::new() } + } + + pub fn get_typ(&self) -> &Option { + &self.typ + } + + pub fn get_items(&self) -> &[Attribute] { + &self.items + } + + pub fn into_items(self) -> Vec { + self.items + } + + pub fn add_item(&mut self, value: Attribute) { + if !self.items.iter().any(|item| item.typ == value.typ) { + if let Some(pos) = self.items.iter().position(|item| item.typ > value.typ) { + self.items.insert(pos, value); + } else { + self.items.push(value); + } + } + } } diff --git a/crates/common/src/domain.rs b/crates/common/src/domain.rs index 89c26a26e..c262d5463 100644 --- a/crates/common/src/domain.rs +++ b/crates/common/src/domain.rs @@ -1,8 +1,8 @@ use std::{collections::BTreeMap, path::Path, str::FromStr}; use inflector::cases::{ - camelcase::to_camel_case, kebabcase::to_kebab_case, pascalcase::to_pascal_case, - snakecase::to_snake_case, + camelcase::to_camel_case, kebabcase::to_kebab_case, pascalcase::to_pascal_case, + snakecase::to_snake_case, }; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -11,787 +11,786 @@ use crate::prov::DomaintypeId; #[derive(Debug, Error)] pub enum ModelError { - #[error("Attribute not defined argument: {attr}")] - AttributeNotDefined { attr: String }, - - #[error("Model file not readable: {0}")] - ModelFileNotReadable( - #[from] - #[source] - std::io::Error, - ), - - #[error("Model file invalid JSON: {0}")] - ModelFileInvalidJson( - #[from] - #[source] - serde_json::Error, - ), - - #[error("Model file invalid YAML: {0}")] - ModelFileInvalidYaml( - #[from] - #[source] - serde_yaml::Error, - ), + #[error("Attribute not defined argument: {attr}")] + AttributeNotDefined { attr: String }, + + #[error("Model file not readable: {0}")] + ModelFileNotReadable( + #[from] + #[source] + std::io::Error, + ), + + #[error("Model file invalid JSON: {0}")] + ModelFileInvalidJson( + #[from] + #[source] + serde_json::Error, + ), + + #[error("Model file invalid YAML: {0}")] + ModelFileInvalidYaml( + #[from] + #[source] + serde_yaml::Error, + ), } #[derive(Deserialize, Serialize, Debug, Copy, Clone, PartialEq, Eq)] pub enum PrimitiveType { - String, - Bool, - Int, - JSON, + String, + Bool, + Int, + JSON, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AttributeDef { - pub typ: String, - pub doc: Option, - pub primitive_type: PrimitiveType, + pub typ: String, + pub doc: Option, + pub primitive_type: PrimitiveType, } impl TypeName for AttributeDef { - fn as_type_name(&self) -> String { - to_pascal_case(&self.typ) - } - - fn preserve_inflection(&self) -> String { - match (self.typ.chars().next(), self.typ.chars().nth(1), &self.typ[1..]) { - (_, Some(c), _) if c.is_uppercase() => format!("{}Attribute", self.typ), - (Some(first), _, body) => format!("{}{}Attribute", first.to_lowercase(), body), - _ => format!("{}Attribute", self.typ), - } - } + fn as_type_name(&self) -> String { + to_pascal_case(&self.typ) + } + + fn preserve_inflection(&self) -> String { + match (self.typ.chars().next(), self.typ.chars().nth(1), &self.typ[1..]) { + (_, Some(c), _) if c.is_uppercase() => format!("{}Attribute", self.typ), + (Some(first), _, body) => format!("{}{}Attribute", first.to_lowercase(), body), + _ => format!("{}Attribute", self.typ), + } + } } impl AttributeDef { - pub fn as_scalar_type(&self) -> String { - match (self.typ.chars().next(), self.typ.chars().nth(1), &self.typ[1..]) { - (_, Some(c), _) if c.is_uppercase() => format!("{}Attribute", self.typ), - (Some(first), _, body) => format!("{}{}Attribute", first.to_uppercase(), body), - _ => format!("{}Attribute", self.as_type_name()), - } - } - - pub fn as_property(&self) -> String { - to_snake_case(&format!("{}Attribute", self.typ)) - } - - pub fn from_attribute_file_input(external_id: String, attr: AttributeFileInput) -> Self { - AttributeDef { typ: external_id, doc: attr.doc, primitive_type: attr.typ } - } + pub fn as_scalar_type(&self) -> String { + match (self.typ.chars().next(), self.typ.chars().nth(1), &self.typ[1..]) { + (_, Some(c), _) if c.is_uppercase() => format!("{}Attribute", self.typ), + (Some(first), _, body) => format!("{}{}Attribute", first.to_uppercase(), body), + _ => format!("{}Attribute", self.as_type_name()), + } + } + + pub fn as_property(&self) -> String { + to_snake_case(&format!("{}Attribute", self.typ)) + } + + pub fn from_attribute_file_input(external_id: String, attr: AttributeFileInput) -> Self { + AttributeDef { typ: external_id, doc: attr.doc, primitive_type: attr.typ } + } } /// A external_id formatted for CLI use - kebab-case, singular, lowercase pub trait CliName { - fn as_cli_name(&self) -> String; + fn as_cli_name(&self) -> String; } /// A correctly cased and singularized external_id for the type pub trait TypeName { - fn as_type_name(&self) -> String; - fn preserve_inflection(&self) -> String; + fn as_type_name(&self) -> String; + fn preserve_inflection(&self) -> String; - fn as_method_name(&self) -> String { - format!("define{}", self.as_type_name()) - } + fn as_method_name(&self) -> String { + format!("define{}", self.as_type_name()) + } - fn as_domain_type_id(&self) -> DomaintypeId { - DomaintypeId::from_external_id(self.as_type_name()) - } + fn as_domain_type_id(&self) -> DomaintypeId { + DomaintypeId::from_external_id(self.as_type_name()) + } } /// Entities, Activities and Agents have a specific set of attributes. pub trait AttributesTypeName { - fn attributes_type_name(&self) -> String; - fn attributes_type_name_preserve_inflection(&self) -> String; + fn attributes_type_name(&self) -> String; + fn attributes_type_name_preserve_inflection(&self) -> String; } pub trait Property { - fn as_property(&self) -> String; + fn as_property(&self) -> String; } impl AttributesTypeName for T -where - T: TypeName, + where + T: TypeName, { - fn attributes_type_name(&self) -> String { - to_pascal_case(&format!("{}Attributes", self.as_type_name())) - } + fn attributes_type_name(&self) -> String { + to_pascal_case(&format!("{}Attributes", self.as_type_name())) + } - fn attributes_type_name_preserve_inflection(&self) -> String { - format!("{}Attributes", self.as_type_name()) - } + fn attributes_type_name_preserve_inflection(&self) -> String { + format!("{}Attributes", self.as_type_name()) + } } impl CliName for T -where - T: TypeName, + where + T: TypeName, { - fn as_cli_name(&self) -> String { - to_kebab_case(&self.as_type_name()) - } + fn as_cli_name(&self) -> String { + to_kebab_case(&self.as_type_name()) + } } impl Property for T -where - T: TypeName, + where + T: TypeName, { - fn as_property(&self) -> String { - to_snake_case(&self.as_type_name()) - } + fn as_property(&self) -> String { + to_snake_case(&self.as_type_name()) + } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AgentDef { - pub external_id: String, - pub doc: Option, - pub attributes: Vec, + pub external_id: String, + pub doc: Option, + pub attributes: Vec, } impl TypeName for AgentDef { - fn as_type_name(&self) -> String { - type_name_for_kind("Agent", &self.external_id) - } + fn as_type_name(&self) -> String { + type_name_for_kind("Agent", &self.external_id) + } - fn preserve_inflection(&self) -> String { - preserve_inflection_for_kind("Agent", &self.external_id) - } + fn preserve_inflection(&self) -> String { + preserve_inflection_for_kind("Agent", &self.external_id) + } } impl<'a> TypeName for &'a AgentDef { - fn as_type_name(&self) -> String { - TypeName::as_type_name(*self) - } + fn as_type_name(&self) -> String { + TypeName::as_type_name(*self) + } - fn preserve_inflection(&self) -> String { - TypeName::preserve_inflection(*self) - } + fn preserve_inflection(&self) -> String { + TypeName::preserve_inflection(*self) + } } impl<'a> TypeName for &'a EntityDef { - fn as_type_name(&self) -> String { - TypeName::as_type_name(*self) - } + fn as_type_name(&self) -> String { + TypeName::as_type_name(*self) + } - fn preserve_inflection(&self) -> String { - TypeName::preserve_inflection(*self) - } + fn preserve_inflection(&self) -> String { + TypeName::preserve_inflection(*self) + } } impl<'a> TypeName for &'a ActivityDef { - fn as_type_name(&self) -> String { - TypeName::as_type_name(*self) - } + fn as_type_name(&self) -> String { + TypeName::as_type_name(*self) + } - fn preserve_inflection(&self) -> String { - TypeName::preserve_inflection(*self) - } + fn preserve_inflection(&self) -> String { + TypeName::preserve_inflection(*self) + } } impl AgentDef { - pub fn new( - external_id: impl AsRef, - doc: Option, - attributes: Vec, - ) -> Self { - Self { external_id: external_id.as_ref().to_string(), doc, attributes } - } - - pub fn from_input<'a>( - external_id: String, - doc: Option, - attributes: &BTreeMap, - attribute_references: impl Iterator, - ) -> Result { - Ok(Self { - external_id, - doc, - attributes: attribute_references - .map(|x| { - attributes - .get(&*x.0) - .ok_or_else(|| ModelError::AttributeNotDefined { attr: x.0.to_owned() }) - .map(|attr| AttributeDef { - typ: x.0.to_owned(), - doc: attr.doc.to_owned(), - primitive_type: attr.typ, - }) - }) - .collect::, _>>()?, - }) - } + pub fn new( + external_id: impl AsRef, + doc: Option, + attributes: Vec, + ) -> Self { + Self { external_id: external_id.as_ref().to_string(), doc, attributes } + } + + pub fn from_input<'a>( + external_id: String, + doc: Option, + attributes: &BTreeMap, + attribute_references: impl Iterator, + ) -> Result { + Ok(Self { + external_id, + doc, + attributes: attribute_references + .map(|x| { + attributes + .get(&*x.0) + .ok_or_else(|| ModelError::AttributeNotDefined { attr: x.0.to_owned() }) + .map(|attr| AttributeDef { + typ: x.0.to_owned(), + doc: attr.doc.to_owned(), + primitive_type: attr.typ, + }) + }) + .collect::, _>>()?, + }) + } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct EntityDef { - pub external_id: String, - pub doc: Option, - pub attributes: Vec, + pub external_id: String, + pub doc: Option, + pub attributes: Vec, } impl TypeName for EntityDef { - fn as_type_name(&self) -> String { - type_name_for_kind("Entity", &self.external_id) - } + fn as_type_name(&self) -> String { + type_name_for_kind("Entity", &self.external_id) + } - fn preserve_inflection(&self) -> String { - preserve_inflection_for_kind("Entity", &self.external_id) - } + fn preserve_inflection(&self) -> String { + preserve_inflection_for_kind("Entity", &self.external_id) + } } impl EntityDef { - pub fn new( - external_id: impl AsRef, - doc: Option, - attributes: Vec, - ) -> Self { - Self { external_id: external_id.as_ref().to_string(), doc, attributes } - } - - pub fn from_input<'a>( - external_id: String, - doc: Option, - attributes: &BTreeMap, - attribute_references: impl Iterator, - ) -> Result { - Ok(Self { - external_id, - doc, - attributes: attribute_references - .map(|x| { - attributes - .get(&*x.0) - .ok_or_else(|| ModelError::AttributeNotDefined { attr: x.0.to_owned() }) - .map(|attr| AttributeDef { - typ: x.0.to_owned(), - doc: attr.doc.to_owned(), - primitive_type: attr.typ, - }) - }) - .collect::, _>>()?, - }) - } + pub fn new( + external_id: impl AsRef, + doc: Option, + attributes: Vec, + ) -> Self { + Self { external_id: external_id.as_ref().to_string(), doc, attributes } + } + + pub fn from_input<'a>( + external_id: String, + doc: Option, + attributes: &BTreeMap, + attribute_references: impl Iterator, + ) -> Result { + Ok(Self { + external_id, + doc, + attributes: attribute_references + .map(|x| { + attributes + .get(&*x.0) + .ok_or_else(|| ModelError::AttributeNotDefined { attr: x.0.to_owned() }) + .map(|attr| AttributeDef { + typ: x.0.to_owned(), + doc: attr.doc.to_owned(), + primitive_type: attr.typ, + }) + }) + .collect::, _>>()?, + }) + } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ActivityDef { - pub external_id: String, - pub doc: Option, - pub attributes: Vec, + pub external_id: String, + pub doc: Option, + pub attributes: Vec, } impl TypeName for ActivityDef { - fn as_type_name(&self) -> String { - type_name_for_kind("Activity", &self.external_id) - } + fn as_type_name(&self) -> String { + type_name_for_kind("Activity", &self.external_id) + } - fn preserve_inflection(&self) -> String { - preserve_inflection_for_kind("Activity", &self.external_id) - } + fn preserve_inflection(&self) -> String { + preserve_inflection_for_kind("Activity", &self.external_id) + } } impl ActivityDef { - pub fn new( - external_id: impl AsRef, - doc: Option, - attributes: Vec, - ) -> Self { - Self { external_id: external_id.as_ref().to_string(), doc, attributes } - } - - pub fn from_input<'a>( - external_id: String, - doc: Option, - attributes: &BTreeMap, - attribute_references: impl Iterator, - ) -> Result { - Ok(Self { - external_id, - doc, - attributes: attribute_references - .map(|x| { - attributes - .get(&*x.0) - .ok_or_else(|| ModelError::AttributeNotDefined { attr: x.0.to_owned() }) - .map(|attr| AttributeDef { - typ: x.0.to_owned(), - doc: attr.doc.to_owned(), - primitive_type: attr.typ, - }) - }) - .collect::, _>>()?, - }) - } + pub fn new( + external_id: impl AsRef, + doc: Option, + attributes: Vec, + ) -> Self { + Self { external_id: external_id.as_ref().to_string(), doc, attributes } + } + + pub fn from_input<'a>( + external_id: String, + doc: Option, + attributes: &BTreeMap, + attribute_references: impl Iterator, + ) -> Result { + Ok(Self { + external_id, + doc, + attributes: attribute_references + .map(|x| { + attributes + .get(&*x.0) + .ok_or_else(|| ModelError::AttributeNotDefined { attr: x.0.to_owned() }) + .map(|attr| AttributeDef { + typ: x.0.to_owned(), + doc: attr.doc.to_owned(), + primitive_type: attr.typ, + }) + }) + .collect::, _>>()?, + }) + } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RoleDef { - pub external_id: String, + pub external_id: String, } impl RoleDef { - pub fn new(external_id: impl AsRef) -> Self { - Self { external_id: external_id.as_ref().to_string() } - } + pub fn new(external_id: impl AsRef) -> Self { + Self { external_id: external_id.as_ref().to_string() } + } - pub fn from_role_file_input(external_id: String) -> Self { - RoleDef { external_id } - } + pub fn from_role_file_input(external_id: String) -> Self { + RoleDef { external_id } + } } impl TypeName for &RoleDef { - fn as_type_name(&self) -> String { - to_pascal_case(&self.external_id) - } + fn as_type_name(&self) -> String { + to_pascal_case(&self.external_id) + } - fn preserve_inflection(&self) -> String { - self.external_id.clone() - } + fn preserve_inflection(&self) -> String { + self.external_id.clone() + } } fn type_name_for_kind(kind: &str, id: &str) -> String { - if id == format!("Prov{kind}") { - id.to_string() - } else { - match (id.chars().next(), id.chars().nth(1), &id[1..]) { - (_, Some(c), _) if c.is_uppercase() => format!("{id}{kind}"), - (Some(first), _, body) => format!("{}{}{}", first.to_uppercase(), body, kind), - _ => format!("{}{}", to_pascal_case(id), kind), - } - } + if id == format!("Prov{kind}") { + id.to_string() + } else { + match (id.chars().next(), id.chars().nth(1), &id[1..]) { + (_, Some(c), _) if c.is_uppercase() => format!("{id}{kind}"), + (Some(first), _, body) => format!("{}{}{}", first.to_uppercase(), body, kind), + _ => format!("{}{}", to_pascal_case(id), kind), + } + } } fn preserve_inflection_for_kind(kind: &str, id: &str) -> String { - match (id.chars().next(), id.chars().nth(1), &id[1..]) { - (_, Some(c), _) if c.is_uppercase() => format!("{id}{kind}"), - (Some(first), _, body) => format!("{}{}{}", first.to_lowercase(), body, kind), - _ => to_camel_case(&format!("{id}{kind}")), - } + match (id.chars().next(), id.chars().nth(1), &id[1..]) { + (_, Some(c), _) if c.is_uppercase() => format!("{id}{kind}"), + (Some(first), _, body) => format!("{}{}{}", first.to_lowercase(), body, kind), + _ => to_camel_case(&format!("{id}{kind}")), + } } #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct ChronicleDomainDef { - name: String, - pub attributes: Vec, - pub agents: Vec, - pub entities: Vec, - pub activities: Vec, - pub roles_doc: Option, - pub roles: Vec, + name: String, + pub attributes: Vec, + pub agents: Vec, + pub entities: Vec, + pub activities: Vec, + pub roles_doc: Option, + pub roles: Vec, } pub struct AgentBuilder<'a>(&'a ChronicleDomainDef, AgentDef); impl<'a> AgentBuilder<'a> { - pub fn new( - domain: &'a ChronicleDomainDef, - external_id: impl AsRef, - doc: Option, - ) -> Self { - Self(domain, AgentDef::new(external_id, doc, vec![])) - } - - pub fn with_attribute(mut self, typ: impl AsRef) -> Result { - let attr = self - .0 - .attribute(typ.as_ref()) - .ok_or(ModelError::AttributeNotDefined { attr: typ.as_ref().to_string() })?; - self.1.attributes.push(attr); - Ok(self) - } + pub fn new( + domain: &'a ChronicleDomainDef, + external_id: impl AsRef, + doc: Option, + ) -> Self { + Self(domain, AgentDef::new(external_id, doc, vec![])) + } + + pub fn with_attribute(mut self, typ: impl AsRef) -> Result { + let attr = self + .0 + .attribute(typ.as_ref()) + .ok_or(ModelError::AttributeNotDefined { attr: typ.as_ref().to_string() })?; + self.1.attributes.push(attr); + Ok(self) + } } impl<'a> From> for AgentDef { - fn from(val: AgentBuilder<'a>) -> Self { - val.1 - } + fn from(val: AgentBuilder<'a>) -> Self { + val.1 + } } pub struct EntityBuilder<'a>(&'a ChronicleDomainDef, EntityDef); impl<'a> EntityBuilder<'a> { - pub fn new( - domain: &'a ChronicleDomainDef, - external_id: impl AsRef, - doc: Option, - ) -> Self { - Self(domain, EntityDef::new(external_id, doc, vec![])) - } - - pub fn with_attribute(mut self, typ: impl AsRef) -> Result { - let attr = self - .0 - .attribute(typ.as_ref()) - .ok_or(ModelError::AttributeNotDefined { attr: typ.as_ref().to_string() })?; - self.1.attributes.push(attr); - Ok(self) - } + pub fn new( + domain: &'a ChronicleDomainDef, + external_id: impl AsRef, + doc: Option, + ) -> Self { + Self(domain, EntityDef::new(external_id, doc, vec![])) + } + + pub fn with_attribute(mut self, typ: impl AsRef) -> Result { + let attr = self + .0 + .attribute(typ.as_ref()) + .ok_or(ModelError::AttributeNotDefined { attr: typ.as_ref().to_string() })?; + self.1.attributes.push(attr); + Ok(self) + } } impl<'a> From> for EntityDef { - fn from(val: EntityBuilder<'a>) -> Self { - val.1 - } + fn from(val: EntityBuilder<'a>) -> Self { + val.1 + } } pub struct ActivityBuilder<'a>(&'a ChronicleDomainDef, ActivityDef); impl<'a> ActivityBuilder<'a> { - pub fn new( - domain: &'a ChronicleDomainDef, - external_id: impl AsRef, - doc: Option, - ) -> Self { - Self(domain, ActivityDef::new(external_id, doc, vec![])) - } - - pub fn with_attribute(mut self, typ: impl AsRef) -> Result { - let attr = self - .0 - .attribute(typ.as_ref()) - .ok_or(ModelError::AttributeNotDefined { attr: typ.as_ref().to_string() })?; - self.1.attributes.push(attr); - Ok(self) - } + pub fn new( + domain: &'a ChronicleDomainDef, + external_id: impl AsRef, + doc: Option, + ) -> Self { + Self(domain, ActivityDef::new(external_id, doc, vec![])) + } + + pub fn with_attribute(mut self, typ: impl AsRef) -> Result { + let attr = self + .0 + .attribute(typ.as_ref()) + .ok_or(ModelError::AttributeNotDefined { attr: typ.as_ref().to_string() })?; + self.1.attributes.push(attr); + Ok(self) + } } impl<'a> From> for ActivityDef { - fn from(val: ActivityBuilder<'a>) -> Self { - val.1 - } + fn from(val: ActivityBuilder<'a>) -> Self { + val.1 + } } pub struct Builder(ChronicleDomainDef); impl Builder { - pub fn new(name: impl AsRef) -> Self { - Builder(ChronicleDomainDef { name: name.as_ref().to_string(), ..Default::default() }) - } - - pub fn with_attribute_type( - mut self, - external_id: impl AsRef, - doc: Option, - typ: PrimitiveType, - ) -> Result { - self.0.attributes.push(AttributeDef { - typ: external_id.as_ref().to_string(), - doc, - primitive_type: typ, - }); - - Ok(self) - } - - pub fn with_agent( - mut self, - external_id: impl AsRef, - doc: Option, - b: impl FnOnce(AgentBuilder<'_>) -> Result, ModelError>, - ) -> Result { - self.0 - .agents - .push(b(AgentBuilder(&self.0, AgentDef::new(external_id, doc, vec![])))?.into()); - Ok(self) - } - - pub fn with_entity( - mut self, - external_id: impl AsRef, - doc: Option, - b: impl FnOnce(EntityBuilder<'_>) -> Result, ModelError>, - ) -> Result { - self.0 - .entities - .push(b(EntityBuilder(&self.0, EntityDef::new(external_id, doc, vec![])))?.into()); - Ok(self) - } - - pub fn with_activity( - mut self, - external_id: impl AsRef, - doc: Option, - b: impl FnOnce(ActivityBuilder<'_>) -> Result, ModelError>, - ) -> Result { - self.0 - .activities - .push(b(ActivityBuilder(&self.0, ActivityDef::new(external_id, doc, vec![])))?.into()); - - Ok(self) - } - - pub fn with_role(mut self, external_id: impl AsRef) -> Result { - self.0.roles.push(RoleDef::new(external_id)); - - Ok(self) - } - - pub fn build(self) -> ChronicleDomainDef { - self.0 - } + pub fn new(name: impl AsRef) -> Self { + Builder(ChronicleDomainDef { name: name.as_ref().to_string(), ..Default::default() }) + } + + pub fn with_attribute_type( + mut self, + external_id: impl AsRef, + doc: Option, + typ: PrimitiveType, + ) -> Result { + self.0.attributes.push(AttributeDef { + typ: external_id.as_ref().to_string(), + doc, + primitive_type: typ, + }); + + Ok(self) + } + + pub fn with_agent( + mut self, + external_id: impl AsRef, + doc: Option, + b: impl FnOnce(AgentBuilder<'_>) -> Result, ModelError>, + ) -> Result { + self.0 + .agents + .push(b(AgentBuilder(&self.0, AgentDef::new(external_id, doc, vec![])))?.into()); + Ok(self) + } + + pub fn with_entity( + mut self, + external_id: impl AsRef, + doc: Option, + b: impl FnOnce(EntityBuilder<'_>) -> Result, ModelError>, + ) -> Result { + self.0 + .entities + .push(b(EntityBuilder(&self.0, EntityDef::new(external_id, doc, vec![])))?.into()); + Ok(self) + } + + pub fn with_activity( + mut self, + external_id: impl AsRef, + doc: Option, + b: impl FnOnce(ActivityBuilder<'_>) -> Result, ModelError>, + ) -> Result { + self.0 + .activities + .push(b(ActivityBuilder(&self.0, ActivityDef::new(external_id, doc, vec![])))?.into()); + + Ok(self) + } + + pub fn with_role(mut self, external_id: impl AsRef) -> Result { + self.0.roles.push(RoleDef::new(external_id)); + + Ok(self) + } + + pub fn build(self) -> ChronicleDomainDef { + self.0 + } } #[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)] pub struct AttributeFileInput { - doc: Option, - #[serde(rename = "type")] - typ: PrimitiveType, + doc: Option, + #[serde(rename = "type")] + typ: PrimitiveType, } impl From<&AttributeDef> for AttributeFileInput { - fn from(attr: &AttributeDef) -> Self { - Self { doc: attr.doc.to_owned(), typ: attr.primitive_type } - } + fn from(attr: &AttributeDef) -> Self { + Self { doc: attr.doc.to_owned(), typ: attr.primitive_type } + } } #[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)] - pub struct AttributeRef(pub String); #[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)] pub struct ResourceDef { - pub doc: Option, - pub attributes: Vec, + pub doc: Option, + pub attributes: Vec, } impl From<&AgentDef> for ResourceDef { - fn from(agent: &AgentDef) -> Self { - Self { - doc: agent.doc.to_owned(), - attributes: agent - .attributes - .iter() - .map(|attr| AttributeRef(attr.typ.to_owned())) - .collect(), - } - } + fn from(agent: &AgentDef) -> Self { + Self { + doc: agent.doc.to_owned(), + attributes: agent + .attributes + .iter() + .map(|attr| AttributeRef(attr.typ.to_owned())) + .collect(), + } + } } impl From<&EntityDef> for ResourceDef { - fn from(entity: &EntityDef) -> Self { - Self { - doc: entity.doc.to_owned(), - attributes: entity - .attributes - .iter() - .map(|attr| AttributeRef(attr.typ.to_owned())) - .collect(), - } - } + fn from(entity: &EntityDef) -> Self { + Self { + doc: entity.doc.to_owned(), + attributes: entity + .attributes + .iter() + .map(|attr| AttributeRef(attr.typ.to_owned())) + .collect(), + } + } } impl From<&ActivityDef> for ResourceDef { - fn from(activity: &ActivityDef) -> Self { - Self { - doc: activity.doc.to_owned(), - attributes: activity - .attributes - .iter() - .map(|attr| AttributeRef(attr.typ.to_owned())) - .collect(), - } - } + fn from(activity: &ActivityDef) -> Self { + Self { + doc: activity.doc.to_owned(), + attributes: activity + .attributes + .iter() + .map(|attr| AttributeRef(attr.typ.to_owned())) + .collect(), + } + } } #[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Default)] pub struct DomainFileInput { - pub name: String, - pub attributes: BTreeMap, - pub agents: BTreeMap, - pub entities: BTreeMap, - pub activities: BTreeMap, - pub roles_doc: Option, - pub roles: Vec, + pub name: String, + pub attributes: BTreeMap, + pub agents: BTreeMap, + pub entities: BTreeMap, + pub activities: BTreeMap, + pub roles_doc: Option, + pub roles: Vec, } impl DomainFileInput { - pub fn new(name: impl AsRef) -> Self { - DomainFileInput { name: name.as_ref().to_string(), ..Default::default() } - } + pub fn new(name: impl AsRef) -> Self { + DomainFileInput { name: name.as_ref().to_string(), ..Default::default() } + } } impl FromStr for DomainFileInput { - type Err = ModelError; - - fn from_str(s: &str) -> Result { - match serde_json::from_str::(s) { - Err(_) => Ok(serde_yaml::from_str::(s)?), - Ok(domain) => Ok(domain), - } - } + type Err = ModelError; + + fn from_str(s: &str) -> Result { + match serde_json::from_str::(s) { + Err(_) => Ok(serde_yaml::from_str::(s)?), + Ok(domain) => Ok(domain), + } + } } impl From<&ChronicleDomainDef> for DomainFileInput { - fn from(domain: &ChronicleDomainDef) -> Self { - let mut file = Self::new(&domain.name); - - for attr in &domain.attributes { - let external_id = attr.typ.to_string(); - file.attributes.insert(external_id, attr.into()); - } - - file.agents = domain - .agents - .iter() - .map(|x| (x.external_id.clone(), ResourceDef::from(x))) - .collect(); - - file.entities = domain - .entities - .iter() - .map(|x| (x.external_id.clone(), ResourceDef::from(x))) - .collect(); - - file.activities = domain - .activities - .iter() - .map(|x| (x.external_id.clone(), ResourceDef::from(x))) - .collect(); - - file.roles_doc = domain.roles_doc.to_owned(); - - file.roles = domain.roles.iter().map(|x| x.as_type_name()).collect(); - - file - } + fn from(domain: &ChronicleDomainDef) -> Self { + let mut file = Self::new(&domain.name); + + for attr in &domain.attributes { + let external_id = attr.typ.to_string(); + file.attributes.insert(external_id, attr.into()); + } + + file.agents = domain + .agents + .iter() + .map(|x| (x.external_id.clone(), ResourceDef::from(x))) + .collect(); + + file.entities = domain + .entities + .iter() + .map(|x| (x.external_id.clone(), ResourceDef::from(x))) + .collect(); + + file.activities = domain + .activities + .iter() + .map(|x| (x.external_id.clone(), ResourceDef::from(x))) + .collect(); + + file.roles_doc = domain.roles_doc.to_owned(); + + file.roles = domain.roles.iter().map(|x| x.as_type_name()).collect(); + + file + } } impl ChronicleDomainDef { - pub fn build(external_id: &str) -> Builder { - Builder::new(external_id) - } - - fn attribute(&self, attr: &str) -> Option { - self.attributes.iter().find(|a| a.typ == attr).cloned() - } - - pub fn from_input_string(s: &str) -> Result { - ChronicleDomainDef::from_str(s) - } - - fn from_json(file: &str) -> Result { - let model = serde_json::from_str::(file)?; - Self::from_model(model) - } - - fn from_yaml(file: &str) -> Result { - let model = serde_yaml::from_str::(file)?; - Self::from_model(model) - } - - pub fn from_file(path: impl AsRef) -> Result { - let path = path.as_ref(); - - let file: String = std::fs::read_to_string(path)?; - - match path.extension() { - Some(ext) if ext == "json" => Self::from_json(&file), - _ => Self::from_yaml(&file), - } - } - - fn from_model(model: DomainFileInput) -> Result { - let mut builder = Builder::new(model.name); - - for (external_id, attr) in model.attributes.iter() { - builder = builder.with_attribute_type(external_id, attr.doc.to_owned(), attr.typ)?; - } - - for (external_id, def) in model.agents { - builder.0.agents.push(AgentDef::from_input( - external_id, - def.doc, - &model.attributes, - def.attributes.iter(), - )?) - } - - for (external_id, def) in model.entities { - builder.0.entities.push(EntityDef::from_input( - external_id, - def.doc, - &model.attributes, - def.attributes.iter(), - )?) - } - - for (external_id, def) in model.activities { - builder.0.activities.push(ActivityDef::from_input( - external_id, - def.doc, - &model.attributes, - def.attributes.iter(), - )?) - } - - if model.roles_doc.is_some() { - builder.0.roles_doc = model.roles_doc; - } - - for role in model.roles { - builder.0.roles.push(RoleDef::from_role_file_input(role)); - } - - Ok(builder.build()) - } - - pub fn to_json_string(&self) -> Result { - let input: DomainFileInput = self.into(); - let json = serde_json::to_string(&input)?; - Ok(json) - } - - fn to_yaml_string(&self) -> Result { - let input: DomainFileInput = self.into(); - let yaml = serde_yaml::to_string(&input)?; - Ok(yaml) - } + pub fn build(external_id: &str) -> Builder { + Builder::new(external_id) + } + + fn attribute(&self, attr: &str) -> Option { + self.attributes.iter().find(|a| a.typ == attr).cloned() + } + + pub fn from_input_string(s: &str) -> Result { + ChronicleDomainDef::from_str(s) + } + + fn from_json(file: &str) -> Result { + let model = serde_json::from_str::(file)?; + Self::from_model(model) + } + + fn from_yaml(file: &str) -> Result { + let model = serde_yaml::from_str::(file)?; + Self::from_model(model) + } + + pub fn from_file(path: impl AsRef) -> Result { + let path = path.as_ref(); + + let file: String = std::fs::read_to_string(path)?; + + match path.extension() { + Some(ext) if ext == "json" => Self::from_json(&file), + _ => Self::from_yaml(&file), + } + } + + fn from_model(model: DomainFileInput) -> Result { + let mut builder = Builder::new(model.name); + + for (external_id, attr) in model.attributes.iter() { + builder = builder.with_attribute_type(external_id, attr.doc.to_owned(), attr.typ)?; + } + + for (external_id, def) in model.agents { + builder.0.agents.push(AgentDef::from_input( + external_id, + def.doc, + &model.attributes, + def.attributes.iter(), + )?) + } + + for (external_id, def) in model.entities { + builder.0.entities.push(EntityDef::from_input( + external_id, + def.doc, + &model.attributes, + def.attributes.iter(), + )?) + } + + for (external_id, def) in model.activities { + builder.0.activities.push(ActivityDef::from_input( + external_id, + def.doc, + &model.attributes, + def.attributes.iter(), + )?) + } + + if model.roles_doc.is_some() { + builder.0.roles_doc = model.roles_doc; + } + + for role in model.roles { + builder.0.roles.push(RoleDef::from_role_file_input(role)); + } + + Ok(builder.build()) + } + + pub fn to_json_string(&self) -> Result { + let input: DomainFileInput = self.into(); + let json = serde_json::to_string(&input)?; + Ok(json) + } + + fn to_yaml_string(&self) -> Result { + let input: DomainFileInput = self.into(); + let yaml = serde_yaml::to_string(&input)?; + Ok(yaml) + } } /// Parse from a yaml formatted string impl FromStr for ChronicleDomainDef { - type Err = ModelError; + type Err = ModelError; - fn from_str(s: &str) -> Result { - Self::from_yaml(s) - } + fn from_str(s: &str) -> Result { + Self::from_yaml(s) + } } #[cfg(test)] pub mod test { - use super::{ChronicleDomainDef, DomainFileInput, EntityDef}; + use super::{ChronicleDomainDef, DomainFileInput, EntityDef}; - use std::cmp::Ordering; + use std::cmp::Ordering; - impl PartialEq for EntityDef { - fn eq(&self, other: &Self) -> bool { - self.external_id == other.external_id - } - } + impl PartialEq for EntityDef { + fn eq(&self, other: &Self) -> bool { + self.external_id == other.external_id + } + } - impl Eq for EntityDef {} + impl Eq for EntityDef {} - impl PartialOrd for EntityDef { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } + impl PartialOrd for EntityDef { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } - impl Ord for EntityDef { - fn cmp(&self, other: &Self) -> Ordering { - self.external_id.cmp(&other.external_id) - } - } + impl Ord for EntityDef { + fn cmp(&self, other: &Self) -> Ordering { + self.external_id.cmp(&other.external_id) + } + } - use assert_fs::prelude::*; + use assert_fs::prelude::*; - fn create_test_yaml_file() -> Result> { - let file = assert_fs::NamedTempFile::new("test.yml")?; - file.write_str( - r#" + fn create_test_yaml_file() -> Result> { + let file = assert_fs::NamedTempFile::new("test.yml")?; + file.write_str( + r#" name: "chronicle" attributes: String: @@ -831,16 +830,15 @@ pub mod test { roles: - drummer "#, - )?; - Ok(file) - } - - // more than one entity will be in no particular order - fn create_test_yaml_file_single_entity( - ) -> Result> { - let file = assert_fs::NamedTempFile::new("test.yml")?; - file.write_str( - r#" + )?; + Ok(file) + } + + // more than one entity will be in no particular order + fn create_test_yaml_file_single_entity() -> Result> { + let file = assert_fs::NamedTempFile::new("test.yml")?; + file.write_str( + r#" name: "test" attributes: String: @@ -860,14 +858,14 @@ pub mod test { roles: - drummer "#, - )?; - Ok(file) - } - - fn create_test_json_file() -> Result> { - let file = assert_fs::NamedTempFile::new("test.json")?; - file.write_str( - r#" { + )?; + Ok(file) + } + + fn create_test_json_file() -> Result> { + let file = assert_fs::NamedTempFile::new("test.json")?; + file.write_str( + r#" { "name": "chronicle", "attributes": { "String": { @@ -903,19 +901,19 @@ pub mod test { "roles" : ["drummer"] } "#, - )?; - Ok(file) - } + )?; + Ok(file) + } - #[test] - fn json_from_file() -> Result<(), Box> { - let file = create_test_json_file()?; + #[test] + fn json_from_file() -> Result<(), Box> { + let file = create_test_json_file()?; - let mut domain = ChronicleDomainDef::from_file(file.path()).unwrap(); + let mut domain = ChronicleDomainDef::from_file(file.path()).unwrap(); - domain.entities.sort(); + domain.entities.sort(); - insta::assert_yaml_snapshot!(domain, @r###" + insta::assert_yaml_snapshot!(domain, @r###" --- name: chronicle attributes: @@ -954,18 +952,18 @@ pub mod test { - external_id: drummer "###); - Ok(()) - } + Ok(()) + } - #[test] - fn yaml_from_file() -> Result<(), Box> { - let file = create_test_yaml_file()?; + #[test] + fn yaml_from_file() -> Result<(), Box> { + let file = create_test_yaml_file()?; - let mut domain = ChronicleDomainDef::from_file(file.path()).unwrap(); + let mut domain = ChronicleDomainDef::from_file(file.path()).unwrap(); - domain.entities.sort(); + domain.entities.sort(); - insta::assert_yaml_snapshot!(domain, @r###" + insta::assert_yaml_snapshot!(domain, @r###" --- name: chronicle attributes: @@ -1046,18 +1044,18 @@ pub mod test { - external_id: drummer "###); - Ok(()) - } + Ok(()) + } - use std::str::FromStr; + use std::str::FromStr; - #[test] - fn test_chronicle_domain_def_from_str() -> Result<(), Box> { - let file = create_test_yaml_file()?; - let s: String = std::fs::read_to_string(file.path())?; - let domain = ChronicleDomainDef::from_str(&s)?; + #[test] + fn test_chronicle_domain_def_from_str() -> Result<(), Box> { + let file = create_test_yaml_file()?; + let s: String = std::fs::read_to_string(file.path())?; + let domain = ChronicleDomainDef::from_str(&s)?; - insta::assert_yaml_snapshot!(domain, @r###" + insta::assert_yaml_snapshot!(domain, @r###" --- name: chronicle attributes: @@ -1138,17 +1136,17 @@ pub mod test { - external_id: drummer "###); - Ok(()) - } + Ok(()) + } - #[test] - fn test_from_domain_for_file_input() -> Result<(), Box> { - let file = create_test_yaml_file_single_entity()?; - let s: String = std::fs::read_to_string(file.path())?; - let domain = ChronicleDomainDef::from_str(&s)?; - let input = DomainFileInput::from(&domain); + #[test] + fn test_from_domain_for_file_input() -> Result<(), Box> { + let file = create_test_yaml_file_single_entity()?; + let s: String = std::fs::read_to_string(file.path())?; + let domain = ChronicleDomainDef::from_str(&s)?; + let input = DomainFileInput::from(&domain); - insta::assert_yaml_snapshot!(input, @r###" + insta::assert_yaml_snapshot!(input, @r###" --- name: test attributes: @@ -1175,33 +1173,33 @@ pub mod test { - Drummer "###); - Ok(()) - } + Ok(()) + } - use super::{AttributeDef, AttributeFileInput, PrimitiveType}; + use super::{AttributeDef, AttributeFileInput, PrimitiveType}; - #[test] - fn test_from_attribute_def_for_attribute_file_input() { - let attr = AttributeDef { - typ: "string".to_string(), - doc: None, - primitive_type: PrimitiveType::String, - }; - let input = AttributeFileInput::from(&attr); - insta::assert_yaml_snapshot!(input, @r###" + #[test] + fn test_from_attribute_def_for_attribute_file_input() { + let attr = AttributeDef { + typ: "string".to_string(), + doc: None, + primitive_type: PrimitiveType::String, + }; + let input = AttributeFileInput::from(&attr); + insta::assert_yaml_snapshot!(input, @r###" --- doc: ~ type: String "###); - } + } - #[test] - fn test_to_json_string() -> Result<(), Box> { - let file = create_test_yaml_file_single_entity()?; - let s: String = std::fs::read_to_string(file.path())?; - let domain = ChronicleDomainDef::from_str(&s)?; + #[test] + fn test_to_json_string() -> Result<(), Box> { + let file = create_test_yaml_file_single_entity()?; + let s: String = std::fs::read_to_string(file.path())?; + let domain = ChronicleDomainDef::from_str(&s)?; - insta::assert_yaml_snapshot!(domain, @r###" + insta::assert_yaml_snapshot!(domain, @r###" --- name: test attributes: @@ -1234,16 +1232,16 @@ pub mod test { - external_id: drummer "###); - Ok(()) - } + Ok(()) + } - #[test] - fn test_to_yaml_string() -> Result<(), Box> { - let file = create_test_yaml_file_single_entity()?; - let s: String = std::fs::read_to_string(file.path())?; - let domain = ChronicleDomainDef::from_str(&s)?; + #[test] + fn test_to_yaml_string() -> Result<(), Box> { + let file = create_test_yaml_file_single_entity()?; + let s: String = std::fs::read_to_string(file.path())?; + let domain = ChronicleDomainDef::from_str(&s)?; - insta::assert_yaml_snapshot!(domain, @r###" + insta::assert_yaml_snapshot!(domain, @r###" --- name: test attributes: @@ -1276,14 +1274,13 @@ pub mod test { - external_id: drummer "###); - Ok(()) - } + Ok(()) + } - fn create_test_yaml_file_with_acronyms( - ) -> Result> { - let file = assert_fs::NamedTempFile::new("test.yml")?; - file.write_str( - r#" + fn create_test_yaml_file_with_acronyms() -> Result> { + let file = assert_fs::NamedTempFile::new("test.yml")?; + file.write_str( + r#" name: "evidence" attributes: Content: @@ -1339,19 +1336,19 @@ pub mod test { - RESEARCHER - EDITOR "#, - )?; - Ok(file) - } - - #[test] - fn test_from_domain_for_file_input_with_inflections() -> Result<(), Box> - { - let file = create_test_yaml_file_with_acronyms()?; - let s: String = std::fs::read_to_string(file.path())?; - let domain = ChronicleDomainDef::from_str(&s)?; - let input = DomainFileInput::from(&domain); - - insta::assert_yaml_snapshot!(input, @r###" + )?; + Ok(file) + } + + #[test] + fn test_from_domain_for_file_input_with_inflections() -> Result<(), Box> + { + let file = create_test_yaml_file_with_acronyms()?; + let s: String = std::fs::read_to_string(file.path())?; + let domain = ChronicleDomainDef::from_str(&s)?; + let input = DomainFileInput::from(&domain); + + insta::assert_yaml_snapshot!(input, @r###" --- name: evidence attributes: @@ -1425,13 +1422,12 @@ pub mod test { - Researcher - Editor "###); - Ok(()) - } + Ok(()) + } - fn create_test_yaml_file_with_docs( - ) -> Result> { - let file = assert_fs::NamedTempFile::new("test.yml")?; - file.write_str( + fn create_test_yaml_file_with_docs() -> Result> { + let file = assert_fs::NamedTempFile::new("test.yml")?; + file.write_str( r#" name: Artworld attributes: @@ -1560,17 +1556,17 @@ pub mod test { - CREATOR "#, )?; - Ok(file) - } + Ok(file) + } - #[test] - fn test_from_domain_for_file_input_with_docs() -> Result<(), Box> { - let file = create_test_yaml_file_with_docs()?; - let s: String = std::fs::read_to_string(file.path())?; - let domain = ChronicleDomainDef::from_str(&s)?; - let input = DomainFileInput::from(&domain); + #[test] + fn test_from_domain_for_file_input_with_docs() -> Result<(), Box> { + let file = create_test_yaml_file_with_docs()?; + let s: String = std::fs::read_to_string(file.path())?; + let domain = ChronicleDomainDef::from_str(&s)?; + let input = DomainFileInput::from(&domain); - insta::assert_yaml_snapshot!(input, @r###" + insta::assert_yaml_snapshot!(input, @r###" --- name: Artworld attributes: @@ -1631,6 +1627,6 @@ pub mod test { - Seller - Creator "###); - Ok(()) - } + Ok(()) + } } diff --git a/crates/common/src/identity.rs b/crates/common/src/identity.rs index 6ae5ca287..585aa4210 100644 --- a/crates/common/src/identity.rs +++ b/crates/common/src/identity.rs @@ -1,67 +1,65 @@ -use crate::prov::AgentId; +#[cfg(feature = "std")] +use std::collections::BTreeMap; +#[cfg(feature = "std")] +use std::collections::BTreeSet; use k256::sha2::{Digest, Sha512}; -use serde_json::{Map, Value}; -use tracing::warn; - #[cfg(not(feature = "std"))] use parity_scale_codec::{ - alloc::collections::BTreeMap, alloc::collections::BTreeSet, alloc::string::String, - alloc::vec::Vec, Decode, Encode, + alloc::collections::BTreeMap, alloc::collections::BTreeSet, alloc::string::String, + alloc::vec::Vec, Decode, Encode, }; #[cfg(not(feature = "std"))] -use scale_info::{prelude::borrow::ToOwned, prelude::string::ToString, prelude::*, TypeInfo}; -#[cfg(feature = "std")] -use std::collections::BTreeMap; - +use scale_info::{prelude::*, prelude::borrow::ToOwned, prelude::string::ToString, TypeInfo}; +use serde_json::{Map, Value}; #[cfg(feature = "std")] use thiserror::Error; #[cfg(not(feature = "std"))] use thiserror_no_std::Error; +use tracing::warn; -#[cfg(feature = "std")] -use std::collections::BTreeSet; +use crate::prov::AgentId; #[derive(Error, Debug)] pub enum IdentityError { - #[error("Failed to get agent id from JWT claims")] - JwtClaims, - - #[error("Signer : {0}")] - Signing( - #[from] - #[source] - anyhow::Error, - ), - - #[error("Malformed JSON: {0}")] - SerdeJson( - #[from] - #[source] - serde_json::Error, - ), - - #[error("Serialization error: {0}")] - SerdeJsonSerialize(String), + #[error("Failed to get agent id from JWT claims")] + JwtClaims, + + #[error("Signer : {0}")] + Signing( + #[from] + #[source] + anyhow::Error, + ), + + #[error("Malformed JSON: {0}")] + SerdeJson( + #[from] + #[source] + serde_json::Error, + ), + + #[error("Serialization error: {0}")] + SerdeJsonSerialize(String), } /// Contains the scalar ID and identity claims for a user established via JWT #[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] pub struct JwtId { - pub id: AgentId, - pub claims: Value, + pub id: AgentId, + pub claims: Value, } impl JwtId { - fn new(external_id: &str, claims: Value) -> Self { - Self { id: AgentId::from_external_id(external_id), claims } - } + fn new(external_id: &str, claims: Value) -> Self { + Self { id: AgentId::from_external_id(external_id), claims } + } } impl core::fmt::Debug for JwtId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - f.debug_struct("JwtId").field("id", &self.id).finish_non_exhaustive() - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + f.debug_struct("JwtId").field("id", &self.id).finish_non_exhaustive() + } } /// Claims from a JWT, referenced in creating an AgentId for a Chronicle user @@ -69,214 +67,217 @@ impl core::fmt::Debug for JwtId { pub struct JwtClaims(pub Map); impl core::fmt::Debug for JwtClaims { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - let claims = self.0.iter().map(|(k, _v)| (k, "***SECRET***")).collect::>(); - write!(f, "JwtClaims({:?})", claims) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + let claims = self.0.iter().map(|(k, _v)| (k, "***SECRET***")).collect::>(); + write!(f, "JwtClaims({:?})", claims) + } } /// Chronicle identity object for authorization #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] #[serde(rename_all = "lowercase", tag = "type")] pub enum AuthId { - Anonymous, - Chronicle, - JWT(JwtId), + Anonymous, + Chronicle, + JWT(JwtId), } impl core::fmt::Display for AuthId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::Anonymous => write!(f, "Anonymous"), - Self::Chronicle => write!(f, "Chronicle"), - Self::JWT(jwt_id) => write!(f, "{}", jwt_id.id), - } - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Anonymous => write!(f, "Anonymous"), + Self::Chronicle => write!(f, "Chronicle"), + Self::JWT(jwt_id) => write!(f, "{}", jwt_id.id), + } + } } impl TryFrom<&str> for AuthId { - type Error = serde_json::Error; + type Error = serde_json::Error; - fn try_from(s: &str) -> Result { - serde_json::from_str(s) - } + fn try_from(s: &str) -> Result { + serde_json::from_str(s) + } } impl AuthId { - /// Establish a Chronicle user via JWT using a provided pointer into the JWT claims, - /// caching the claims with the JWT user identity - pub fn from_jwt_claims( - JwtClaims(claims): &JwtClaims, - id_keys: &BTreeSet, - ) -> Result { - const ZERO: [u8; 1] = [0]; - - let mut hasher = Sha512::new(); - - for id_key in id_keys { - if let Some(Value::String(claim_value)) = claims.get(id_key) { - hasher.update(id_key.as_bytes()); - hasher.update(ZERO); - hasher.update(claim_value.as_bytes()); - hasher.update(ZERO); - } else { - let keys_available: Vec<&String> = claims.keys().collect(); - warn!( + /// Establish a Chronicle user via JWT using a provided pointer into the JWT claims, + /// caching the claims with the JWT user identity + pub fn from_jwt_claims( + JwtClaims(claims): &JwtClaims, + id_keys: &BTreeSet, + ) -> Result { + const ZERO: [u8; 1] = [0]; + + let mut hasher = Sha512::new(); + + for id_key in id_keys { + if let Some(Value::String(claim_value)) = claims.get(id_key) { + hasher.update(id_key.as_bytes()); + hasher.update(ZERO); + hasher.update(claim_value.as_bytes()); + hasher.update(ZERO); + } else { + let keys_available: Vec<&String> = claims.keys().collect(); + warn!( "For constructing Chronicle identity no {id_key:?} field among JWT claims: {keys_available:?}" ); - return Err(IdentityError::JwtClaims); - } - } - - Ok(Self::JWT(JwtId::new(&hex::encode(hasher.finalize()), Value::Object(claims.to_owned())))) - } - - /// Create an Anonymous Chronicle user - pub fn anonymous() -> Self { - Self::Anonymous - } - - /// Create a Chronicle super user - pub fn chronicle() -> Self { - Self::Chronicle - } - - /// Serialize identity to a JSON object containing "type" ("Anonymous", "Chronicle", or "JWT"), - /// and, in the case of a JWT identity, "id" fields - the Input for an OPA check - pub fn identity(&self) -> Result { - serde_json::to_value(self).map_err(|e| IdentityError::SerdeJsonSerialize(e.to_string())) - } + return Err(IdentityError::JwtClaims); + } + } + + Ok(Self::JWT(JwtId::new(&hex::encode(hasher.finalize()), Value::Object(claims.to_owned())))) + } + + /// Create an Anonymous Chronicle user + pub fn anonymous() -> Self { + Self::Anonymous + } + + /// Create a Chronicle super user + pub fn chronicle() -> Self { + Self::Chronicle + } + + /// Serialize identity to a JSON object containing "type" ("Anonymous", "Chronicle", or "JWT"), + /// and, in the case of a JWT identity, "id" fields - the Input for an OPA check + pub fn identity(&self) -> Result { + serde_json::to_value(self).map_err(|e| IdentityError::SerdeJsonSerialize(e.to_string())) + } } /// Context data for an OPA check - `operation` and `state` fields are /// equivalent to GraphQL parent type and path node #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Default)] struct Context { - operation: Value, - state: Value, + operation: Value, + state: Value, } /// Identity and Context data for an OPA check #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct IdentityContext { - identity: AuthId, - context: Context, + identity: AuthId, + context: Context, } impl IdentityContext { - pub fn new(identity: AuthId, operation: Value, state: Value) -> Self { - Self { identity, context: Context { operation, state } } - } + pub fn new(identity: AuthId, operation: Value, state: Value) -> Self { + Self { identity, context: Context { operation, state } } + } } /// Contextual data for OPA created either via GraphQL or in the Transaction Processor #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] #[serde(rename_all = "lowercase", tag = "type")] pub enum OpaData { - GraphQL(IdentityContext), - Operation(IdentityContext), + GraphQL(IdentityContext), + Operation(IdentityContext), } impl OpaData { - pub fn graphql(identity: &AuthId, parent_type: &Value, resolve_path: &Value) -> Self { - Self::GraphQL(IdentityContext::new( - identity.to_owned(), - parent_type.to_owned(), - resolve_path.to_owned(), - )) - } - - pub fn operation(identity: &AuthId, operation: &Value, state: &Value) -> Self { - Self::Operation(IdentityContext::new( - identity.to_owned(), - operation.to_owned(), - state.to_owned(), - )) - } + pub fn graphql(identity: &AuthId, parent_type: &Value, resolve_path: &Value) -> Self { + Self::GraphQL(IdentityContext::new( + identity.to_owned(), + parent_type.to_owned(), + resolve_path.to_owned(), + )) + } + + pub fn operation(identity: &AuthId, operation: &Value, state: &Value) -> Self { + Self::Operation(IdentityContext::new( + identity.to_owned(), + operation.to_owned(), + state.to_owned(), + )) + } } + /// Signed user identity containing the serialized identity, signature, and /// verifying key. Implements `TryFrom` to deserialize to the user identity object #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Clone, Debug, Eq, PartialEq)] pub struct SignedIdentity { - pub identity: String, - pub signature: Option>, - pub verifying_key: Option>, + pub identity: String, + pub signature: Option>, + pub verifying_key: Option>, } impl SignedIdentity { - fn new(id: &AuthId, signature: Vec, verifying_key: Vec) -> Result { - Ok(Self { - identity: serde_json::to_string(&id)?, - signature: Some(signature), - verifying_key: Some(verifying_key), - }) - } - - pub fn new_no_identity() -> Self { - Self { identity: "none".to_string(), signature: None, verifying_key: None } - } + fn new(id: &AuthId, signature: Vec, verifying_key: Vec) -> Result { + Ok(Self { + identity: serde_json::to_string(&id)?, + signature: Some(signature), + verifying_key: Some(verifying_key), + }) + } + + pub fn new_no_identity() -> Self { + Self { identity: "none".to_string(), signature: None, verifying_key: None } + } } impl TryFrom<&SignedIdentity> for AuthId { - type Error = serde_json::Error; + type Error = serde_json::Error; - fn try_from(signed_identity: &SignedIdentity) -> Result { - serde_json::from_str(&signed_identity.identity) - } + fn try_from(signed_identity: &SignedIdentity) -> Result { + serde_json::from_str(&signed_identity.identity) + } } #[cfg(test)] mod tests { - use super::*; - use crate::prov::{ExternalId, ExternalIdPart}; - use serde_json::json; - - fn external_id_from_jwt_claims<'a>(claim_strings: impl Iterator) -> ExternalId { - const ZERO: [u8; 1] = [0]; - let mut hasher = Sha512::new(); - claim_strings.for_each(|s| { - hasher.update(s.as_bytes()); - hasher.update(ZERO); - }); - hex::encode(hasher.finalize()).into() - } - - #[test] - fn test_auth_id_serialization() { - let auth_id = AuthId::anonymous(); - insta::assert_json_snapshot!(auth_id, @r###" + use serde_json::json; + + use crate::prov::{ExternalId, ExternalIdPart}; + + use super::*; + + fn external_id_from_jwt_claims<'a>(claim_strings: impl Iterator) -> ExternalId { + const ZERO: [u8; 1] = [0]; + let mut hasher = Sha512::new(); + claim_strings.for_each(|s| { + hasher.update(s.as_bytes()); + hasher.update(ZERO); + }); + hex::encode(hasher.finalize()).into() + } + + #[test] + fn test_auth_id_serialization() { + let auth_id = AuthId::anonymous(); + insta::assert_json_snapshot!(auth_id, @r###" { "type": "anonymous" } "###); - let auth_id = AuthId::chronicle(); - insta::assert_json_snapshot!(auth_id, @r###" + let auth_id = AuthId::chronicle(); + insta::assert_json_snapshot!(auth_id, @r###" { "type": "chronicle" } "###); - let claims = JwtClaims( - json!({ + let claims = JwtClaims( + json!({ "name": "abcdef", }) - .as_object() - .unwrap() - .to_owned(), - ); - let auth_id = - AuthId::from_jwt_claims(&claims, &BTreeSet::from(["name".to_string()])).unwrap(); - insta::assert_json_snapshot!(auth_id, @r###" + .as_object() + .unwrap() + .to_owned(), + ); + let auth_id = + AuthId::from_jwt_claims(&claims, &BTreeSet::from(["name".to_string()])).unwrap(); + insta::assert_json_snapshot!(auth_id, @r###" { "type": "jwt", "id": "6e7f57aeab5edb9bf5863ba2d749715b6f9a9079f3b8c81b6207d437c005b5b9f6f14de53c34c38ee0b1cc77fa6e02b5cef694faf5aaf028b58c15b3c4ee1cb0", @@ -286,59 +287,59 @@ mod tests { } "###); - if let AuthId::JWT(JwtId { id, .. }) = auth_id { - assert_eq!( - &external_id_from_jwt_claims(vec!["name", "abcdef"].into_iter()), - id.external_id_part() - ); - } else { - panic!("did not receive expected JWT identity: {auth_id}"); - } - } - - #[test] - fn test_auth_id_deserialization() { - let serialized = r#"{"type":"anonymous"}"#; - let deserialized: AuthId = serde_json::from_str(serialized).unwrap(); - assert_eq!(deserialized, AuthId::Anonymous); - - let serialized = r#"{"type":"chronicle"}"#; - let deserialized: AuthId = serde_json::from_str(serialized).unwrap(); - assert_eq!(deserialized, AuthId::Chronicle); - - let serialized = r#"{ + if let AuthId::JWT(JwtId { id, .. }) = auth_id { + assert_eq!( + &external_id_from_jwt_claims(vec!["name", "abcdef"].into_iter()), + id.external_id_part() + ); + } else { + panic!("did not receive expected JWT identity: {auth_id}"); + } + } + + #[test] + fn test_auth_id_deserialization() { + let serialized = r#"{"type":"anonymous"}"#; + let deserialized: AuthId = serde_json::from_str(serialized).unwrap(); + assert_eq!(deserialized, AuthId::Anonymous); + + let serialized = r#"{"type":"chronicle"}"#; + let deserialized: AuthId = serde_json::from_str(serialized).unwrap(); + assert_eq!(deserialized, AuthId::Chronicle); + + let serialized = r#"{ "type": "jwt", "id": "abcdef", "claims": { "name": "abcdef" } }"#; - let deserialized: AuthId = serde_json::from_str(serialized).unwrap(); - assert_eq!( - deserialized, - AuthId::JWT(JwtId { - id: AgentId::from_external_id("abcdef"), - claims: json!({ + let deserialized: AuthId = serde_json::from_str(serialized).unwrap(); + assert_eq!( + deserialized, + AuthId::JWT(JwtId { + id: AgentId::from_external_id("abcdef"), + claims: json!({ "name": "abcdef" - }) - }) - ); - } - - #[test] - fn test_auth_id_from_jwt_claims() { - let claims = JwtClaims( - json!({ + }), + }) + ); + } + + #[test] + fn test_auth_id_from_jwt_claims() { + let claims = JwtClaims( + json!({ "sub": "John Doe" }) - .as_object() - .unwrap() - .to_owned(), - ); - let auth_id = - AuthId::from_jwt_claims(&claims, &BTreeSet::from(["sub".to_string()])).unwrap(); - - insta::assert_json_snapshot!(auth_id, @r###" + .as_object() + .unwrap() + .to_owned(), + ); + let auth_id = + AuthId::from_jwt_claims(&claims, &BTreeSet::from(["sub".to_string()])).unwrap(); + + insta::assert_json_snapshot!(auth_id, @r###" { "type": "jwt", "id": "13cc0854e3c226984a47e3159be9d71dae9796586ae15c493a7dcb79c2c511be7b311a238439a6922b779014b2bc71f351ff388fcac012d4f20f161720fa0dcf", @@ -348,47 +349,47 @@ mod tests { } "###); - if let AuthId::JWT(JwtId { id, .. }) = auth_id { - assert_eq!( - &external_id_from_jwt_claims(vec!["sub", "John Doe"].into_iter()), - id.external_id_part() - ); - } else { - panic!("did not receive expected JWT identity: {auth_id}"); - } - } - - #[test] - fn test_auth_id_from_jwt_claims_failure() { - let claims = JwtClaims( - json!({ + if let AuthId::JWT(JwtId { id, .. }) = auth_id { + assert_eq!( + &external_id_from_jwt_claims(vec!["sub", "John Doe"].into_iter()), + id.external_id_part() + ); + } else { + panic!("did not receive expected JWT identity: {auth_id}"); + } + } + + #[test] + fn test_auth_id_from_jwt_claims_failure() { + let claims = JwtClaims( + json!({ "sub": "John Doe" }) - .as_object() - .unwrap() - .to_owned(), - ); - let auth_id_result = - AuthId::from_jwt_claims(&claims, &BTreeSet::from(["externalId".to_string()])); - assert!(auth_id_result.is_err()); - assert_eq!(auth_id_result.unwrap_err().to_string(), IdentityError::JwtClaims.to_string()); - } - - #[test] - fn test_opa_data_serialization() { - let identity = AuthId::Chronicle; - let operation = json!({ + .as_object() + .unwrap() + .to_owned(), + ); + let auth_id_result = + AuthId::from_jwt_claims(&claims, &BTreeSet::from(["externalId".to_string()])); + assert!(auth_id_result.is_err()); + assert_eq!(auth_id_result.unwrap_err().to_string(), IdentityError::JwtClaims.to_string()); + } + + #[test] + fn test_opa_data_serialization() { + let identity = AuthId::Chronicle; + let operation = json!({ "resource": "users", "action": "read" }); - let state = json!([{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]); - let context = OpaData::graphql(&identity, &operation, &state); + let state = json!([{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]); + let context = OpaData::graphql(&identity, &operation, &state); - let json = serde_json::to_string(&context).unwrap(); - let deserialized_context: OpaData = serde_json::from_str(&json).unwrap(); + let json = serde_json::to_string(&context).unwrap(); + let deserialized_context: OpaData = serde_json::from_str(&json).unwrap(); - assert!(context == deserialized_context); - insta::assert_json_snapshot!(context, @r###" + assert!(context == deserialized_context); + insta::assert_json_snapshot!(context, @r###" { "type": "graphql", "identity": { @@ -412,30 +413,30 @@ mod tests { } } "###); - } + } - #[test] - fn test_jwt_claims_custom_debug() { - let claims = JwtClaims( - json!({ + #[test] + fn test_jwt_claims_custom_debug() { + let claims = JwtClaims( + json!({ "key": "value", }) - .as_object() - .unwrap() - .to_owned(), - ); - insta::assert_debug_snapshot!(claims, @r###"JwtClaims({"key": "***SECRET***"})"###); - } - - #[test] - fn test_jwt_id_custom_debug() { - let jwt_id = AuthId::JWT(JwtId { - id: AgentId::from_external_id("abcdef"), - claims: json!({ + .as_object() + .unwrap() + .to_owned(), + ); + insta::assert_debug_snapshot!(claims, @r###"JwtClaims({"key": "***SECRET***"})"###); + } + + #[test] + fn test_jwt_id_custom_debug() { + let jwt_id = AuthId::JWT(JwtId { + id: AgentId::from_external_id("abcdef"), + claims: json!({ "key": "value" }), - }); - insta::assert_debug_snapshot!(jwt_id, @r###" + }); + insta::assert_debug_snapshot!(jwt_id, @r###" JWT( JwtId { id: AgentId( @@ -447,5 +448,5 @@ mod tests { }, ) "###); - } + } } diff --git a/crates/common/src/ledger.rs b/crates/common/src/ledger.rs index 7bfc82cb9..96a33b174 100644 --- a/crates/common/src/ledger.rs +++ b/crates/common/src/ledger.rs @@ -2,637 +2,637 @@ use tracing::instrument; use uuid::Uuid; use crate::{ - identity::SignedIdentity, - prov::{ - operations::{ - ActivityExists, ActivityUses, ActsOnBehalfOf, AgentExists, ChronicleOperation, - CreateNamespace, EndActivity, EntityDerive, EntityExists, SetAttributes, StartActivity, - WasAssociatedWith, WasAttributedTo, WasGeneratedBy, WasInformedBy, - }, - ChronicleIri, ChronicleTransactionId, Contradiction, NamespaceId, ProcessorError, - ProvModel, - }, + identity::SignedIdentity, + prov::{ + operations::{ + ActivityExists, ActivityUses, ActsOnBehalfOf, AgentExists, ChronicleOperation, + CreateNamespace, EndActivity, EntityDerive, EntityExists, SetAttributes, StartActivity, + WasAssociatedWith, WasAttributedTo, WasGeneratedBy, WasInformedBy, + }, + ChronicleIri, ChronicleTransactionId, Contradiction, NamespaceId, ProcessorError, + ProvModel, + }, }; #[cfg(not(feature = "std"))] use core::str::FromStr; #[cfg(not(feature = "std"))] use parity_scale_codec::{ - alloc::boxed::Box, alloc::collections::btree_map::Entry, alloc::collections::BTreeMap, - alloc::collections::BTreeSet, alloc::string::String, alloc::sync::Arc, alloc::vec::Vec, Decode, - Encode, + alloc::boxed::Box, alloc::collections::btree_map::Entry, alloc::collections::BTreeMap, + alloc::collections::BTreeSet, alloc::string::String, alloc::sync::Arc, alloc::vec::Vec, Decode, + Encode, }; #[cfg(not(feature = "std"))] use scale_info::prelude::*; #[cfg(feature = "std")] use std::{ - boxed::Box, collections::btree_map::Entry, collections::BTreeMap, collections::BTreeSet, - sync::Arc, + boxed::Box, collections::btree_map::Entry, collections::BTreeMap, collections::BTreeSet, + sync::Arc, }; #[derive(Debug, Clone)] pub enum SubmissionError { - Communication { source: Arc, tx_id: ChronicleTransactionId }, - Processor { source: Arc, tx_id: ChronicleTransactionId }, - Contradiction { source: Contradiction, tx_id: ChronicleTransactionId }, + Communication { source: Arc, tx_id: ChronicleTransactionId }, + Processor { source: Arc, tx_id: ChronicleTransactionId }, + Contradiction { source: Contradiction, tx_id: ChronicleTransactionId }, } #[cfg(feature = "std")] impl std::error::Error for SubmissionError {} impl SubmissionError { - pub fn tx_id(&self) -> &ChronicleTransactionId { - match self { - SubmissionError::Communication { tx_id, .. } => tx_id, - SubmissionError::Processor { tx_id, .. } => tx_id, - SubmissionError::Contradiction { tx_id, .. } => tx_id, - } - } - - pub fn processor(tx_id: &ChronicleTransactionId, source: ProcessorError) -> SubmissionError { - SubmissionError::Processor { source: Arc::new(source), tx_id: *tx_id } - } - - pub fn contradiction(tx_id: &ChronicleTransactionId, source: Contradiction) -> SubmissionError { - SubmissionError::Contradiction { source, tx_id: *tx_id } - } - - pub fn communication(tx_id: &ChronicleTransactionId, source: anyhow::Error) -> SubmissionError { - SubmissionError::Communication { source: Arc::new(source), tx_id: *tx_id } - } + pub fn tx_id(&self) -> &ChronicleTransactionId { + match self { + SubmissionError::Communication { tx_id, .. } => tx_id, + SubmissionError::Processor { tx_id, .. } => tx_id, + SubmissionError::Contradiction { tx_id, .. } => tx_id, + } + } + + pub fn processor(tx_id: &ChronicleTransactionId, source: ProcessorError) -> SubmissionError { + SubmissionError::Processor { source: Arc::new(source), tx_id: *tx_id } + } + + pub fn contradiction(tx_id: &ChronicleTransactionId, source: Contradiction) -> SubmissionError { + SubmissionError::Contradiction { source, tx_id: *tx_id } + } + + pub fn communication(tx_id: &ChronicleTransactionId, source: anyhow::Error) -> SubmissionError { + SubmissionError::Communication { source: Arc::new(source), tx_id: *tx_id } + } } #[derive(Debug)] pub enum SubscriptionError { - Implementation { source: anyhow::Error }, + Implementation { source: anyhow::Error }, } impl core::fmt::Display for SubscriptionError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::Implementation { .. } => write!(f, "Subscription error"), - } - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Implementation { .. } => write!(f, "Subscription error"), + } + } } impl core::fmt::Display for SubmissionError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::Communication { source, .. } => write!(f, "Ledger error {source} "), - Self::Processor { source, .. } => write!(f, "Processor error {source} "), - Self::Contradiction { source, .. } => write!(f, "Contradiction: {source}"), - } - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Communication { source, .. } => write!(f, "Ledger error {source} "), + Self::Processor { source, .. } => write!(f, "Processor error {source} "), + Self::Contradiction { source, .. } => write!(f, "Contradiction: {source}"), + } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - scale_encode::EncodeAsType, - parity_scale_codec::Encode, - parity_scale_codec::Decode - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + scale_encode::EncodeAsType, + parity_scale_codec::Encode, + parity_scale_codec::Decode + ) )] #[derive(Debug, Clone, Eq, PartialEq)] pub struct OperationSubmission { - pub correlation_id: [u8; 16], - pub items: Arc>, - pub identity: Arc, + pub correlation_id: [u8; 16], + pub items: Arc>, + pub identity: Arc, } impl OperationSubmission { - pub fn new(uuid: Uuid, identity: SignedIdentity, operations: Vec) -> Self { - OperationSubmission { - correlation_id: uuid.into_bytes(), - identity: identity.into(), - items: operations.into(), - } - } - - pub fn new_anonymous(uuid: Uuid, operations: Vec) -> Self { - Self::new(uuid, SignedIdentity::new_no_identity(), operations) - } + pub fn new(uuid: Uuid, identity: SignedIdentity, operations: Vec) -> Self { + OperationSubmission { + correlation_id: uuid.into_bytes(), + identity: identity.into(), + items: operations.into(), + } + } + + pub fn new_anonymous(uuid: Uuid, operations: Vec) -> Self { + Self::new(uuid, SignedIdentity::new_no_identity(), operations) + } } pub type SubmitResult = Result; #[derive(Debug, Clone)] pub struct Commit { - pub tx_id: ChronicleTransactionId, - pub block_id: String, - pub delta: Box, + pub tx_id: ChronicleTransactionId, + pub block_id: String, + pub delta: Box, } impl Commit { - pub fn new(tx_id: ChronicleTransactionId, block_id: String, delta: Box) -> Self { - Commit { tx_id, block_id, delta } - } + pub fn new(tx_id: ChronicleTransactionId, block_id: String, delta: Box) -> Self { + Commit { tx_id, block_id, delta } + } } pub type CommitResult = Result; #[derive(Debug, Clone)] pub enum SubmissionStage { - Submitted(SubmitResult), - Committed(Commit, Box), - NotCommitted((ChronicleTransactionId, Contradiction, Box)), + Submitted(SubmitResult), + Committed(Commit, Box), + NotCommitted((ChronicleTransactionId, Contradiction, Box)), } impl SubmissionStage { - pub fn submitted_error(r: &SubmissionError) -> Self { - SubmissionStage::Submitted(Err(r.clone())) - } - - pub fn submitted(r: &ChronicleTransactionId) -> Self { - SubmissionStage::Submitted(Ok(*r)) - } - - pub fn committed(commit: Commit, identity: SignedIdentity) -> Self { - SubmissionStage::Committed(commit, identity.into()) - } - - pub fn not_committed( - tx: ChronicleTransactionId, - contradiction: Contradiction, - identity: SignedIdentity, - ) -> Self { - SubmissionStage::NotCommitted((tx, contradiction, identity.into())) - } - - pub fn tx_id(&self) -> &ChronicleTransactionId { - match self { - Self::Submitted(tx_id) => match tx_id { - Ok(tx_id) => tx_id, - Err(e) => e.tx_id(), - }, - Self::Committed(commit, _) => &commit.tx_id, - Self::NotCommitted((tx_id, _, _)) => tx_id, - } - } + pub fn submitted_error(r: &SubmissionError) -> Self { + SubmissionStage::Submitted(Err(r.clone())) + } + + pub fn submitted(r: &ChronicleTransactionId) -> Self { + SubmissionStage::Submitted(Ok(*r)) + } + + pub fn committed(commit: Commit, identity: SignedIdentity) -> Self { + SubmissionStage::Committed(commit, identity.into()) + } + + pub fn not_committed( + tx: ChronicleTransactionId, + contradiction: Contradiction, + identity: SignedIdentity, + ) -> Self { + SubmissionStage::NotCommitted((tx, contradiction, identity.into())) + } + + pub fn tx_id(&self) -> &ChronicleTransactionId { + match self { + Self::Submitted(tx_id) => match tx_id { + Ok(tx_id) => tx_id, + Err(e) => e.tx_id(), + }, + Self::Committed(commit, _) => &commit.tx_id, + Self::NotCommitted((tx_id, _, _)) => tx_id, + } + } } #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone)] #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] pub struct ChronicleAddress { - // Namespaces do not have a namespace - namespace: Option, - resource: ChronicleIri, + // Namespaces do not have a namespace + namespace: Option, + resource: ChronicleIri, } #[cfg(feature = "parity-encoding")] impl parity_scale_codec::MaxEncodedLen for ChronicleAddress { - fn max_encoded_len() -> usize { - 2048usize - } + fn max_encoded_len() -> usize { + 2048usize + } } impl core::fmt::Display for ChronicleAddress { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - if let Some(namespace) = &self.namespace { - write!(f, "{}:{}", namespace, self.resource) - } else { - write!(f, "{}", self.resource) - } - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if let Some(namespace) = &self.namespace { + write!(f, "{}:{}", namespace, self.resource) + } else { + write!(f, "{}", self.resource) + } + } } pub trait NameSpacePart { - fn namespace_part(&self) -> Option; + fn namespace_part(&self) -> Option; } impl NameSpacePart for ChronicleAddress { - fn namespace_part(&self) -> Option { - self.namespace.clone() - } + fn namespace_part(&self) -> Option { + self.namespace.clone() + } } pub trait ResourcePart { - fn resource_part(&self) -> ChronicleIri; + fn resource_part(&self) -> ChronicleIri; } impl ResourcePart for ChronicleAddress { - fn resource_part(&self) -> ChronicleIri { - self.resource.clone() - } + fn resource_part(&self) -> ChronicleIri { + self.resource.clone() + } } impl ChronicleAddress { - fn namespace(ns: &NamespaceId) -> Self { - Self { namespace: None, resource: ns.clone().into() } - } + fn namespace(ns: &NamespaceId) -> Self { + Self { namespace: None, resource: ns.clone().into() } + } - fn in_namespace(ns: &NamespaceId, resource: impl Into) -> Self { - Self { namespace: Some(ns.clone()), resource: resource.into() } - } + fn in_namespace(ns: &NamespaceId, resource: impl Into) -> Self { + Self { namespace: Some(ns.clone()), resource: resource.into() } + } } // Split a ProvModel into a snapshot list of its components - Namespaces, Entities, Activities and // Agents pub trait ProvSnapshot { - fn to_snapshot(&self) -> Vec<((Option, ChronicleIri), ProvModel)>; + fn to_snapshot(&self) -> Vec<((Option, ChronicleIri), ProvModel)>; } impl ProvSnapshot for ProvModel { - fn to_snapshot(&self) -> Vec<((Option, ChronicleIri), ProvModel)> { - let mut snapshot = Vec::new(); - - for (namespace_id, namespace) in &self.namespaces { - snapshot.push(( - (None, namespace_id.clone().into()), - ProvModel { - namespaces: vec![(namespace_id.clone(), namespace.clone())] - .into_iter() - .collect(), - ..Default::default() - }, - )); - } - - for ((ns, agent_id), agent) in &self.agents { - let mut delegation = BTreeMap::new(); - if let Some(delegation_set) = self.delegation.get(&(ns.clone(), agent_id.clone())) { - delegation.insert((ns.clone(), agent_id.clone()), delegation_set.clone()); - } - let mut acted_on_behalf_of = BTreeMap::new(); - if let Some(acted_on_behalf_of_set) = - self.acted_on_behalf_of.get(&(ns.clone(), agent_id.clone())) - { - acted_on_behalf_of - .insert((ns.clone(), agent_id.clone()), acted_on_behalf_of_set.clone()); - } - snapshot.push(( - (Some(ns.clone()), agent_id.clone().into()), - ProvModel { - agents: vec![((ns.clone(), agent_id.clone()), agent.clone())] - .into_iter() - .collect(), - delegation, - acted_on_behalf_of, - ..Default::default() - }, - )); - } - - for ((ns, activity_id), activity) in &self.activities { - let mut was_informed_by = BTreeMap::new(); - if let Some(was_informed_by_set) = - self.was_informed_by.get(&(ns.clone(), activity_id.clone())) - { - was_informed_by - .insert((ns.clone(), activity_id.clone()), was_informed_by_set.clone()); - } - let mut generated = BTreeMap::new(); - if let Some(generated_set) = self.generated.get(&(ns.clone(), activity_id.clone())) { - generated.insert((ns.clone(), activity_id.clone()), generated_set.clone()); - } - let mut usage = BTreeMap::new(); - if let Some(usage_set) = self.usage.get(&(ns.clone(), activity_id.clone())) { - usage.insert((ns.clone(), activity_id.clone()), usage_set.clone()); - } - let mut association = BTreeMap::new(); - if let Some(association_set) = self.association.get(&(ns.clone(), activity_id.clone())) - { - association.insert((ns.clone(), activity_id.clone()), association_set.clone()); - } - - snapshot.push(( - (Some(ns.clone()), activity_id.clone().into()), - ProvModel { - activities: vec![((ns.clone(), activity_id.clone()), activity.clone())] - .into_iter() - .collect(), - was_informed_by, - usage, - generated, - association, - ..Default::default() - }, - )); - } - - for ((ns, entity_id), entity) in &self.entities { - let mut derivation = BTreeMap::new(); - if let Some(derivation_set) = self.derivation.get(&(ns.clone(), entity_id.clone())) { - derivation.insert((ns.clone(), entity_id.clone()), derivation_set.clone()); - } - let mut generation = BTreeMap::new(); - if let Some(generation_set) = self.generation.get(&(ns.clone(), entity_id.clone())) { - generation.insert((ns.clone(), entity_id.clone()), generation_set.clone()); - } - let mut attribution = BTreeMap::new(); - if let Some(attribution_set) = self.attribution.get(&(ns.clone(), entity_id.clone())) { - attribution.insert((ns.clone(), entity_id.clone()), attribution_set.clone()); - } - snapshot.push(( - (Some(ns.clone()), entity_id.clone().into()), - ProvModel { - entities: vec![((ns.clone(), entity_id.clone()), entity.clone())] - .into_iter() - .collect(), - derivation, - generation, - attribution, - ..Default::default() - }, - )); - } - - snapshot - } + fn to_snapshot(&self) -> Vec<((Option, ChronicleIri), ProvModel)> { + let mut snapshot = Vec::new(); + + for (namespace_id, namespace) in &self.namespaces { + snapshot.push(( + (None, namespace_id.clone().into()), + ProvModel { + namespaces: vec![(namespace_id.clone(), namespace.clone())] + .into_iter() + .collect(), + ..Default::default() + }, + )); + } + + for ((ns, agent_id), agent) in &self.agents { + let mut delegation = BTreeMap::new(); + if let Some(delegation_set) = self.delegation.get(&(ns.clone(), agent_id.clone())) { + delegation.insert((ns.clone(), agent_id.clone()), delegation_set.clone()); + } + let mut acted_on_behalf_of = BTreeMap::new(); + if let Some(acted_on_behalf_of_set) = + self.acted_on_behalf_of.get(&(ns.clone(), agent_id.clone())) + { + acted_on_behalf_of + .insert((ns.clone(), agent_id.clone()), acted_on_behalf_of_set.clone()); + } + snapshot.push(( + (Some(ns.clone()), agent_id.clone().into()), + ProvModel { + agents: vec![((ns.clone(), agent_id.clone()), agent.clone())] + .into_iter() + .collect(), + delegation, + acted_on_behalf_of, + ..Default::default() + }, + )); + } + + for ((ns, activity_id), activity) in &self.activities { + let mut was_informed_by = BTreeMap::new(); + if let Some(was_informed_by_set) = + self.was_informed_by.get(&(ns.clone(), activity_id.clone())) + { + was_informed_by + .insert((ns.clone(), activity_id.clone()), was_informed_by_set.clone()); + } + let mut generated = BTreeMap::new(); + if let Some(generated_set) = self.generated.get(&(ns.clone(), activity_id.clone())) { + generated.insert((ns.clone(), activity_id.clone()), generated_set.clone()); + } + let mut usage = BTreeMap::new(); + if let Some(usage_set) = self.usage.get(&(ns.clone(), activity_id.clone())) { + usage.insert((ns.clone(), activity_id.clone()), usage_set.clone()); + } + let mut association = BTreeMap::new(); + if let Some(association_set) = self.association.get(&(ns.clone(), activity_id.clone())) + { + association.insert((ns.clone(), activity_id.clone()), association_set.clone()); + } + + snapshot.push(( + (Some(ns.clone()), activity_id.clone().into()), + ProvModel { + activities: vec![((ns.clone(), activity_id.clone()), activity.clone())] + .into_iter() + .collect(), + was_informed_by, + usage, + generated, + association, + ..Default::default() + }, + )); + } + + for ((ns, entity_id), entity) in &self.entities { + let mut derivation = BTreeMap::new(); + if let Some(derivation_set) = self.derivation.get(&(ns.clone(), entity_id.clone())) { + derivation.insert((ns.clone(), entity_id.clone()), derivation_set.clone()); + } + let mut generation = BTreeMap::new(); + if let Some(generation_set) = self.generation.get(&(ns.clone(), entity_id.clone())) { + generation.insert((ns.clone(), entity_id.clone()), generation_set.clone()); + } + let mut attribution = BTreeMap::new(); + if let Some(attribution_set) = self.attribution.get(&(ns.clone(), entity_id.clone())) { + attribution.insert((ns.clone(), entity_id.clone()), attribution_set.clone()); + } + snapshot.push(( + (Some(ns.clone()), entity_id.clone().into()), + ProvModel { + entities: vec![((ns.clone(), entity_id.clone()), entity.clone())] + .into_iter() + .collect(), + derivation, + generation, + attribution, + ..Default::default() + }, + )); + } + + snapshot + } } #[derive(Debug, Clone)] pub struct StateInput { - data: ProvModel, + data: ProvModel, } impl StateInput { - pub fn new(data: ProvModel) -> Self { - Self { data } - } + pub fn new(data: ProvModel) -> Self { + Self { data } + } - pub fn data(&self) -> &ProvModel { - &self.data - } + pub fn data(&self) -> &ProvModel { + &self.data + } } #[derive(Debug)] pub struct StateOutput { - pub address: ChronicleAddress, - pub data: ProvModel, + pub address: ChronicleAddress, + pub data: ProvModel, } impl StateOutput { - pub fn new(address: ChronicleAddress, data: ProvModel) -> Self { - Self { address, data } - } + pub fn new(address: ChronicleAddress, data: ProvModel) -> Self { + Self { address, data } + } - pub fn address(&self) -> &ChronicleAddress { - &self.address - } + pub fn address(&self) -> &ChronicleAddress { + &self.address + } - pub fn data(&self) -> &ProvModel { - &self.data - } + pub fn data(&self) -> &ProvModel { + &self.data + } } #[derive(Debug, Clone)] pub struct Version { - pub(crate) version: u32, - pub(crate) value: Option, + pub(crate) version: u32, + pub(crate) value: Option, } impl Version { - pub fn write(&mut self, value: Option) { - if value != self.value { - self.version += 1; - self.value = value - } - } + pub fn write(&mut self, value: Option) { + if value != self.value { + self.version += 1; + self.value = value + } + } } /// Hold a cache of `LedgerWriter::submit` input and output address data pub struct OperationState { - state: BTreeMap, + state: BTreeMap, } impl Default for OperationState { - fn default() -> Self { - Self::new() - } + fn default() -> Self { + Self::new() + } } impl OperationState { - pub fn new() -> Self { - Self { state: BTreeMap::new() } - } - - pub fn update_state_from_output(&mut self, output: impl Iterator) { - self.update_state(output.map(|output| (output.address, Some(output.data)))) - } - - /// Load input values into `OperationState` - pub fn update_state( - &mut self, - input: impl Iterator)>, - ) { - input.for_each(|(address, value)| { - let entry = self.state.entry(address); - if let Entry::Vacant(e) = entry { - e.insert(Version { version: 0, value }); - } else if let Entry::Occupied(mut e) = entry { - e.get_mut().write(value); - } - }); - } - - /// Return the input data held in `OperationState` - /// as a vector of `StateInput`s - pub fn input(&self) -> Vec { - self.state - .values() - .cloned() - .filter_map(|v| v.value.map(StateInput::new)) - .collect() - } - - /// Check if the data associated with an address has changed in processing - /// while outputting a stream of dirty `StateOutput`s - pub fn dirty(self) -> impl Iterator { - self.state - .into_iter() - .filter_map(|(addr, data)| { - if data.version > 0 { - data.value.map(|value| (StateOutput::new(addr, value))) - } else { - None - } - }) - .collect::>() - .into_iter() - } - - /// Return the input data held in `OperationState` for `addresses` as a vector of `StateInput`s - pub fn opa_context(&self, addresses: BTreeSet) -> Vec { - self.state - .iter() - .filter(|(addr, _data)| addresses.iter().any(|a| &a == addr)) - .map(|(_, data)| data.clone()) - .filter_map(|v| v.value.map(StateInput::new)) - .collect() - } + pub fn new() -> Self { + Self { state: BTreeMap::new() } + } + + pub fn update_state_from_output(&mut self, output: impl Iterator) { + self.update_state(output.map(|output| (output.address, Some(output.data)))) + } + + /// Load input values into `OperationState` + pub fn update_state( + &mut self, + input: impl Iterator)>, + ) { + input.for_each(|(address, value)| { + let entry = self.state.entry(address); + if let Entry::Vacant(e) = entry { + e.insert(Version { version: 0, value }); + } else if let Entry::Occupied(mut e) = entry { + e.get_mut().write(value); + } + }); + } + + /// Return the input data held in `OperationState` + /// as a vector of `StateInput`s + pub fn input(&self) -> Vec { + self.state + .values() + .cloned() + .filter_map(|v| v.value.map(StateInput::new)) + .collect() + } + + /// Check if the data associated with an address has changed in processing + /// while outputting a stream of dirty `StateOutput`s + pub fn dirty(self) -> impl Iterator { + self.state + .into_iter() + .filter_map(|(addr, data)| { + if data.version > 0 { + data.value.map(|value| (StateOutput::new(addr, value))) + } else { + None + } + }) + .collect::>() + .into_iter() + } + + /// Return the input data held in `OperationState` for `addresses` as a vector of `StateInput`s + pub fn opa_context(&self, addresses: BTreeSet) -> Vec { + self.state + .iter() + .filter(|(addr, _data)| addresses.iter().any(|a| &a == addr)) + .map(|(_, data)| data.clone()) + .filter_map(|v| v.value.map(StateInput::new)) + .collect() + } } impl ChronicleOperation { - /// Compute dependencies for a chronicle operation, input and output addresses are always - /// symmetric - pub fn dependencies(&self) -> Vec { - match self { - ChronicleOperation::CreateNamespace(CreateNamespace { id, .. }) => { - vec![ChronicleAddress::namespace(id)] - }, - ChronicleOperation::AgentExists(AgentExists { namespace, id, .. }) => { - vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, id.clone()), - ] - }, - ChronicleOperation::ActivityExists(ActivityExists { namespace, id, .. }) => { - vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, id.clone()), - ] - }, - ChronicleOperation::StartActivity(StartActivity { namespace, id, .. }) => { - vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, id.clone()), - ] - }, - ChronicleOperation::WasAssociatedWith(WasAssociatedWith { - id, - namespace, - activity_id, - agent_id, - .. - }) => vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, id.clone()), - ChronicleAddress::in_namespace(namespace, activity_id.clone()), - ChronicleAddress::in_namespace(namespace, agent_id.clone()), - ], - ChronicleOperation::WasAttributedTo(WasAttributedTo { - id, - namespace, - entity_id, - agent_id, - .. - }) => vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, id.clone()), - ChronicleAddress::in_namespace(namespace, entity_id.clone()), - ChronicleAddress::in_namespace(namespace, agent_id.clone()), - ], - ChronicleOperation::EndActivity(EndActivity { namespace, id, .. }) => { - vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, id.clone()), - ] - }, - ChronicleOperation::ActivityUses(ActivityUses { namespace, id, activity }) => { - vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, activity.clone()), - ChronicleAddress::in_namespace(namespace, id.clone()), - ] - }, - ChronicleOperation::EntityExists(EntityExists { namespace, id }) => { - vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, id.clone()), - ] - }, - ChronicleOperation::WasGeneratedBy(WasGeneratedBy { namespace, id, activity }) => vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, activity.clone()), - ChronicleAddress::in_namespace(namespace, id.clone()), - ], - ChronicleOperation::WasInformedBy(WasInformedBy { - namespace, - activity, - informing_activity, - }) => { - vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, activity.clone()), - ChronicleAddress::in_namespace(namespace, informing_activity.clone()), - ] - }, - ChronicleOperation::AgentActsOnBehalfOf(ActsOnBehalfOf { - namespace, - id, - delegate_id, - activity_id, - responsible_id, - .. - }) => vec![ - Some(ChronicleAddress::namespace(namespace)), - activity_id.as_ref().map(|activity_id| { - ChronicleAddress::in_namespace(namespace, activity_id.clone()) - }), - Some(ChronicleAddress::in_namespace(namespace, delegate_id.clone())), - Some(ChronicleAddress::in_namespace(namespace, responsible_id.clone())), - Some(ChronicleAddress::in_namespace(namespace, id.clone())), - ] - .into_iter() - .flatten() - .collect(), - ChronicleOperation::EntityDerive(EntityDerive { - namespace, - id, - used_id, - activity_id, - .. - }) => vec![ - Some(ChronicleAddress::namespace(namespace)), - activity_id.as_ref().map(|activity_id| { - ChronicleAddress::in_namespace(namespace, activity_id.clone()) - }), - Some(ChronicleAddress::in_namespace(namespace, used_id.clone())), - Some(ChronicleAddress::in_namespace(namespace, id.clone())), - ] - .into_iter() - .flatten() - .collect(), - ChronicleOperation::SetAttributes(SetAttributes::Agent { id, namespace, .. }) => { - vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, id.clone()), - ] - }, - ChronicleOperation::SetAttributes(SetAttributes::Entity { id, namespace, .. }) => { - vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, id.clone()), - ] - }, - ChronicleOperation::SetAttributes(SetAttributes::Activity { - id, namespace, .. - }) => { - vec![ - ChronicleAddress::namespace(namespace), - ChronicleAddress::in_namespace(namespace, id.clone()), - ] - }, - } - } - - /// Apply an operation's input states to the prov model - /// Take input states and apply them to the prov model, then apply transaction, - /// then return a snapshot of output state for diff calculation - #[instrument(level = "debug", skip(self, model, input))] - pub fn process( - &self, - mut model: ProvModel, - input: Vec, - ) -> Result<(Vec, ProvModel), ProcessorError> { - for input in input.iter() { - model.combine(input.data()) - } - model.apply(self).map_err(ProcessorError::Contradiction)?; - Ok(( - model - .to_snapshot() - .into_iter() - .map(|((namespace, resource), prov)| { - StateOutput::new(ChronicleAddress { namespace, resource }, prov) - }) - .collect::>(), - model, - )) - } + /// Compute dependencies for a chronicle operation, input and output addresses are always + /// symmetric + pub fn dependencies(&self) -> Vec { + match self { + ChronicleOperation::CreateNamespace(CreateNamespace { id, .. }) => { + vec![ChronicleAddress::namespace(id)] + } + ChronicleOperation::AgentExists(AgentExists { namespace, id, .. }) => { + vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, id.clone()), + ] + } + ChronicleOperation::ActivityExists(ActivityExists { namespace, id, .. }) => { + vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, id.clone()), + ] + } + ChronicleOperation::StartActivity(StartActivity { namespace, id, .. }) => { + vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, id.clone()), + ] + } + ChronicleOperation::WasAssociatedWith(WasAssociatedWith { + id, + namespace, + activity_id, + agent_id, + .. + }) => vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, id.clone()), + ChronicleAddress::in_namespace(namespace, activity_id.clone()), + ChronicleAddress::in_namespace(namespace, agent_id.clone()), + ], + ChronicleOperation::WasAttributedTo(WasAttributedTo { + id, + namespace, + entity_id, + agent_id, + .. + }) => vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, id.clone()), + ChronicleAddress::in_namespace(namespace, entity_id.clone()), + ChronicleAddress::in_namespace(namespace, agent_id.clone()), + ], + ChronicleOperation::EndActivity(EndActivity { namespace, id, .. }) => { + vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, id.clone()), + ] + } + ChronicleOperation::ActivityUses(ActivityUses { namespace, id, activity }) => { + vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, activity.clone()), + ChronicleAddress::in_namespace(namespace, id.clone()), + ] + } + ChronicleOperation::EntityExists(EntityExists { namespace, id }) => { + vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, id.clone()), + ] + } + ChronicleOperation::WasGeneratedBy(WasGeneratedBy { namespace, id, activity }) => vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, activity.clone()), + ChronicleAddress::in_namespace(namespace, id.clone()), + ], + ChronicleOperation::WasInformedBy(WasInformedBy { + namespace, + activity, + informing_activity, + }) => { + vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, activity.clone()), + ChronicleAddress::in_namespace(namespace, informing_activity.clone()), + ] + } + ChronicleOperation::AgentActsOnBehalfOf(ActsOnBehalfOf { + namespace, + id, + delegate_id, + activity_id, + responsible_id, + .. + }) => vec![ + Some(ChronicleAddress::namespace(namespace)), + activity_id.as_ref().map(|activity_id| { + ChronicleAddress::in_namespace(namespace, activity_id.clone()) + }), + Some(ChronicleAddress::in_namespace(namespace, delegate_id.clone())), + Some(ChronicleAddress::in_namespace(namespace, responsible_id.clone())), + Some(ChronicleAddress::in_namespace(namespace, id.clone())), + ] + .into_iter() + .flatten() + .collect(), + ChronicleOperation::EntityDerive(EntityDerive { + namespace, + id, + used_id, + activity_id, + .. + }) => vec![ + Some(ChronicleAddress::namespace(namespace)), + activity_id.as_ref().map(|activity_id| { + ChronicleAddress::in_namespace(namespace, activity_id.clone()) + }), + Some(ChronicleAddress::in_namespace(namespace, used_id.clone())), + Some(ChronicleAddress::in_namespace(namespace, id.clone())), + ] + .into_iter() + .flatten() + .collect(), + ChronicleOperation::SetAttributes(SetAttributes::Agent { id, namespace, .. }) => { + vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, id.clone()), + ] + } + ChronicleOperation::SetAttributes(SetAttributes::Entity { id, namespace, .. }) => { + vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, id.clone()), + ] + } + ChronicleOperation::SetAttributes(SetAttributes::Activity { + id, namespace, .. + }) => { + vec![ + ChronicleAddress::namespace(namespace), + ChronicleAddress::in_namespace(namespace, id.clone()), + ] + } + } + } + + /// Apply an operation's input states to the prov model + /// Take input states and apply them to the prov model, then apply transaction, + /// then return a snapshot of output state for diff calculation + #[instrument(level = "debug", skip(self, model, input))] + pub fn process( + &self, + mut model: ProvModel, + input: Vec, + ) -> Result<(Vec, ProvModel), ProcessorError> { + for input in input.iter() { + model.combine(input.data()) + } + model.apply(self).map_err(ProcessorError::Contradiction)?; + Ok(( + model + .to_snapshot() + .into_iter() + .map(|((namespace, resource), prov)| { + StateOutput::new(ChronicleAddress { namespace, resource }, prov) + }) + .collect::>(), + model, + )) + } } diff --git a/crates/common/src/opa/core.rs b/crates/common/src/opa/core.rs index 42e5d5f3d..7658121bc 100644 --- a/crates/common/src/opa/core.rs +++ b/crates/common/src/opa/core.rs @@ -6,128 +6,129 @@ use parity_scale_codec::alloc::string::String; use scale_info::{prelude::vec, prelude::vec::Vec}; #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType, - scale_decode::DecodeAsType, - parity_scale_codec::MaxEncodedLen - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType, + scale_decode::DecodeAsType, + parity_scale_codec::MaxEncodedLen + ) )] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize,))] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, ))] #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct H128([u8; 16]); impl H128 { - pub fn new(value: [u8; 16]) -> Self { - H128(value) - } + pub fn new(value: [u8; 16]) -> Self { + H128(value) + } - pub fn into(self) -> [u8; 16] { - self.0 - } + pub fn into(self) -> [u8; 16] { + self.0 + } } #[cfg(not(feature = "std"))] use scale_info::prelude::format; + #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType, - scale_decode::DecodeAsType, - parity_scale_codec::MaxEncodedLen - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType, + scale_decode::DecodeAsType, + parity_scale_codec::MaxEncodedLen + ) )] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize,))] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, ))] #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct PolicyAddress(H128); impl fmt::Display for PolicyAddress { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "PolicyAddress({})", hex::encode(self.0.into())) - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "PolicyAddress({})", hex::encode(self.0.into())) + } } impl From<[u8; 16]> for PolicyAddress { - fn from(value: [u8; 16]) -> Self { - tracing::debug!("Converting [u8; 16] to PolicyAddress"); - PolicyAddress(H128::new(value)) - } + fn from(value: [u8; 16]) -> Self { + tracing::debug!("Converting [u8; 16] to PolicyAddress"); + PolicyAddress(H128::new(value)) + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType, - parity_scale_codec::MaxEncodedLen - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType, + parity_scale_codec::MaxEncodedLen + ) )] #[derive(Debug, PartialEq, Eq, Clone)] pub struct PolicyMetaAddress(H128); impl PolicyMetaAddress { - pub fn new(value: H128) -> Self { - PolicyMetaAddress(value) - } + pub fn new(value: H128) -> Self { + PolicyMetaAddress(value) + } - pub fn into(self) -> H128 { - self.0 - } + pub fn into(self) -> H128 { + self.0 + } } impl From<[u8; 16]> for H128 { - fn from(value: [u8; 16]) -> Self { - H128(value) - } + fn from(value: [u8; 16]) -> Self { + H128(value) + } } impl From<[u8; 16]> for PolicyMetaAddress { - fn from(value: [u8; 16]) -> Self { - PolicyMetaAddress(H128::new(value)) - } + fn from(value: [u8; 16]) -> Self { + PolicyMetaAddress(H128::new(value)) + } } impl From<[u8; 16]> for KeyAddress { - fn from(value: [u8; 16]) -> Self { - KeyAddress(H128::new(value)) - } + fn from(value: [u8; 16]) -> Self { + KeyAddress(H128::new(value)) + } } impl From for PolicyMetaAddress { - fn from(value: H128) -> Self { - PolicyMetaAddress(value) - } + fn from(value: H128) -> Self { + PolicyMetaAddress(value) + } } impl From for PolicyAddress { - fn from(value: H128) -> Self { - PolicyAddress(value) - } + fn from(value: H128) -> Self { + PolicyAddress(value) + } } impl From for KeyAddress { - fn from(value: H128) -> Self { - KeyAddress(value) - } + fn from(value: H128) -> Self { + KeyAddress(value) + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType, - parity_scale_codec::MaxEncodedLen - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType, + parity_scale_codec::MaxEncodedLen + ) )] #[derive(Debug, PartialEq, Eq, Clone)] pub struct KeyAddress(H128); @@ -136,55 +137,56 @@ pub struct KeyAddress(H128); // This message is used to bootstrap the root key for a newly created authz tp, // it can only be executed once pub struct BootstrapRoot { - pub public_key: PemEncoded, + pub public_key: PemEncoded, } + #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType, - scale_decode::DecodeAsType, - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType, + scale_decode::DecodeAsType, + ) )] -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize,))] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, ))] #[derive(Debug, Clone, Eq, PartialEq)] pub struct PemEncoded(String); impl PemEncoded { - pub fn as_str(&self) -> &str { - &self.0 - } + pub fn as_str(&self) -> &str { + &self.0 + } - pub fn as_bytes(&self) -> &[u8] { - self.0.as_bytes() - } + pub fn as_bytes(&self) -> &[u8] { + self.0.as_bytes() + } } impl PemEncoded { - pub fn new(encoded: String) -> Self { - PemEncoded(encoded) - } + pub fn new(encoded: String) -> Self { + PemEncoded(encoded) + } } impl From for PemEncoded { - fn from(encoded: String) -> Self { - PemEncoded(encoded) - } + fn from(encoded: String) -> Self { + PemEncoded(encoded) + } } #[derive(Debug, Clone, Eq, PartialEq)] pub struct RegisterKey { - pub public_key: PemEncoded, - pub id: String, - pub overwrite_existing: bool, + pub public_key: PemEncoded, + pub id: String, + pub overwrite_existing: bool, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct NewPublicKey { - pub public_key: PemEncoded, - pub id: String, + pub public_key: PemEncoded, + pub id: String, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -192,119 +194,120 @@ pub struct NewPublicKey { // message must be signed by the old key. The signature must be valid for // the new one, to demonstrate ownership of both keys pub struct RotateKey { - pub payload: NewPublicKey, - pub previous_signing_key: PemEncoded, - pub previous_signature: Vec, - pub new_signing_key: PemEncoded, - pub new_signature: Vec, + pub payload: NewPublicKey, + pub previous_signing_key: PemEncoded, + pub previous_signature: Vec, + pub new_signing_key: PemEncoded, + pub new_signature: Vec, } + #[derive(Debug, Clone, Eq, PartialEq)] // Set the policy with name to the new policy, the SignedOperation for this must // be signed by the root key pub struct SetPolicy { - pub id: String, - pub policy: Policy, + pub id: String, + pub policy: Policy, } #[derive(Debug, Clone, Eq, PartialEq)] pub struct SignedOperationPayload { - pub operation: Operation, + pub operation: Operation, } #[derive(Debug, Clone, Eq, PartialEq)] // An OPA TP operation and its signature pub struct SignedOperation { - pub payload: SignedOperationPayload, - pub verifying_key: PemEncoded, - pub signature: Vec, + pub payload: SignedOperationPayload, + pub verifying_key: PemEncoded, + pub signature: Vec, } #[derive(Debug, Clone, Eq, PartialEq)] pub enum Operation { - RegisterKey(RegisterKey), - RotateKey(RotateKey), - SetPolicy(SetPolicy), + RegisterKey(RegisterKey), + RotateKey(RotateKey), + SetPolicy(SetPolicy), } #[derive(Debug, Clone, Eq, PartialEq)] pub struct OpaSubmission { - pub version: String, - pub correlation_id: [u8; 16], - pub span_id: u64, - pub payload: Payload, + pub version: String, + pub correlation_id: [u8; 16], + pub span_id: u64, + pub payload: Payload, } #[derive(Debug, Clone, Eq, PartialEq)] pub enum Payload { - BootstrapRoot(BootstrapRoot), - SignedOperation(SignedOperation), + BootstrapRoot(BootstrapRoot), + SignedOperation(SignedOperation), } -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize,))] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, ))] #[derive(Debug, Clone, PartialEq, Eq)] pub struct KeyRegistration { - pub key: PemEncoded, - pub version: u64, + pub key: PemEncoded, + pub version: u64, } -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize,))] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, ))] #[derive(Debug, Clone, PartialEq, Eq)] pub struct Keys { - pub id: String, - pub current: KeyRegistration, - pub expired: Option, + pub id: String, + pub current: KeyRegistration, + pub expired: Option, } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType, - scale_decode::DecodeAsType, - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType, + scale_decode::DecodeAsType, + ) )] #[derive(Debug, Clone, PartialEq, Eq)] pub struct Policy(Vec); impl Policy { - pub fn new(data: Vec) -> Self { - Policy(data) - } + pub fn new(data: Vec) -> Self { + Policy(data) + } - pub fn as_bytes(&self) -> &[u8] { - &self.0 - } + pub fn as_bytes(&self) -> &[u8] { + &self.0 + } - pub fn into_vec(self) -> Vec { - self.0 - } + pub fn into_vec(self) -> Vec { + self.0 + } } -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize,))] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, ))] #[derive(Debug, Clone, PartialEq, Eq)] pub struct PolicyMeta { - pub id: String, - pub hash: H128, - pub policy_address: PolicyAddress, + pub id: String, + pub hash: H128, + pub policy_address: PolicyAddress, } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType, - scale_decode::DecodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType, + scale_decode::DecodeAsType + ) )] #[derive(Debug, Clone)] pub struct OpaSettings { - pub policy_address: PolicyAddress, - pub policy_name: String, - pub entrypoint: String, + pub policy_address: PolicyAddress, + pub policy_name: String, + pub entrypoint: String, } #[cfg(feature = "parity-encoding")] @@ -312,380 +315,381 @@ use parity_scale_codec::MaxEncodedLen; #[cfg(feature = "parity-encoding")] impl MaxEncodedLen for OpaSettings { - fn max_encoded_len() -> usize { - PolicyAddress::max_encoded_len() + 1024 - } + fn max_encoded_len() -> usize { + PolicyAddress::max_encoded_len() + 1024 + } } #[cfg(feature = "parity-encoding")] pub mod codec { - use super::*; - use parity_scale_codec::{Decode, Encode}; - - use scale_decode::DecodeAsType; - use scale_encode::EncodeAsType; - #[cfg(not(feature = "std"))] - use scale_info::prelude::vec::Vec; - - use scale_info::TypeInfo; - - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, Eq, PartialEq, TypeInfo, Clone)] - pub struct KeysV1 { - pub id: String, - pub current: KeyRegistrationV1, - pub expired: Option, - } - - impl MaxEncodedLen for KeysV1 { - fn max_encoded_len() -> usize { - 1024 + KeyRegistrationV1::max_encoded_len() + - Option::::max_encoded_len() - } - } - - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, Eq, PartialEq, TypeInfo, Clone)] - pub struct KeyRegistrationV1 { - // Der encoded public key - pub key: PemEncoded, - pub version: u64, - } - - impl MaxEncodedLen for KeyRegistrationV1 { - fn max_encoded_len() -> usize { - 1024 + u64::max_encoded_len() - } - } - - impl From for KeysV1 { - fn from(keys: super::Keys) -> Self { - Self { - id: keys.id, - current: KeyRegistrationV1 { key: keys.current.key, version: keys.current.version }, - expired: keys.expired.map(|expired_key| KeyRegistrationV1 { - key: expired_key.key, - version: expired_key.version, - }), - } - } - } - - impl core::convert::TryFrom for super::Keys { - type Error = core::convert::Infallible; - - fn try_from(keys_v1: KeysV1) -> Result { - Ok(Self { - id: keys_v1.id, - current: super::KeyRegistration { - key: keys_v1.current.key, - version: keys_v1.current.version, - }, - expired: keys_v1.expired.map(|expired_key_v1| super::KeyRegistration { - key: expired_key_v1.key, - version: expired_key_v1.version, - }), - }) - } - } - - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] - pub struct BootstrapRootV1 { - pub public_key: PemEncoded, - } - - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] - pub struct RegisterKeyV1 { - pub public_key: PemEncoded, - pub id: String, - pub overwrite_existing: bool, - } - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] - pub struct NewPublicKeyV1 { - pub public_key: PemEncoded, - pub id: String, - } - - impl From for NewPublicKeyV1 { - fn from(new_public_key: super::NewPublicKey) -> Self { - Self { public_key: new_public_key.public_key, id: new_public_key.id } - } - } - - impl core::convert::TryFrom for super::NewPublicKey { - type Error = core::convert::Infallible; - - fn try_from(new_public_key_v1: NewPublicKeyV1) -> Result { - Ok(Self { public_key: new_public_key_v1.public_key, id: new_public_key_v1.id }) - } - } - - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] - pub struct RotateKeyV1 { - pub payload: NewPublicKeyV1, - pub previous_signing_key: PemEncoded, - pub previous_signature: Vec, - pub new_signing_key: PemEncoded, - pub new_signature: Vec, - } - - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] - pub struct SetPolicyV1 { - pub id: String, - pub policy: Policy, - } - - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] - pub struct SignedOperationPayloadV1 { - pub operation: OperationV1, - } - - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] - pub struct SignedOperationV1 { - pub payload: SignedOperationPayloadV1, - pub verifying_key: PemEncoded, - pub signature: Vec, - } - - impl From for SignedOperationV1 { - fn from(signed_operation: super::SignedOperation) -> Self { - Self { - payload: SignedOperationPayloadV1 { - operation: signed_operation.payload.operation.into(), - }, - verifying_key: signed_operation.verifying_key, - signature: signed_operation.signature, - } - } - } - - impl From for OperationV1 { - fn from(operation: super::Operation) -> Self { - match operation { - super::Operation::RegisterKey(register_key) => - OperationV1::RegisterKey(register_key.into()), - super::Operation::RotateKey(rotate_key) => - OperationV1::RotateKey(rotate_key.into()), - super::Operation::SetPolicy(set_policy) => - OperationV1::SetPolicy(set_policy.into()), - } - } - } - - impl From for RegisterKeyV1 { - fn from(register_key: super::RegisterKey) -> Self { - Self { - public_key: register_key.public_key, - id: register_key.id, - overwrite_existing: register_key.overwrite_existing, - } - } - } - - impl From for RotateKeyV1 { - fn from(rotate_key: super::RotateKey) -> Self { - Self { - payload: rotate_key.payload.into(), - previous_signing_key: rotate_key.previous_signing_key, - previous_signature: rotate_key.previous_signature, - new_signing_key: rotate_key.new_signing_key, - new_signature: rotate_key.new_signature, - } - } - } - - impl From for SetPolicyV1 { - fn from(set_policy: super::SetPolicy) -> Self { - Self { id: set_policy.id, policy: set_policy.policy } - } - } - - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, Clone, TypeInfo, PartialEq, Eq)] - pub enum OperationV1 { - RegisterKey(RegisterKeyV1), - RotateKey(RotateKeyV1), - SetPolicy(SetPolicyV1), - } - - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] - pub struct OpaSubmissionV1 { - pub version: String, - pub correlation_id: [u8; 16], - pub span_id: u64, - pub payload: PayloadV1, - } - - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] - pub enum PayloadV1 { - BootstrapRoot(BootstrapRootV1), - SignedOperation(SignedOperationV1), - } - - #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq)] - pub struct PolicyV1(Vec); - - impl PolicyV1 { - pub fn into_vec(self) -> Vec { - self.0 - } - } - - impl MaxEncodedLen for PolicyV1 { - fn max_encoded_len() -> usize { - 1024 * 1024 * 10 - } - } - - impl From for codec::PolicyV1 { - fn from(item: Policy) -> Self { - Self(item.0) - } - } - - impl core::convert::TryFrom for Policy { - type Error = core::convert::Infallible; - - fn try_from(value: codec::PolicyV1) -> Result { - Ok(Self(value.0)) - } - } - - #[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq)] - pub struct PolicyMetaV1 { - pub id: String, - pub hash: H128, - pub policy_address: PolicyAddress, - } - - impl MaxEncodedLen for PolicyMetaV1 { - fn max_encoded_len() -> usize { - 1024 + H128::max_encoded_len() + PolicyAddress::max_encoded_len() - } - } - - impl From for codec::PolicyMetaV1 { - fn from(item: super::PolicyMeta) -> Self { - Self { id: item.id, hash: item.hash, policy_address: item.policy_address } - } - } - - impl core::convert::TryFrom for super::PolicyMeta { - type Error = core::convert::Infallible; - - fn try_from(value: codec::PolicyMetaV1) -> Result { - Ok(Self { id: value.id, hash: value.hash, policy_address: value.policy_address }) - } - } - - impl From for BootstrapRoot { - fn from(item: codec::BootstrapRootV1) -> Self { - Self { public_key: item.public_key } - } - } - - impl From for codec::BootstrapRootV1 { - fn from(item: BootstrapRoot) -> Self { - tracing::debug!(target: "codec_conversion", "Converting BootstrapRoot to BootstrapRootV1"); - Self { public_key: item.public_key } - } - } - - impl From for Payload { - fn from(item: codec::PayloadV1) -> Self { - match item { - codec::PayloadV1::BootstrapRoot(v) => Self::BootstrapRoot(v.into()), - codec::PayloadV1::SignedOperation(v) => Self::SignedOperation(v.into()), - } - } - } - - impl From for OpaSubmission { - fn from(item: codec::OpaSubmissionV1) -> Self { - Self { - correlation_id: item.correlation_id, - version: item.version, - span_id: item.span_id, - payload: item.payload.into(), - } - } - } - - impl From for codec::OpaSubmissionV1 { - fn from(item: OpaSubmission) -> Self { - tracing::debug!(target: "codec_conversion", "Converting OpaSubmission to OpaSubmissionV1"); - Self { - version: item.version, - correlation_id: item.correlation_id, - span_id: item.span_id, - payload: match item.payload { - Payload::BootstrapRoot(v) => { - tracing::trace!(target: "codec_conversion", "Payload is BootstrapRoot"); - codec::PayloadV1::BootstrapRoot(v.into()) - }, - Payload::SignedOperation(v) => { - tracing::trace!(target: "codec_conversion", "Payload is SignedOperation"); - codec::PayloadV1::SignedOperation(v.into()) - }, - }, - } - } - } - - impl From for Operation { - fn from(item: codec::OperationV1) -> Self { - match item { - codec::OperationV1::RegisterKey(v) => Self::RegisterKey(v.into()), - codec::OperationV1::RotateKey(v) => Self::RotateKey(v.into()), - codec::OperationV1::SetPolicy(v) => Self::SetPolicy(v.into()), - } - } - } - - impl From for SignedOperation { - fn from(item: codec::SignedOperationV1) -> Self { - Self { - payload: SignedOperationPayload { operation: item.payload.operation.into() }, - verifying_key: item.verifying_key, - signature: item.signature, - } - } - } - - impl From for RotateKey { - fn from(item: codec::RotateKeyV1) -> Self { - Self { - payload: NewPublicKey { public_key: item.payload.public_key, id: item.payload.id }, - previous_signing_key: item.previous_signing_key, - previous_signature: item.previous_signature, - new_signing_key: item.new_signing_key, - new_signature: item.new_signature, - } - } - } - - impl From for RegisterKey { - fn from(item: codec::RegisterKeyV1) -> Self { - Self { - public_key: item.public_key, - id: item.id, - overwrite_existing: item.overwrite_existing, - } - } - } - - impl From for SetPolicy { - fn from(item: codec::SetPolicyV1) -> Self { - Self { id: item.id, policy: item.policy } - } - } - - impl From for codec::SignedOperationPayloadV1 { - fn from(item: SignedOperationPayload) -> Self { - codec::SignedOperationPayloadV1 { - operation: match item.operation { - Operation::RegisterKey(v) => codec::OperationV1::RegisterKey(v.into()), - Operation::RotateKey(v) => codec::OperationV1::RotateKey(v.into()), - Operation::SetPolicy(v) => codec::OperationV1::SetPolicy(v.into()), - }, - } - } - } + use super::*; + use parity_scale_codec::{Decode, Encode}; + + use scale_decode::DecodeAsType; + use scale_encode::EncodeAsType; + #[cfg(not(feature = "std"))] + use scale_info::prelude::vec::Vec; + + use scale_info::TypeInfo; + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, Eq, PartialEq, TypeInfo, Clone)] + pub struct KeysV1 { + pub id: String, + pub current: KeyRegistrationV1, + pub expired: Option, + } + + impl MaxEncodedLen for KeysV1 { + fn max_encoded_len() -> usize { + 1024 + KeyRegistrationV1::max_encoded_len() + + Option::::max_encoded_len() + } + } + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, Eq, PartialEq, TypeInfo, Clone)] + pub struct KeyRegistrationV1 { + // Der encoded public key + pub key: PemEncoded, + pub version: u64, + } + + impl MaxEncodedLen for KeyRegistrationV1 { + fn max_encoded_len() -> usize { + 1024 + u64::max_encoded_len() + } + } + + impl From for KeysV1 { + fn from(keys: super::Keys) -> Self { + Self { + id: keys.id, + current: KeyRegistrationV1 { key: keys.current.key, version: keys.current.version }, + expired: keys.expired.map(|expired_key| KeyRegistrationV1 { + key: expired_key.key, + version: expired_key.version, + }), + } + } + } + + impl core::convert::TryFrom for super::Keys { + type Error = core::convert::Infallible; + + fn try_from(keys_v1: KeysV1) -> Result { + Ok(Self { + id: keys_v1.id, + current: super::KeyRegistration { + key: keys_v1.current.key, + version: keys_v1.current.version, + }, + expired: keys_v1.expired.map(|expired_key_v1| super::KeyRegistration { + key: expired_key_v1.key, + version: expired_key_v1.version, + }), + }) + } + } + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] + pub struct BootstrapRootV1 { + pub public_key: PemEncoded, + } + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] + pub struct RegisterKeyV1 { + pub public_key: PemEncoded, + pub id: String, + pub overwrite_existing: bool, + } + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] + pub struct NewPublicKeyV1 { + pub public_key: PemEncoded, + pub id: String, + } + + impl From for NewPublicKeyV1 { + fn from(new_public_key: super::NewPublicKey) -> Self { + Self { public_key: new_public_key.public_key, id: new_public_key.id } + } + } + + impl core::convert::TryFrom for super::NewPublicKey { + type Error = core::convert::Infallible; + + fn try_from(new_public_key_v1: NewPublicKeyV1) -> Result { + Ok(Self { public_key: new_public_key_v1.public_key, id: new_public_key_v1.id }) + } + } + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] + pub struct RotateKeyV1 { + pub payload: NewPublicKeyV1, + pub previous_signing_key: PemEncoded, + pub previous_signature: Vec, + pub new_signing_key: PemEncoded, + pub new_signature: Vec, + } + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] + pub struct SetPolicyV1 { + pub id: String, + pub policy: Policy, + } + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] + pub struct SignedOperationPayloadV1 { + pub operation: OperationV1, + } + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] + pub struct SignedOperationV1 { + pub payload: SignedOperationPayloadV1, + pub verifying_key: PemEncoded, + pub signature: Vec, + } + + impl From for SignedOperationV1 { + fn from(signed_operation: super::SignedOperation) -> Self { + Self { + payload: SignedOperationPayloadV1 { + operation: signed_operation.payload.operation.into(), + }, + verifying_key: signed_operation.verifying_key, + signature: signed_operation.signature, + } + } + } + + impl From for OperationV1 { + fn from(operation: super::Operation) -> Self { + match operation { + super::Operation::RegisterKey(register_key) => + OperationV1::RegisterKey(register_key.into()), + super::Operation::RotateKey(rotate_key) => + OperationV1::RotateKey(rotate_key.into()), + super::Operation::SetPolicy(set_policy) => + OperationV1::SetPolicy(set_policy.into()), + } + } + } + + impl From for RegisterKeyV1 { + fn from(register_key: super::RegisterKey) -> Self { + Self { + public_key: register_key.public_key, + id: register_key.id, + overwrite_existing: register_key.overwrite_existing, + } + } + } + + impl From for RotateKeyV1 { + fn from(rotate_key: super::RotateKey) -> Self { + Self { + payload: rotate_key.payload.into(), + previous_signing_key: rotate_key.previous_signing_key, + previous_signature: rotate_key.previous_signature, + new_signing_key: rotate_key.new_signing_key, + new_signature: rotate_key.new_signature, + } + } + } + + impl From for SetPolicyV1 { + fn from(set_policy: super::SetPolicy) -> Self { + Self { id: set_policy.id, policy: set_policy.policy } + } + } + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, Clone, TypeInfo, PartialEq, Eq)] + pub enum OperationV1 { + RegisterKey(RegisterKeyV1), + RotateKey(RotateKeyV1), + SetPolicy(SetPolicyV1), + } + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] + pub struct OpaSubmissionV1 { + pub version: String, + pub correlation_id: [u8; 16], + pub span_id: u64, + pub payload: PayloadV1, + } + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)] + pub enum PayloadV1 { + BootstrapRoot(BootstrapRootV1), + SignedOperation(SignedOperationV1), + } + + #[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq)] + pub struct PolicyV1(Vec); + + impl PolicyV1 { + pub fn into_vec(self) -> Vec { + self.0 + } + } + + impl MaxEncodedLen for PolicyV1 { + fn max_encoded_len() -> usize { + 1024 * 1024 * 10 + } + } + + impl From for codec::PolicyV1 { + fn from(item: Policy) -> Self { + Self(item.0) + } + } + + impl core::convert::TryFrom for Policy { + type Error = core::convert::Infallible; + + fn try_from(value: codec::PolicyV1) -> Result { + Ok(Self(value.0)) + } + } + + #[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq)] + pub struct PolicyMetaV1 { + pub id: String, + pub hash: H128, + pub policy_address: PolicyAddress, + } + + impl MaxEncodedLen for PolicyMetaV1 { + fn max_encoded_len() -> usize { + 1024 + H128::max_encoded_len() + PolicyAddress::max_encoded_len() + } + } + + impl From for codec::PolicyMetaV1 { + fn from(item: super::PolicyMeta) -> Self { + Self { id: item.id, hash: item.hash, policy_address: item.policy_address } + } + } + + impl core::convert::TryFrom for super::PolicyMeta { + type Error = core::convert::Infallible; + + fn try_from(value: codec::PolicyMetaV1) -> Result { + Ok(Self { id: value.id, hash: value.hash, policy_address: value.policy_address }) + } + } + + impl From for BootstrapRoot { + fn from(item: codec::BootstrapRootV1) -> Self { + Self { public_key: item.public_key } + } + } + + impl From for codec::BootstrapRootV1 { + fn from(item: BootstrapRoot) -> Self { + tracing::debug!(target: "codec_conversion", "Converting BootstrapRoot to BootstrapRootV1"); + Self { public_key: item.public_key } + } + } + + impl From for Payload { + fn from(item: codec::PayloadV1) -> Self { + match item { + codec::PayloadV1::BootstrapRoot(v) => Self::BootstrapRoot(v.into()), + codec::PayloadV1::SignedOperation(v) => Self::SignedOperation(v.into()), + } + } + } + + impl From for OpaSubmission { + fn from(item: codec::OpaSubmissionV1) -> Self { + Self { + correlation_id: item.correlation_id, + version: item.version, + span_id: item.span_id, + payload: item.payload.into(), + } + } + } + + impl From for codec::OpaSubmissionV1 { + fn from(item: OpaSubmission) -> Self { + tracing::debug!(target: "codec_conversion", "Converting OpaSubmission to OpaSubmissionV1"); + Self { + version: item.version, + correlation_id: item.correlation_id, + span_id: item.span_id, + payload: match item.payload { + Payload::BootstrapRoot(v) => { + tracing::trace!(target: "codec_conversion", "Payload is BootstrapRoot"); + codec::PayloadV1::BootstrapRoot(v.into()) + } + Payload::SignedOperation(v) => { + tracing::trace!(target: "codec_conversion", "Payload is SignedOperation"); + codec::PayloadV1::SignedOperation(v.into()) + } + }, + } + } + } + + impl From for Operation { + fn from(item: codec::OperationV1) -> Self { + match item { + codec::OperationV1::RegisterKey(v) => Self::RegisterKey(v.into()), + codec::OperationV1::RotateKey(v) => Self::RotateKey(v.into()), + codec::OperationV1::SetPolicy(v) => Self::SetPolicy(v.into()), + } + } + } + + impl From for SignedOperation { + fn from(item: codec::SignedOperationV1) -> Self { + Self { + payload: SignedOperationPayload { operation: item.payload.operation.into() }, + verifying_key: item.verifying_key, + signature: item.signature, + } + } + } + + impl From for RotateKey { + fn from(item: codec::RotateKeyV1) -> Self { + Self { + payload: NewPublicKey { public_key: item.payload.public_key, id: item.payload.id }, + previous_signing_key: item.previous_signing_key, + previous_signature: item.previous_signature, + new_signing_key: item.new_signing_key, + new_signature: item.new_signature, + } + } + } + + impl From for RegisterKey { + fn from(item: codec::RegisterKeyV1) -> Self { + Self { + public_key: item.public_key, + id: item.id, + overwrite_existing: item.overwrite_existing, + } + } + } + + impl From for SetPolicy { + fn from(item: codec::SetPolicyV1) -> Self { + Self { id: item.id, policy: item.policy } + } + } + + impl From for codec::SignedOperationPayloadV1 { + fn from(item: SignedOperationPayload) -> Self { + codec::SignedOperationPayloadV1 { + operation: match item.operation { + Operation::RegisterKey(v) => codec::OperationV1::RegisterKey(v.into()), + Operation::RotateKey(v) => codec::OperationV1::RotateKey(v.into()), + Operation::SetPolicy(v) => codec::OperationV1::SetPolicy(v.into()), + }, + } + } + } } diff --git a/crates/common/src/opa/mod.rs b/crates/common/src/opa/mod.rs index 78afeb577..1c0e85966 100644 --- a/crates/common/src/opa/mod.rs +++ b/crates/common/src/opa/mod.rs @@ -1,6 +1,6 @@ -mod core; - pub use core::*; +mod core; + #[cfg(feature = "std")] pub mod std; diff --git a/crates/common/src/opa/std.rs b/crates/common/src/opa/std.rs index cc4aefd9b..6e1b25250 100644 --- a/crates/common/src/opa/std.rs +++ b/crates/common/src/opa/std.rs @@ -1,12 +1,11 @@ +use std::{fs::File, io::Read, path::PathBuf, sync::Arc}; + use futures::lock::Mutex; use opa::{bundle::Bundle, wasm::Opa}; use rust_embed::RustEmbed; -use url::Url; - -use std::{fs::File, io::Read, path::PathBuf, sync::Arc}; - use thiserror::Error; use tracing::{error, instrument}; +use url::Url; use crate::identity::{AuthId, IdentityError, OpaData}; @@ -19,235 +18,236 @@ pub struct EmbeddedOpaPolicies; // Prefer these functions over the core ones in std, as they are more efficient pub fn policy_address(id: impl AsRef) -> PolicyAddress { - sp_core::blake2_128(format!("opa:policy:binary:{}", id.as_ref()).as_bytes()).into() + sp_core::blake2_128(format!("opa:policy:binary:{}", id.as_ref()).as_bytes()).into() } // Prefer these functions over the core ones in std, as they are more efficient pub fn policy_meta_address(id: impl AsRef) -> PolicyMetaAddress { - sp_core::blake2_128(format!("opa:policy:meta:{}", id.as_ref()).as_bytes()).into() + sp_core::blake2_128(format!("opa:policy:meta:{}", id.as_ref()).as_bytes()).into() } // Prefer these functions over the core ones in std, as they are more efficient pub fn key_address(id: impl AsRef) -> KeyAddress { - sp_core::blake2_128(format!("opa:keys:{}", id.as_ref()).as_bytes()).into() + sp_core::blake2_128(format!("opa:keys:{}", id.as_ref()).as_bytes()).into() } #[derive(Error, Debug)] pub enum FromUrlError { - #[error("HTTP error while attempting to read from URL: {0}")] - HTTP( - #[from] - #[source] - reqwest::Error, - ), + #[error("HTTP error while attempting to read from URL: {0}")] + HTTP( + #[from] + #[source] + reqwest::Error, + ), - #[error("Invalid URL scheme: {0}")] - InvalidUrlScheme(String), + #[error("Invalid URL scheme: {0}")] + InvalidUrlScheme(String), - #[error("IO error while attempting to read from URL: {0}")] - IO( - #[from] - #[source] - std::io::Error, - ), + #[error("IO error while attempting to read from URL: {0}")] + IO( + #[from] + #[source] + std::io::Error, + ), } pub enum PathOrUrl { - File(PathBuf), - Url(Url), + File(PathBuf), + Url(Url), } pub async fn load_bytes_from_url(url: &str) -> Result, FromUrlError> { - let path_or_url = match url.parse::() { - Ok(url) => PathOrUrl::Url(url), - Err(_) => PathOrUrl::File(PathBuf::from(url)), - }; - - let content = match path_or_url { - PathOrUrl::File(path) => { - let mut file = File::open(path)?; - let mut buf = Vec::new(); - file.read_to_end(&mut buf)?; - Ok(buf) - }, - PathOrUrl::Url(url) => match url.scheme() { - "file" => { - let mut file = File::open(url.path())?; - let mut buf = Vec::new(); - file.read_to_end(&mut buf)?; - Ok(buf) - }, - "http" | "https" => Ok(reqwest::get(url).await?.bytes().await?.into()), - _ => Err(FromUrlError::InvalidUrlScheme(url.scheme().to_owned())), - }, - }?; - - Ok(content) + let path_or_url = match url.parse::() { + Ok(url) => PathOrUrl::Url(url), + Err(_) => PathOrUrl::File(PathBuf::from(url)), + }; + + let content = match path_or_url { + PathOrUrl::File(path) => { + let mut file = File::open(path)?; + let mut buf = Vec::new(); + file.read_to_end(&mut buf)?; + Ok(buf) + } + PathOrUrl::Url(url) => match url.scheme() { + "file" => { + let mut file = File::open(url.path())?; + let mut buf = Vec::new(); + file.read_to_end(&mut buf)?; + Ok(buf) + } + "http" | "https" => Ok(reqwest::get(url).await?.bytes().await?.into()), + _ => Err(FromUrlError::InvalidUrlScheme(url.scheme().to_owned())), + }, + }?; + + Ok(content) } pub fn load_bytes_from_stdin() -> Result, std::io::Error> { - let mut buffer = Vec::new(); - let mut stdin = std::io::stdin(); - let _ = stdin.read_to_end(&mut buffer)?; - Ok(buffer) + let mut buffer = Vec::new(); + let mut stdin = std::io::stdin(); + let _ = stdin.read_to_end(&mut buffer)?; + Ok(buffer) } + #[derive(Debug, Error)] pub enum OpaExecutorError { - #[error("Access denied")] - AccessDenied, - - #[error("Identity error: {0}")] - IdentityError( - #[from] - #[source] - IdentityError, - ), - - #[error("Error loading OPA policy: {0}")] - PolicyLoaderError( - #[from] - #[source] - PolicyLoaderError, - ), - - #[error("Error evaluating OPA policy: {0}")] - OpaEvaluationError( - #[from] - #[source] - anyhow::Error, - ), + #[error("Access denied")] + AccessDenied, + + #[error("Identity error: {0}")] + IdentityError( + #[from] + #[source] + IdentityError, + ), + + #[error("Error loading OPA policy: {0}")] + PolicyLoaderError( + #[from] + #[source] + PolicyLoaderError, + ), + + #[error("Error evaluating OPA policy: {0}")] + OpaEvaluationError( + #[from] + #[source] + anyhow::Error, + ), } #[async_trait::async_trait] pub trait OpaExecutor { - /// Evaluate the loaded OPA instance against the provided identity and context - async fn evaluate(&mut self, id: &AuthId, context: &OpaData) -> Result<(), OpaExecutorError>; + /// Evaluate the loaded OPA instance against the provided identity and context + async fn evaluate(&mut self, id: &AuthId, context: &OpaData) -> Result<(), OpaExecutorError>; } #[derive(Clone, Debug)] pub struct ExecutorContext { - executor: Arc>, - hash: String, + executor: Arc>, + hash: String, } impl ExecutorContext { - #[instrument(skip(self), level = "trace", ret(Debug))] - pub async fn evaluate(&self, id: &AuthId, context: &OpaData) -> Result<(), OpaExecutorError> { - self.executor.lock().await.evaluate(id, context).await - } + #[instrument(skip(self), level = "trace", ret(Debug))] + pub async fn evaluate(&self, id: &AuthId, context: &OpaData) -> Result<(), OpaExecutorError> { + self.executor.lock().await.evaluate(id, context).await + } - pub fn from_loader(loader: &L) -> Result { - Ok(Self { - executor: Arc::new(Mutex::new(WasmtimeOpaExecutor::from_loader(loader)?)), - hash: loader.hash(), - }) - } + pub fn from_loader(loader: &L) -> Result { + Ok(Self { + executor: Arc::new(Mutex::new(WasmtimeOpaExecutor::from_loader(loader)?)), + hash: loader.hash(), + }) + } - pub fn hash(&self) -> &str { - &self.hash - } + pub fn hash(&self) -> &str { + &self.hash + } } #[derive(Debug)] pub struct WasmtimeOpaExecutor { - opa: Opa, - entrypoint: String, + opa: Opa, + entrypoint: String, } impl WasmtimeOpaExecutor { - /// Build a `WasmtimeOpaExecutor` from the `PolicyLoader` provided - pub fn from_loader(loader: &L) -> Result { - Ok(Self { opa: loader.build_opa()?, entrypoint: loader.get_entrypoint().to_owned() }) - } + /// Build a `WasmtimeOpaExecutor` from the `PolicyLoader` provided + pub fn from_loader(loader: &L) -> Result { + Ok(Self { opa: loader.build_opa()?, entrypoint: loader.get_entrypoint().to_owned() }) + } } #[async_trait::async_trait] impl OpaExecutor for WasmtimeOpaExecutor { - #[instrument(level = "trace", skip(self))] - async fn evaluate(&mut self, id: &AuthId, context: &OpaData) -> Result<(), OpaExecutorError> { - self.opa.set_data(context)?; - let input = id.identity()?; - match self.opa.eval(&self.entrypoint, &input)? { - true => Ok(()), - false => Err(OpaExecutorError::AccessDenied), - } - } + #[instrument(level = "trace", skip(self))] + async fn evaluate(&mut self, id: &AuthId, context: &OpaData) -> Result<(), OpaExecutorError> { + self.opa.set_data(context)?; + let input = id.identity()?; + match self.opa.eval(&self.entrypoint, &input)? { + true => Ok(()), + false => Err(OpaExecutorError::AccessDenied), + } + } } #[derive(Debug, Error)] pub enum PolicyLoaderError { - #[error("Failed to read embedded OPA policies")] - EmbeddedOpaPolicies, - - #[error("Policy not found: {0}")] - MissingPolicy(String), - - #[error("OPA bundle I/O error: {0}")] - OpaBundleError( - #[from] - #[source] - opa::bundle::Error, - ), - - #[error("Error loading OPA policy: {0}")] - Substrate( - #[from] - #[source] - anyhow::Error, - ), - - #[error("Error loading from URL: {0}")] - FromUrl( - #[from] - #[source] - FromUrlError, - ), + #[error("Failed to read embedded OPA policies")] + EmbeddedOpaPolicies, + + #[error("Policy not found: {0}")] + MissingPolicy(String), + + #[error("OPA bundle I/O error: {0}")] + OpaBundleError( + #[from] + #[source] + opa::bundle::Error, + ), + + #[error("Error loading OPA policy: {0}")] + Substrate( + #[from] + #[source] + anyhow::Error, + ), + + #[error("Error loading from URL: {0}")] + FromUrl( + #[from] + #[source] + FromUrlError, + ), } #[async_trait::async_trait] pub trait PolicyLoader { - /// Set address of OPA policy - fn set_address(&mut self, address: &str); + /// Set address of OPA policy + fn set_address(&mut self, address: &str); - /// Set OPA policy - fn set_rule_name(&mut self, policy: &str); + /// Set OPA policy + fn set_rule_name(&mut self, policy: &str); - /// Set entrypoint for OPA policy - fn set_entrypoint(&mut self, entrypoint: &str); + /// Set entrypoint for OPA policy + fn set_entrypoint(&mut self, entrypoint: &str); - fn get_address(&self) -> &str; + fn get_address(&self) -> &str; - fn get_rule_name(&self) -> &str; + fn get_rule_name(&self) -> &str; - fn get_entrypoint(&self) -> &str; + fn get_entrypoint(&self) -> &str; - fn get_policy(&self) -> &[u8]; + fn get_policy(&self) -> &[u8]; - /// Load OPA policy from address set in `PolicyLoader` - async fn load_policy(&mut self) -> Result<(), PolicyLoaderError>; + /// Load OPA policy from address set in `PolicyLoader` + async fn load_policy(&mut self) -> Result<(), PolicyLoaderError>; - /// Load OPA policy from provided bytes - fn load_policy_from_bytes(&mut self, policy: &[u8]); + /// Load OPA policy from provided bytes + fn load_policy_from_bytes(&mut self, policy: &[u8]); - /// Return a built OPA instance from the cached policy - #[instrument(level = "trace", skip(self), ret)] - fn build_opa(&self) -> Result { - Ok(Opa::new().build(self.get_policy())?) - } + /// Return a built OPA instance from the cached policy + #[instrument(level = "trace", skip(self), ret)] + fn build_opa(&self) -> Result { + Ok(Opa::new().build(self.get_policy())?) + } - /// Load OPA policy from provided policy bundle - fn load_policy_from_bundle(&mut self, bundle: &Bundle) -> Result<(), PolicyLoaderError> { - let rule = self.get_rule_name(); - self.load_policy_from_bytes( - bundle - .wasm_policies - .iter() - .find(|p| p.entrypoint == rule) - .map(|p| p.bytes.as_ref()) - .ok_or(PolicyLoaderError::MissingPolicy(rule.to_string()))?, - ); - Ok(()) - } + /// Load OPA policy from provided policy bundle + fn load_policy_from_bundle(&mut self, bundle: &Bundle) -> Result<(), PolicyLoaderError> { + let rule = self.get_rule_name(); + self.load_policy_from_bytes( + bundle + .wasm_policies + .iter() + .find(|p| p.entrypoint == rule) + .map(|p| p.bytes.as_ref()) + .ok_or(PolicyLoaderError::MissingPolicy(rule.to_string()))?, + ); + Ok(()) + } - fn hash(&self) -> String; + fn hash(&self) -> String; } diff --git a/crates/common/src/protocol.rs b/crates/common/src/protocol.rs index 47dd452b4..14dc546af 100644 --- a/crates/common/src/protocol.rs +++ b/crates/common/src/protocol.rs @@ -1,52 +1,51 @@ use std::io::Cursor; use prost::Message; +use thiserror::Error; use tracing::span; use crate::{ - identity::SignedIdentity, - prov::{ - operations::ChronicleOperation, to_json_ld::ToJson, ChronicleTransaction, CompactionError, - Contradiction, ExpandedJson, ProcessorError, ProvModel, - }, + identity::SignedIdentity, + prov::{ + ChronicleTransaction, CompactionError, Contradiction, ExpandedJson, + operations::ChronicleOperation, ProcessorError, ProvModel, to_json_ld::ToJson, + }, }; -use thiserror::Error; - use self::messages::event::OptionContradiction; #[derive(Error, Debug)] pub enum ProtocolError { - #[error("Protobuf deserialization error {source}")] - ProtobufDeserialize { - #[from] - #[source] - source: prost::DecodeError, - }, - #[error("Protobuf serialization error {source}")] - ProtobufSerialize { - #[from] - #[source] - source: prost::EncodeError, - }, - #[error("Serde de/serialization error {source}")] - JsonSerialize { - #[from] - #[source] - source: serde_json::Error, - }, - #[error("Problem applying delta {source}")] - ProcessorError { - #[from] - #[source] - source: ProcessorError, - }, - #[error("Could not compact json {source}")] - Compaction { - #[from] - #[source] - source: CompactionError, - }, + #[error("Protobuf deserialization error {source}")] + ProtobufDeserialize { + #[from] + #[source] + source: prost::DecodeError, + }, + #[error("Protobuf serialization error {source}")] + ProtobufSerialize { + #[from] + #[source] + source: prost::EncodeError, + }, + #[error("Serde de/serialization error {source}")] + JsonSerialize { + #[from] + #[source] + source: serde_json::Error, + }, + #[error("Problem applying delta {source}")] + ProcessorError { + #[from] + #[source] + source: ProcessorError, + }, + #[error("Could not compact json {source}")] + Compaction { + #[from] + #[source] + source: CompactionError, + }, } static PROTOCOL_VERSION: &str = "2"; @@ -54,7 +53,7 @@ static PROTOCOL_VERSION: &str = "2"; // Include the `submission` module, which is // generated from ./protos/submission.proto. pub mod messages { - #![allow(clippy::derive_partial_eq_without_eq)] + #![allow(clippy::derive_partial_eq_without_eq)] - include!(concat!(env!("OUT_DIR"), "/_.rs")); + include!(concat!(env!("OUT_DIR"), "/_.rs")); } diff --git a/crates/common/src/prov/id/diesel_bindings.rs b/crates/common/src/prov/id/diesel_bindings.rs index ddb472c4e..d5d0722f3 100644 --- a/crates/common/src/prov/id/diesel_bindings.rs +++ b/crates/common/src/prov/id/diesel_bindings.rs @@ -1,47 +1,47 @@ use super::*; use diesel::{ - backend::Backend, - deserialize::FromSql, - serialize::{Output, ToSql}, - sql_types::Text, + backend::Backend, + deserialize::FromSql, + serialize::{Output, ToSql}, + sql_types::Text, }; impl ToSql for Role -where - DB: Backend, - String: ToSql, + where + DB: Backend, + String: ToSql, { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result { - self.0.to_sql(out) - } + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result { + self.0.to_sql(out) + } } impl FromSql for Role -where - DB: Backend, - String: FromSql, + where + DB: Backend, + String: FromSql, { - fn from_sql(bytes: ::RawValue<'_>) -> diesel::deserialize::Result { - Ok(Self(String::from_sql(bytes)?)) - } + fn from_sql(bytes: ::RawValue<'_>) -> diesel::deserialize::Result { + Ok(Self(String::from_sql(bytes)?)) + } } impl ToSql for ExternalId -where - DB: Backend, - String: ToSql, + where + DB: Backend, + String: ToSql, { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result { - self.0.to_sql(out) - } + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result { + self.0.to_sql(out) + } } impl FromSql for ExternalId -where - DB: Backend, - String: FromSql, + where + DB: Backend, + String: FromSql, { - fn from_sql(bytes: ::RawValue<'_>) -> diesel::deserialize::Result { - Ok(Self(String::from_sql(bytes)?)) - } + fn from_sql(bytes: ::RawValue<'_>) -> diesel::deserialize::Result { + Ok(Self(String::from_sql(bytes)?)) + } } diff --git a/crates/common/src/prov/id/graphlql_scalars.rs b/crates/common/src/prov/id/graphlql_scalars.rs index d6d9b1706..325901240 100644 --- a/crates/common/src/prov/id/graphlql_scalars.rs +++ b/crates/common/src/prov/id/graphlql_scalars.rs @@ -8,74 +8,74 @@ async_graphql::scalar!(ChronicleJSON); /// Derived from an `Activity`'s or `Agent`'s or `Entity`'s subtype. /// The built-in GraphQL field `__TypeName` should be used for union queries. impl ScalarType for DomaintypeId { - fn parse(value: Value) -> InputValueResult { - if let Value::String(value) = value { - // Parse the integer value - Ok(DomaintypeId::try_from(value)?) - } else { - // If the type does not match - Err(InputValueError::expected_type(value)) - } - } + fn parse(value: Value) -> InputValueResult { + if let Value::String(value) = value { + // Parse the integer value + Ok(DomaintypeId::try_from(value)?) + } else { + // If the type does not match + Err(InputValueError::expected_type(value)) + } + } - fn to_value(&self) -> Value { - Value::String(self.to_string()) - } + fn to_value(&self) -> Value { + Value::String(self.to_string()) + } } #[Scalar(name = "EntityID")] /// This is derived from an `Entity`'s externalId, but clients /// should not attempt to synthesize it themselves. impl ScalarType for EntityId { - fn parse(value: Value) -> InputValueResult { - if let Value::String(value) = value { - // Parse the integer value - Ok(EntityId::try_from(value)?) - } else { - // If the type does not match - Err(InputValueError::expected_type(value)) - } - } + fn parse(value: Value) -> InputValueResult { + if let Value::String(value) = value { + // Parse the integer value + Ok(EntityId::try_from(value)?) + } else { + // If the type does not match + Err(InputValueError::expected_type(value)) + } + } - fn to_value(&self) -> Value { - Value::String(self.to_string()) - } + fn to_value(&self) -> Value { + Value::String(self.to_string()) + } } #[Scalar(name = "AgentID")] /// This is derived from an `Agent`'s externalId, but clients /// should not attempt to synthesize it themselves. impl ScalarType for AgentId { - fn parse(value: Value) -> InputValueResult { - if let Value::String(value) = value { - // Parse the integer value - Ok(AgentId::try_from(value)?) - } else { - // If the type does not match - Err(InputValueError::expected_type(value)) - } - } + fn parse(value: Value) -> InputValueResult { + if let Value::String(value) = value { + // Parse the integer value + Ok(AgentId::try_from(value)?) + } else { + // If the type does not match + Err(InputValueError::expected_type(value)) + } + } - fn to_value(&self) -> Value { - Value::String(self.to_string()) - } + fn to_value(&self) -> Value { + Value::String(self.to_string()) + } } #[Scalar(name = "ActivityID")] /// This is derived from an `Activity`'s externalId, but clients /// should not attempt to synthesize it themselves. impl ScalarType for ActivityId { - fn parse(value: Value) -> InputValueResult { - if let Value::String(value) = value { - // Parse the integer value - Ok(ActivityId::try_from(value)?) - } else { - // If the type does not match - Err(InputValueError::expected_type(value)) - } - } + fn parse(value: Value) -> InputValueResult { + if let Value::String(value) = value { + // Parse the integer value + Ok(ActivityId::try_from(value)?) + } else { + // If the type does not match + Err(InputValueError::expected_type(value)) + } + } - fn to_value(&self) -> Value { - Value::String(self.to_string()) - } + fn to_value(&self) -> Value { + Value::String(self.to_string()) + } } diff --git a/crates/common/src/prov/id/mod.rs b/crates/common/src/prov/id/mod.rs index 2a7795b5b..557b59eee 100644 --- a/crates/common/src/prov/id/mod.rs +++ b/crates/common/src/prov/id/mod.rs @@ -1,5 +1,6 @@ #[cfg(feature = "graphql-bindings")] mod graphlql_scalars; + use core::str::FromStr; #[cfg(feature = "graphql-bindings")] @@ -16,7 +17,7 @@ use parity_scale_codec::{alloc::string::String, alloc::vec::Vec}; #[cfg(not(feature = "std"))] use scale_info::{ - prelude::borrow::ToOwned, prelude::string::ToString, prelude::sync::Arc, prelude::*, + prelude::borrow::ToOwned, prelude::string::ToString, prelude::sync::Arc, prelude::*, }; #[cfg(feature = "diesel-bindings")] @@ -32,16 +33,16 @@ use thiserror_no_std::Error; #[derive(Debug, Error)] pub enum ParseIriError { - #[error("Not an IRI")] - NotAnIri(String), - #[error("Unparsable Chronicle IRI")] - UnparsableIri(String), - #[error("Unparsable UUID")] - UnparsableUuid(uuid::Error), - #[error("Unexpected IRI type")] - NotAChronicleUri(String), - #[error("Expected {component}")] - MissingComponent { component: String }, + #[error("Not an IRI")] + NotAnIri(String), + #[error("Unparsable Chronicle IRI")] + UnparsableIri(String), + #[error("Unparsable UUID")] + UnparsableUuid(uuid::Error), + #[error("Unexpected IRI type")] + NotAChronicleUri(String), + #[error("Expected {component}")] + MissingComponent { component: String }, } // Percent decoded, and has the correct authority @@ -50,980 +51,980 @@ pub enum ParseIriError { pub struct ProbableChronicleCURIE(Vec); impl ProbableChronicleCURIE { - fn from_string(str: String) -> Result { - let uri = iri_string::types::UriString::try_from(str) - .map_err(|e| ParseIriError::NotAnIri(e.into_source()))?; - - Self::from_uri(uri) - } - - // Take long or short form uris and return a short form iri - fn from_uri(uri: UriString) -> Result { - let mut uri = uri; - - if uri.as_str().starts_with(Chronicle::LONG_PREFIX) { - uri = UriString::from_str( - &uri.as_str() - .replace(Chronicle::LONG_PREFIX, &(Chronicle::PREFIX.to_owned() + ":")), - ) - .unwrap() - } - - for prefix in Chronicle::LEGACY_PREFIXES { - if uri.as_str().starts_with(prefix) { - uri = UriString::from_str( - &uri.as_str().replace(prefix, &(Chronicle::PREFIX.to_owned() + ":")), - ) - .unwrap() - } - } - - let iri: IriString = uri.into(); - - if iri.scheme_str() != Chronicle::PREFIX { - return Err(ParseIriError::NotAChronicleUri(iri.to_string())); - } - - Ok(Self( - iri.path_str() - .split(':') - .map(|x| percent_encoding::percent_decode_str(x).decode_utf8_lossy().to_string()) - .collect::>(), - )) - } - - fn path_components(&self) -> impl Iterator { - self.0.iter().map(|x| x.as_ref()) - } + fn from_string(str: String) -> Result { + let uri = iri_string::types::UriString::try_from(str) + .map_err(|e| ParseIriError::NotAnIri(e.into_source()))?; + + Self::from_uri(uri) + } + + // Take long or short form uris and return a short form iri + fn from_uri(uri: UriString) -> Result { + let mut uri = uri; + + if uri.as_str().starts_with(Chronicle::LONG_PREFIX) { + uri = UriString::from_str( + &uri.as_str() + .replace(Chronicle::LONG_PREFIX, &(Chronicle::PREFIX.to_owned() + ":")), + ) + .unwrap() + } + + for prefix in Chronicle::LEGACY_PREFIXES { + if uri.as_str().starts_with(prefix) { + uri = UriString::from_str( + &uri.as_str().replace(prefix, &(Chronicle::PREFIX.to_owned() + ":")), + ) + .unwrap() + } + } + + let iri: IriString = uri.into(); + + if iri.scheme_str() != Chronicle::PREFIX { + return Err(ParseIriError::NotAChronicleUri(iri.to_string())); + } + + Ok(Self( + iri.path_str() + .split(':') + .map(|x| percent_encoding::percent_decode_str(x).decode_utf8_lossy().to_string()) + .collect::>(), + )) + } + + fn path_components(&self) -> impl Iterator { + self.0.iter().map(|x| x.as_ref()) + } } impl core::fmt::Display for ProbableChronicleCURIE { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.0.join(":")) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.0.join(":")) + } } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[cfg_attr(feature = "diesel-bindings", derive(AsExpression, FromSqlRow))] #[cfg_attr(feature = "diesel-bindings", diesel(sql_type = diesel::sql_types::Text))] pub struct Role(pub String); impl core::fmt::Display for Role { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.0) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.0) + } } impl From for Role -where - T: AsRef, + where + T: AsRef, { - fn from(s: T) -> Self { - Role(s.as_ref().to_owned()) - } + fn from(s: T) -> Self { + Role(s.as_ref().to_owned()) + } } impl Role { - pub fn as_str(&self) -> &str { - &self.0 - } + pub fn as_str(&self) -> &str { + &self.0 + } } impl AsRef for &Role { - fn as_ref(&self) -> &str { - &self.0 - } + fn as_ref(&self) -> &str { + &self.0 + } } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[cfg_attr(feature = "diesel-bindings", derive(AsExpression, FromSqlRow))] #[cfg_attr(feature = "diesel-bindings", diesel(sql_type = diesel::sql_types::Text))] pub struct ExternalId(String); impl core::fmt::Display for ExternalId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.0) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.0) + } } #[cfg(feature = "graphql-bindings")] async_graphql::scalar!(ExternalId); impl From for ExternalId -where - T: AsRef, + where + T: AsRef, { - fn from(s: T) -> Self { - ExternalId(s.as_ref().to_owned()) - } + fn from(s: T) -> Self { + ExternalId(s.as_ref().to_owned()) + } } impl ExternalId { - pub fn as_str(&self) -> &str { - &self.0 - } + pub fn as_str(&self) -> &str { + &self.0 + } } impl AsRef for &ExternalId { - fn as_ref(&self) -> &str { - &self.0 - } + fn as_ref(&self) -> &str { + &self.0 + } } pub trait ExternalIdPart { - fn external_id_part(&self) -> &ExternalId; + fn external_id_part(&self) -> &ExternalId; } pub trait UuidPart { - fn uuid_part(&self) -> Uuid; + fn uuid_part(&self) -> Uuid; } /// Transform a chronicle IRI into its long-form representation pub trait FromCompact { - fn de_compact(&self) -> String; + fn de_compact(&self) -> String; } impl FromCompact for T { - fn de_compact(&self) -> String { - let replace = Chronicle::PREFIX.to_string() + ":"; - self.to_string().replace(&replace, Chronicle::LONG_PREFIX) - } + fn de_compact(&self) -> String { + let replace = Chronicle::PREFIX.to_string() + ":"; + self.to_string().replace(&replace, Chronicle::LONG_PREFIX) + } } #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, Clone, Ord, PartialOrd)] #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] pub enum ChronicleIri { - Namespace(NamespaceId), - Domaintype(DomaintypeId), - Entity(EntityId), - Agent(AgentId), - Activity(ActivityId), - Association(AssociationId), - Attribution(AttributionId), - Delegation(DelegationId), + Namespace(NamespaceId), + Domaintype(DomaintypeId), + Entity(EntityId), + Agent(AgentId), + Activity(ActivityId), + Association(AssociationId), + Attribution(AttributionId), + Delegation(DelegationId), } #[cfg(feature = "parity-encoding")] impl parity_scale_codec::MaxEncodedLen for ChronicleIri { - fn max_encoded_len() -> usize { - 2048usize - } + fn max_encoded_len() -> usize { + 2048usize + } } impl core::fmt::Display for ChronicleIri { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - ChronicleIri::Namespace(id) => write!(f, "{id}"), - ChronicleIri::Domaintype(id) => write!(f, "{id}"), - ChronicleIri::Entity(id) => write!(f, "{id}"), - ChronicleIri::Agent(id) => write!(f, "{id}"), - ChronicleIri::Activity(id) => write!(f, "{id}"), - ChronicleIri::Association(id) => write!(f, "{id}"), - ChronicleIri::Attribution(id) => write!(f, "{id}"), - ChronicleIri::Delegation(id) => write!(f, "{id}"), - } - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ChronicleIri::Namespace(id) => write!(f, "{id}"), + ChronicleIri::Domaintype(id) => write!(f, "{id}"), + ChronicleIri::Entity(id) => write!(f, "{id}"), + ChronicleIri::Agent(id) => write!(f, "{id}"), + ChronicleIri::Activity(id) => write!(f, "{id}"), + ChronicleIri::Association(id) => write!(f, "{id}"), + ChronicleIri::Attribution(id) => write!(f, "{id}"), + ChronicleIri::Delegation(id) => write!(f, "{id}"), + } + } } impl From for ChronicleIri { - fn from(val: NamespaceId) -> Self { - ChronicleIri::Namespace(val) - } + fn from(val: NamespaceId) -> Self { + ChronicleIri::Namespace(val) + } } impl From for ChronicleIri { - fn from(val: DomaintypeId) -> Self { - ChronicleIri::Domaintype(val) - } + fn from(val: DomaintypeId) -> Self { + ChronicleIri::Domaintype(val) + } } impl From for ChronicleIri { - fn from(val: EntityId) -> Self { - ChronicleIri::Entity(val) - } + fn from(val: EntityId) -> Self { + ChronicleIri::Entity(val) + } } impl From for ChronicleIri { - fn from(val: AgentId) -> Self { - ChronicleIri::Agent(val) - } + fn from(val: AgentId) -> Self { + ChronicleIri::Agent(val) + } } impl From for ChronicleIri { - fn from(val: ActivityId) -> Self { - ChronicleIri::Activity(val) - } + fn from(val: ActivityId) -> Self { + ChronicleIri::Activity(val) + } } impl From for ChronicleIri { - fn from(val: AssociationId) -> Self { - ChronicleIri::Association(val) - } + fn from(val: AssociationId) -> Self { + ChronicleIri::Association(val) + } } impl From for ChronicleIri { - fn from(val: AttributionId) -> Self { - ChronicleIri::Attribution(val) - } + fn from(val: AttributionId) -> Self { + ChronicleIri::Attribution(val) + } } impl From for ChronicleIri { - fn from(val: DelegationId) -> Self { - ChronicleIri::Delegation(val) - } + fn from(val: DelegationId) -> Self { + ChronicleIri::Delegation(val) + } } impl core::str::FromStr for ChronicleIri { - type Err = ParseIriError; + type Err = ParseIriError; - fn from_str(s: &str) -> Result { - trace!(parsing_iri = %s); - //Compacted form, expand + fn from_str(s: &str) -> Result { + trace!(parsing_iri = %s); + //Compacted form, expand - let iri = ProbableChronicleCURIE::from_string(s.to_owned())?; + let iri = ProbableChronicleCURIE::from_string(s.to_owned())?; - //TODO: this just needs to extract the first path component - match iri.path_components().collect::>().as_slice() { - ["agent", ..] => Ok(AgentId::try_from(iri)?.into()), - ["ns", ..] => Ok(NamespaceId::try_from(iri)?.into()), - ["activity", ..] => Ok(ActivityId::try_from(iri)?.into()), - ["entity", ..] => Ok(EntityId::try_from(iri)?.into()), - ["domaintype", ..] => Ok(DomaintypeId::try_from(iri)?.into()), - ["association", ..] => Ok(AssociationId::try_from(iri)?.into()), - ["attribution", ..] => Ok(AttributionId::try_from(iri)?.into()), - ["delegation", ..] => Ok(DelegationId::try_from(iri)?.into()), - _ => Err(ParseIriError::UnparsableIri(s.to_string())), - } - } + //TODO: this just needs to extract the first path component + match iri.path_components().collect::>().as_slice() { + ["agent", ..] => Ok(AgentId::try_from(iri)?.into()), + ["ns", ..] => Ok(NamespaceId::try_from(iri)?.into()), + ["activity", ..] => Ok(ActivityId::try_from(iri)?.into()), + ["entity", ..] => Ok(EntityId::try_from(iri)?.into()), + ["domaintype", ..] => Ok(DomaintypeId::try_from(iri)?.into()), + ["association", ..] => Ok(AssociationId::try_from(iri)?.into()), + ["attribution", ..] => Ok(AttributionId::try_from(iri)?.into()), + ["delegation", ..] => Ok(DelegationId::try_from(iri)?.into()), + _ => Err(ParseIriError::UnparsableIri(s.to_string())), + } + } } impl ChronicleIri { - // Coerce this to a `NamespaceId`, if possible - pub fn namespace(self) -> Result { - match self { - ChronicleIri::Namespace(ns) => Ok(ns), - _ => Err(ParseIriError::NotAChronicleUri(self.to_string())), - } - } + // Coerce this to a `NamespaceId`, if possible + pub fn namespace(self) -> Result { + match self { + ChronicleIri::Namespace(ns) => Ok(ns), + _ => Err(ParseIriError::NotAChronicleUri(self.to_string())), + } + } } #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct ChronicleJSON(pub serde_json::Value); fn optional_component(external_id: &str, component: &str) -> Result, ParseIriError> { - let kv = format!("{external_id}="); - if !component.starts_with(&*kv) { - return Err(ParseIriError::MissingComponent { component: external_id.to_string() }); - } + let kv = format!("{external_id}="); + if !component.starts_with(&*kv) { + return Err(ParseIriError::MissingComponent { component: external_id.to_string() }); + } - match component.replace(&*kv, "") { - s if s.is_empty() => Ok(None), - s => Ok(Some(s)), - } + match component.replace(&*kv, "") { + s if s.is_empty() => Ok(None), + s => Ok(Some(s)), + } } // A composite identifier of agent, activity and role #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, Clone, Ord, PartialOrd)] #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] pub struct DelegationId { - delegate: ExternalId, - responsible: ExternalId, - activity: Option, - role: Option, + delegate: ExternalId, + responsible: ExternalId, + activity: Option, + role: Option, } impl core::fmt::Display for DelegationId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str(Into::::into(self).as_str()) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(Into::::into(self).as_str()) + } } impl DelegationId { - pub fn from_component_ids( - delegate: &AgentId, - responsible: &AgentId, - activity: Option<&ActivityId>, - role: Option>, - ) -> Self { - Self { - delegate: delegate.external_id_part().clone(), - responsible: responsible.external_id_part().clone(), - activity: activity.map(|x| ExternalIdPart::external_id_part(x).to_owned()), - role: role.map(|x| Role::from(x.as_ref())), - } - } - - pub fn delegate(&self) -> AgentId { - AgentId::from_external_id(&self.delegate) - } - - pub fn responsible(&self) -> AgentId { - AgentId::from_external_id(&self.responsible) - } - - pub fn activity(&self) -> Option { - self.activity.as_ref().map(ActivityId::from_external_id) - } - - pub fn role(&self) -> &Option { - &self.role - } + pub fn from_component_ids( + delegate: &AgentId, + responsible: &AgentId, + activity: Option<&ActivityId>, + role: Option>, + ) -> Self { + Self { + delegate: delegate.external_id_part().clone(), + responsible: responsible.external_id_part().clone(), + activity: activity.map(|x| ExternalIdPart::external_id_part(x).to_owned()), + role: role.map(|x| Role::from(x.as_ref())), + } + } + + pub fn delegate(&self) -> AgentId { + AgentId::from_external_id(&self.delegate) + } + + pub fn responsible(&self) -> AgentId { + AgentId::from_external_id(&self.responsible) + } + + pub fn activity(&self) -> Option { + self.activity.as_ref().map(ActivityId::from_external_id) + } + + pub fn role(&self) -> &Option { + &self.role + } } impl TryFrom for DelegationId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: String) -> Result { - ProbableChronicleCURIE::from_string(value)?.try_into() - } + fn try_from(value: String) -> Result { + ProbableChronicleCURIE::from_string(value)?.try_into() + } } impl TryFrom for DelegationId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: UriString) -> Result { - ProbableChronicleCURIE::from_uri(value)?.try_into() - } + fn try_from(value: UriString) -> Result { + ProbableChronicleCURIE::from_uri(value)?.try_into() + } } impl TryFrom for DelegationId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(iri: ProbableChronicleCURIE) -> Result { - match iri.path_components().collect::>().as_slice() { - [_, delegate, responsible, role, activity] => Ok(Self { - delegate: ExternalId::from(delegate), - responsible: ExternalId::from(responsible), - role: optional_component("role", role)?.map(Role::from), - activity: optional_component("activity", activity)?.map(ExternalId::from), - }), + fn try_from(iri: ProbableChronicleCURIE) -> Result { + match iri.path_components().collect::>().as_slice() { + [_, delegate, responsible, role, activity] => Ok(Self { + delegate: ExternalId::from(delegate), + responsible: ExternalId::from(responsible), + role: optional_component("role", role)?.map(Role::from), + activity: optional_component("activity", activity)?.map(ExternalId::from), + }), - _ => Err(ParseIriError::UnparsableIri(iri.to_string())), - } - } + _ => Err(ParseIriError::UnparsableIri(iri.to_string())), + } + } } impl From<&DelegationId> for UriString { - fn from(val: &DelegationId) -> Self { - Chronicle::delegation( - &AgentId::from_external_id(&val.delegate), - &AgentId::from_external_id(&val.responsible), - &val.activity().map(|n| ActivityId::from_external_id(n.external_id_part())), - &val.role, - ) - .unwrap() - } + fn from(val: &DelegationId) -> Self { + Chronicle::delegation( + &AgentId::from_external_id(&val.delegate), + &AgentId::from_external_id(&val.responsible), + &val.activity().map(|n| ActivityId::from_external_id(n.external_id_part())), + &val.role, + ) + .unwrap() + } } // A composite identifier of agent, activity and role #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, Clone, Ord, PartialOrd)] #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] pub struct AssociationId { - agent: ExternalId, - activity: ExternalId, - role: Option, + agent: ExternalId, + activity: ExternalId, + role: Option, } impl core::fmt::Display for AssociationId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str(Into::::into(self).as_str()) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(Into::::into(self).as_str()) + } } impl AssociationId { - pub fn from_component_ids( - agent: &AgentId, - activity: &ActivityId, - role: Option>, - ) -> Self { - Self { - agent: agent.external_id_part().clone(), - activity: activity.external_id_part().clone(), - role: role.map(|x| Role::from(x.as_ref())), - } - } - - pub fn agent(&self) -> AgentId { - AgentId::from_external_id(&self.agent) - } - - pub fn activity(&self) -> ActivityId { - ActivityId::from_external_id(&self.activity) - } + pub fn from_component_ids( + agent: &AgentId, + activity: &ActivityId, + role: Option>, + ) -> Self { + Self { + agent: agent.external_id_part().clone(), + activity: activity.external_id_part().clone(), + role: role.map(|x| Role::from(x.as_ref())), + } + } + + pub fn agent(&self) -> AgentId { + AgentId::from_external_id(&self.agent) + } + + pub fn activity(&self) -> ActivityId { + ActivityId::from_external_id(&self.activity) + } } impl TryFrom for AssociationId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: String) -> Result { - ProbableChronicleCURIE::from_string(value)?.try_into() - } + fn try_from(value: String) -> Result { + ProbableChronicleCURIE::from_string(value)?.try_into() + } } impl TryFrom for AssociationId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: UriString) -> Result { - ProbableChronicleCURIE::from_uri(value)?.try_into() - } + fn try_from(value: UriString) -> Result { + ProbableChronicleCURIE::from_uri(value)?.try_into() + } } impl TryFrom for AssociationId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(iri: ProbableChronicleCURIE) -> Result { - match iri.path_components().collect::>().as_slice() { - [_, agent, activity, role] => Ok(Self { - agent: ExternalId::from(agent), - activity: ExternalId::from(activity), - role: optional_component("role", role)?.map(Role::from), - }), + fn try_from(iri: ProbableChronicleCURIE) -> Result { + match iri.path_components().collect::>().as_slice() { + [_, agent, activity, role] => Ok(Self { + agent: ExternalId::from(agent), + activity: ExternalId::from(activity), + role: optional_component("role", role)?.map(Role::from), + }), - _ => Err(ParseIriError::UnparsableIri(iri.to_string())), - } - } + _ => Err(ParseIriError::UnparsableIri(iri.to_string())), + } + } } impl From<&AssociationId> for UriString { - fn from(val: &AssociationId) -> Self { - Chronicle::association( - &AgentId::from_external_id(&val.agent), - &ActivityId::from_external_id(&val.activity), - &val.role, - ) - .unwrap() - } + fn from(val: &AssociationId) -> Self { + Chronicle::association( + &AgentId::from_external_id(&val.agent), + &ActivityId::from_external_id(&val.activity), + &val.role, + ) + .unwrap() + } } // A composite identifier of agent, entity, and role #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, Clone, Ord, PartialOrd)] #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] pub struct AttributionId { - agent: ExternalId, - entity: ExternalId, - role: Option, + agent: ExternalId, + entity: ExternalId, + role: Option, } impl core::fmt::Display for AttributionId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str(Into::::into(self).as_str()) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(Into::::into(self).as_str()) + } } impl AttributionId { - pub fn from_component_ids( - agent: &AgentId, - entity: &EntityId, - role: Option>, - ) -> Self { - Self { - agent: agent.external_id_part().clone(), - entity: entity.external_id_part().clone(), - role: role.map(|x| Role::from(x.as_ref())), - } - } - - pub fn agent(&self) -> AgentId { - AgentId::from_external_id(&self.agent) - } - - pub fn entity(&self) -> EntityId { - EntityId::from_external_id(&self.entity) - } + pub fn from_component_ids( + agent: &AgentId, + entity: &EntityId, + role: Option>, + ) -> Self { + Self { + agent: agent.external_id_part().clone(), + entity: entity.external_id_part().clone(), + role: role.map(|x| Role::from(x.as_ref())), + } + } + + pub fn agent(&self) -> AgentId { + AgentId::from_external_id(&self.agent) + } + + pub fn entity(&self) -> EntityId { + EntityId::from_external_id(&self.entity) + } } impl TryFrom for AttributionId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: String) -> Result { - ProbableChronicleCURIE::from_string(value)?.try_into() - } + fn try_from(value: String) -> Result { + ProbableChronicleCURIE::from_string(value)?.try_into() + } } impl TryFrom for AttributionId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: UriString) -> Result { - ProbableChronicleCURIE::from_uri(value)?.try_into() - } + fn try_from(value: UriString) -> Result { + ProbableChronicleCURIE::from_uri(value)?.try_into() + } } impl TryFrom for AttributionId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(iri: ProbableChronicleCURIE) -> Result { - match iri.path_components().collect::>().as_slice() { - [_, agent, entity, role] => Ok(Self { - agent: ExternalId::from(agent), - entity: ExternalId::from(entity), - role: optional_component("role", role)?.map(Role::from), - }), + fn try_from(iri: ProbableChronicleCURIE) -> Result { + match iri.path_components().collect::>().as_slice() { + [_, agent, entity, role] => Ok(Self { + agent: ExternalId::from(agent), + entity: ExternalId::from(entity), + role: optional_component("role", role)?.map(Role::from), + }), - _ => Err(ParseIriError::UnparsableIri(iri.to_string())), - } - } + _ => Err(ParseIriError::UnparsableIri(iri.to_string())), + } + } } impl From<&AttributionId> for UriString { - fn from(val: &AttributionId) -> Self { - Chronicle::attribution( - &AgentId::from_external_id(&val.agent), - &EntityId::from_external_id(&val.entity), - &val.role, - ) - .unwrap() - } + fn from(val: &AttributionId) -> Self { + Chronicle::attribution( + &AgentId::from_external_id(&val.agent), + &EntityId::from_external_id(&val.entity), + &val.role, + ) + .unwrap() + } } #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, Clone, Ord, PartialOrd)] #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] pub struct DomaintypeId(ExternalId); impl core::fmt::Display for DomaintypeId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str(Into::::into(self).as_str()) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(Into::::into(self).as_str()) + } } impl ExternalIdPart for DomaintypeId { - fn external_id_part(&self) -> &ExternalId { - &self.0 - } + fn external_id_part(&self) -> &ExternalId { + &self.0 + } } impl DomaintypeId { - pub fn from_external_id(external_id: impl AsRef) -> Self { - Self(external_id.as_ref().into()) - } + pub fn from_external_id(external_id: impl AsRef) -> Self { + Self(external_id.as_ref().into()) + } } impl TryFrom for DomaintypeId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: String) -> Result { - ProbableChronicleCURIE::from_string(value)?.try_into() - } + fn try_from(value: String) -> Result { + ProbableChronicleCURIE::from_string(value)?.try_into() + } } impl TryFrom for DomaintypeId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: UriString) -> Result { - ProbableChronicleCURIE::from_uri(value)?.try_into() - } + fn try_from(value: UriString) -> Result { + ProbableChronicleCURIE::from_uri(value)?.try_into() + } } impl TryFrom for DomaintypeId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(iri: ProbableChronicleCURIE) -> Result { - match iri.path_components().collect::>().as_slice() { - [_, external_id] => Ok(Self(ExternalId::from(external_id))), - _ => Err(ParseIriError::UnparsableIri(iri.to_string())), - } - } + fn try_from(iri: ProbableChronicleCURIE) -> Result { + match iri.path_components().collect::>().as_slice() { + [_, external_id] => Ok(Self(ExternalId::from(external_id))), + _ => Err(ParseIriError::UnparsableIri(iri.to_string())), + } + } } impl From<&DomaintypeId> for UriString { - fn from(val: &DomaintypeId) -> Self { - Chronicle::domaintype(&val.0).unwrap() - } + fn from(val: &DomaintypeId) -> Self { + Chronicle::domaintype(&val.0).unwrap() + } } #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Clone, Ord, PartialOrd)] #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] pub struct NamespaceId { - external_id: ExternalId, - uuid: [u8; 16], + external_id: ExternalId, + uuid: [u8; 16], } impl core::fmt::Display for NamespaceId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str(Into::::into(self).as_str()) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(Into::::into(self).as_str()) + } } impl core::fmt::Debug for NamespaceId { - fn fmt( - &self, - f: &mut scale_info::prelude::fmt::Formatter<'_>, - ) -> scale_info::prelude::fmt::Result { - f.debug_struct("NamespaceId") - .field("external_id", &self.external_id) - .field("uuid", &Uuid::from_bytes(self.uuid)) - .finish() - } + fn fmt( + &self, + f: &mut scale_info::prelude::fmt::Formatter<'_>, + ) -> scale_info::prelude::fmt::Result { + f.debug_struct("NamespaceId") + .field("external_id", &self.external_id) + .field("uuid", &Uuid::from_bytes(self.uuid)) + .finish() + } } impl NamespaceId { - pub fn from_external_id(external_id: impl AsRef, uuid: Uuid) -> Self { - Self { external_id: external_id.as_ref().into(), uuid: uuid.into_bytes() } - } + pub fn from_external_id(external_id: impl AsRef, uuid: Uuid) -> Self { + Self { external_id: external_id.as_ref().into(), uuid: uuid.into_bytes() } + } } impl ExternalIdPart for NamespaceId { - fn external_id_part(&self) -> &ExternalId { - &self.external_id - } + fn external_id_part(&self) -> &ExternalId { + &self.external_id + } } impl UuidPart for NamespaceId { - fn uuid_part(&self) -> Uuid { - Uuid::from_bytes(self.uuid) - } + fn uuid_part(&self) -> Uuid { + Uuid::from_bytes(self.uuid) + } } impl TryFrom<&'_ str> for NamespaceId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: &str) -> Result { - ProbableChronicleCURIE::from_string(value.to_owned())?.try_into() - } + fn try_from(value: &str) -> Result { + ProbableChronicleCURIE::from_string(value.to_owned())?.try_into() + } } impl TryFrom for NamespaceId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: String) -> Result { - ProbableChronicleCURIE::from_string(value)?.try_into() - } + fn try_from(value: String) -> Result { + ProbableChronicleCURIE::from_string(value)?.try_into() + } } impl TryFrom for NamespaceId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: UriString) -> Result { - ProbableChronicleCURIE::from_uri(value)?.try_into() - } + fn try_from(value: UriString) -> Result { + ProbableChronicleCURIE::from_uri(value)?.try_into() + } } impl TryFrom for NamespaceId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(iri: ProbableChronicleCURIE) -> Result { - match iri.path_components().collect::>().as_slice() { - [_, external_id, uuid] => Ok(Self { - external_id: ExternalId::from(external_id), - uuid: Uuid::parse_str(uuid).map_err(ParseIriError::UnparsableUuid)?.into_bytes(), - }), + fn try_from(iri: ProbableChronicleCURIE) -> Result { + match iri.path_components().collect::>().as_slice() { + [_, external_id, uuid] => Ok(Self { + external_id: ExternalId::from(external_id), + uuid: Uuid::parse_str(uuid).map_err(ParseIriError::UnparsableUuid)?.into_bytes(), + }), - _ => Err(ParseIriError::UnparsableIri(format!("{:?}", iri))), - } - } + _ => Err(ParseIriError::UnparsableIri(format!("{:?}", iri))), + } + } } impl From<&NamespaceId> for UriString { - fn from(val: &NamespaceId) -> Self { - Chronicle::namespace(&val.external_id, &val.uuid_part()).unwrap() - } + fn from(val: &NamespaceId) -> Self { + Chronicle::namespace(&val.external_id, &val.uuid_part()).unwrap() + } } #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, Clone, Ord, PartialOrd)] #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] pub struct EntityId(ExternalId); impl core::fmt::Display for EntityId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str(Into::::into(self).as_str()) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(Into::::into(self).as_str()) + } } impl EntityId { - pub fn from_external_id(external_id: impl AsRef) -> Self { - Self(external_id.as_ref().into()) - } + pub fn from_external_id(external_id: impl AsRef) -> Self { + Self(external_id.as_ref().into()) + } } impl ExternalIdPart for EntityId { - fn external_id_part(&self) -> &ExternalId { - &self.0 - } + fn external_id_part(&self) -> &ExternalId { + &self.0 + } } impl TryFrom for EntityId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: String) -> Result { - ProbableChronicleCURIE::from_string(value)?.try_into() - } + fn try_from(value: String) -> Result { + ProbableChronicleCURIE::from_string(value)?.try_into() + } } impl TryFrom for EntityId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: UriString) -> Result { - ProbableChronicleCURIE::from_uri(value)?.try_into() - } + fn try_from(value: UriString) -> Result { + ProbableChronicleCURIE::from_uri(value)?.try_into() + } } impl TryFrom for EntityId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: ProbableChronicleCURIE) -> Result { - match value.path_components().collect::>().as_slice() { - [_, external_id] => Ok(Self(ExternalId::from(external_id))), + fn try_from(value: ProbableChronicleCURIE) -> Result { + match value.path_components().collect::>().as_slice() { + [_, external_id] => Ok(Self(ExternalId::from(external_id))), - _ => Err(ParseIriError::UnparsableIri(value.to_string())), - } - } + _ => Err(ParseIriError::UnparsableIri(value.to_string())), + } + } } impl From<&EntityId> for UriString { - fn from(val: &EntityId) -> Self { - Chronicle::entity(&val.0).unwrap() - } + fn from(val: &EntityId) -> Self { + Chronicle::entity(&val.0).unwrap() + } } /// Input either a short-form `externalId`, e.g. "agreement", /// or long-form Chronicle `id`, e.g. "chronicle:entity:agreement" #[cfg_attr(feature = "graphql-bindings", derive(async_graphql::OneofObject))] pub enum EntityIdOrExternal { - ExternalId(String), - Id(EntityId), + ExternalId(String), + Id(EntityId), } impl From for EntityId { - fn from(input: EntityIdOrExternal) -> Self { - match input { - EntityIdOrExternal::ExternalId(external_id) => Self::from_external_id(external_id), - EntityIdOrExternal::Id(id) => id, - } - } + fn from(input: EntityIdOrExternal) -> Self { + match input { + EntityIdOrExternal::ExternalId(external_id) => Self::from_external_id(external_id), + EntityIdOrExternal::Id(id) => id, + } + } } #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, Clone, Ord, PartialOrd)] #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] pub struct AgentId(ExternalId); impl core::fmt::Display for AgentId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str(Into::::into(self).as_str()) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(Into::::into(self).as_str()) + } } impl AgentId { - pub fn from_external_id(external_id: impl AsRef) -> Self { - Self(external_id.as_ref().into()) - } + pub fn from_external_id(external_id: impl AsRef) -> Self { + Self(external_id.as_ref().into()) + } } impl ExternalIdPart for AgentId { - fn external_id_part(&self) -> &ExternalId { - &self.0 - } + fn external_id_part(&self) -> &ExternalId { + &self.0 + } } impl TryFrom for AgentId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: String) -> Result { - ProbableChronicleCURIE::from_string(value)?.try_into() - } + fn try_from(value: String) -> Result { + ProbableChronicleCURIE::from_string(value)?.try_into() + } } impl TryFrom for AgentId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: UriString) -> Result { - ProbableChronicleCURIE::from_uri(value)?.try_into() - } + fn try_from(value: UriString) -> Result { + ProbableChronicleCURIE::from_uri(value)?.try_into() + } } impl TryFrom for AgentId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: ProbableChronicleCURIE) -> Result { - match value.path_components().collect::>().as_slice() { - [_, external_id] => Ok(Self(ExternalId::from(external_id))), - _ => Err(ParseIriError::UnparsableIri(value.to_string())), - } - } + fn try_from(value: ProbableChronicleCURIE) -> Result { + match value.path_components().collect::>().as_slice() { + [_, external_id] => Ok(Self(ExternalId::from(external_id))), + _ => Err(ParseIriError::UnparsableIri(value.to_string())), + } + } } impl From<&AgentId> for UriString { - fn from(val: &AgentId) -> Self { - Chronicle::agent(&val.0).unwrap() - } + fn from(val: &AgentId) -> Self { + Chronicle::agent(&val.0).unwrap() + } } /// Input either a short-form `externalId`, e.g. "bob", /// or long-form Chronicle `id`, e.g. "chronicle:agent:bob" #[cfg_attr(feature = "graphql-bindings", derive(OneofObject))] pub enum AgentIdOrExternal { - ExternalId(String), - Id(AgentId), + ExternalId(String), + Id(AgentId), } impl From for AgentId { - fn from(input: AgentIdOrExternal) -> Self { - match input { - AgentIdOrExternal::ExternalId(external_id) => Self::from_external_id(external_id), - AgentIdOrExternal::Id(id) => id, - } - } + fn from(input: AgentIdOrExternal) -> Self { + match input { + AgentIdOrExternal::ExternalId(external_id) => Self::from_external_id(external_id), + AgentIdOrExternal::Id(id) => id, + } + } } #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Debug, Clone, Ord, PartialOrd)] #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] pub struct ActivityId(ExternalId); impl core::fmt::Display for ActivityId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str(UriString::from(self).as_str()) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(UriString::from(self).as_str()) + } } impl ActivityId { - pub fn from_external_id(external_id: impl AsRef) -> Self { - Self(external_id.as_ref().into()) - } + pub fn from_external_id(external_id: impl AsRef) -> Self { + Self(external_id.as_ref().into()) + } } impl ExternalIdPart for ActivityId { - fn external_id_part(&self) -> &ExternalId { - &self.0 - } + fn external_id_part(&self) -> &ExternalId { + &self.0 + } } impl TryFrom for ActivityId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: String) -> Result { - ProbableChronicleCURIE::from_string(value)?.try_into() - } + fn try_from(value: String) -> Result { + ProbableChronicleCURIE::from_string(value)?.try_into() + } } impl TryFrom for ActivityId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(value: UriString) -> Result { - ProbableChronicleCURIE::from_uri(value)?.try_into() - } + fn try_from(value: UriString) -> Result { + ProbableChronicleCURIE::from_uri(value)?.try_into() + } } impl TryFrom for ActivityId { - type Error = ParseIriError; + type Error = ParseIriError; - fn try_from(iri: ProbableChronicleCURIE) -> Result { - match iri.path_components().collect::>().as_slice() { - [_, external_id] => Ok(Self(ExternalId::from(external_id))), + fn try_from(iri: ProbableChronicleCURIE) -> Result { + match iri.path_components().collect::>().as_slice() { + [_, external_id] => Ok(Self(ExternalId::from(external_id))), - _ => Err(ParseIriError::UnparsableIri(iri.to_string())), - } - } + _ => Err(ParseIriError::UnparsableIri(iri.to_string())), + } + } } impl From<&ActivityId> for UriString { - fn from(val: &ActivityId) -> Self { - Chronicle::activity(&val.0).unwrap() - } + fn from(val: &ActivityId) -> Self { + Chronicle::activity(&val.0).unwrap() + } } /// Input either a short-form `externalId`, e.g. "record", /// or long-form Chronicle `id`, e.g. "chronicle:activity:record" #[cfg_attr(feature = "graphql-bindings", derive(OneofObject))] pub enum ActivityIdOrExternal { - ExternalId(String), - Id(ActivityId), + ExternalId(String), + Id(ActivityId), } impl From for ActivityId { - fn from(input: ActivityIdOrExternal) -> Self { - match input { - ActivityIdOrExternal::ExternalId(external_id) => Self::from_external_id(external_id), - ActivityIdOrExternal::Id(id) => id, - } - } + fn from(input: ActivityIdOrExternal) -> Self { + match input { + ActivityIdOrExternal::ExternalId(external_id) => Self::from_external_id(external_id), + ActivityIdOrExternal::Id(id) => id, + } + } } /// A `Namespace` ID reserved for Chronicle system use. diff --git a/crates/common/src/prov/mod.rs b/crates/common/src/prov/mod.rs index 9f3cf4a54..f8a95a7b9 100644 --- a/crates/common/src/prov/mod.rs +++ b/crates/common/src/prov/mod.rs @@ -1,7 +1,8 @@ +pub use id::*; +pub use model::*; + mod id; mod model; pub mod operations; pub mod vocab; -pub use id::*; -pub use model::*; diff --git a/crates/common/src/prov/model/contradiction.rs b/crates/common/src/prov/model/contradiction.rs index d5030a6b0..42faa4dba 100644 --- a/crates/common/src/prov/model/contradiction.rs +++ b/crates/common/src/prov/model/contradiction.rs @@ -1,127 +1,125 @@ use chrono::{DateTime, Utc}; - #[cfg(not(feature = "std"))] use parity_scale_codec::{alloc::string::String, alloc::vec::Vec}; - #[cfg(not(feature = "std"))] use scale_info::prelude::*; use crate::{ - attributes::Attribute, - prov::{operations::TimeWrapper, ChronicleIri, NamespaceId}, + attributes::Attribute, + prov::{ChronicleIri, NamespaceId, operations::TimeWrapper}, }; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] pub struct Contradiction { - pub(crate) id: ChronicleIri, - pub(crate) namespace: NamespaceId, - pub(crate) contradiction: Vec, + pub(crate) id: ChronicleIri, + pub(crate) namespace: NamespaceId, + pub(crate) contradiction: Vec, } impl core::fmt::Display for Contradiction { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Contradiction {{ ")?; - for detail in &self.contradiction { - match detail { - ContradictionDetail::AttributeValueChange { name, value, attempted } => { - write!(f, "attribute value change: {name} {value:?} {attempted:?}")?; - }, - ContradictionDetail::StartAlteration { value, attempted } => { - write!(f, "start date alteration: {value} {attempted}")?; - }, - ContradictionDetail::EndAlteration { value, attempted } => { - write!(f, "end date alteration: {value} {attempted}")?; - }, - ContradictionDetail::InvalidRange { start, end } => { - write!(f, "invalid range: {start} {end}")?; - }, - } - } - write!(f, " }}") - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Contradiction {{ ")?; + for detail in &self.contradiction { + match detail { + ContradictionDetail::AttributeValueChange { name, value, attempted } => { + write!(f, "attribute value change: {name} {value:?} {attempted:?}")?; + } + ContradictionDetail::StartAlteration { value, attempted } => { + write!(f, "start date alteration: {value} {attempted}")?; + } + ContradictionDetail::EndAlteration { value, attempted } => { + write!(f, "end date alteration: {value} {attempted}")?; + } + ContradictionDetail::InvalidRange { start, end } => { + write!(f, "invalid range: {start} {end}")?; + } + } + } + write!(f, " }}") + } } impl Contradiction { - pub fn start_date_alteration( - id: ChronicleIri, - namespace: NamespaceId, - value: DateTime, - attempted: DateTime, - ) -> Self { - Self { - id, - namespace, - contradiction: vec![ContradictionDetail::StartAlteration { - value: value.into(), - attempted: attempted.into(), - }], - } - } + pub fn start_date_alteration( + id: ChronicleIri, + namespace: NamespaceId, + value: DateTime, + attempted: DateTime, + ) -> Self { + Self { + id, + namespace, + contradiction: vec![ContradictionDetail::StartAlteration { + value: value.into(), + attempted: attempted.into(), + }], + } + } - pub fn end_date_alteration( - id: ChronicleIri, - namespace: NamespaceId, - value: DateTime, - attempted: DateTime, - ) -> Self { - Self { - id, - namespace, - contradiction: vec![ContradictionDetail::EndAlteration { - value: value.into(), - attempted: attempted.into(), - }], - } - } + pub fn end_date_alteration( + id: ChronicleIri, + namespace: NamespaceId, + value: DateTime, + attempted: DateTime, + ) -> Self { + Self { + id, + namespace, + contradiction: vec![ContradictionDetail::EndAlteration { + value: value.into(), + attempted: attempted.into(), + }], + } + } - pub fn invalid_range( - id: ChronicleIri, - namespace: NamespaceId, - start: DateTime, - end: DateTime, - ) -> Self { - Self { - id, - namespace, - contradiction: vec![ContradictionDetail::InvalidRange { - start: start.into(), - end: end.into(), - }], - } - } + pub fn invalid_range( + id: ChronicleIri, + namespace: NamespaceId, + start: DateTime, + end: DateTime, + ) -> Self { + Self { + id, + namespace, + contradiction: vec![ContradictionDetail::InvalidRange { + start: start.into(), + end: end.into(), + }], + } + } - pub fn attribute_value_change( - id: ChronicleIri, - namespace: NamespaceId, - changes: Vec<(String, Attribute, Attribute)>, - ) -> Self { - Self { - id, - namespace, - contradiction: changes - .into_iter() - .map(|(name, value, attempted)| ContradictionDetail::AttributeValueChange { - name, - value, - attempted, - }) - .collect(), - } - } + pub fn attribute_value_change( + id: ChronicleIri, + namespace: NamespaceId, + changes: Vec<(String, Attribute, Attribute)>, + ) -> Self { + Self { + id, + namespace, + contradiction: changes + .into_iter() + .map(|(name, value, attempted)| ContradictionDetail::AttributeValueChange { + name, + value, + attempted, + }) + .collect(), + } + } } #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] pub enum ContradictionDetail { - AttributeValueChange { name: String, value: Attribute, attempted: Attribute }, - StartAlteration { value: TimeWrapper, attempted: TimeWrapper }, - EndAlteration { value: TimeWrapper, attempted: TimeWrapper }, - InvalidRange { start: TimeWrapper, end: TimeWrapper }, + AttributeValueChange { name: String, value: Attribute, attempted: Attribute }, + StartAlteration { value: TimeWrapper, attempted: TimeWrapper }, + EndAlteration { value: TimeWrapper, attempted: TimeWrapper }, + InvalidRange { start: TimeWrapper, end: TimeWrapper }, } diff --git a/crates/common/src/prov/model/json_ld/from_json_ld.rs b/crates/common/src/prov/model/json_ld/from_json_ld.rs index ae57834cb..e83c2f5b1 100644 --- a/crates/common/src/prov/model/json_ld/from_json_ld.rs +++ b/crates/common/src/prov/model/json_ld/from_json_ld.rs @@ -1,782 +1,779 @@ use chrono::{DateTime, Utc}; - use futures::{future::BoxFuture, FutureExt}; use iref::IriBuf; use iri_string::types::IriString; use json_ld::{ - syntax::IntoJsonWithContextMeta, Indexed, Loader, Node, Profile, RemoteDocument, Term, + Indexed, Loader, Node, Profile, RemoteDocument, syntax::IntoJsonWithContextMeta, Term, }; use locspan::Meta; use mime::Mime; -use rdf_types::{vocabulary::no_vocabulary_mut, BlankIdBuf, IriVocabularyMut}; -use serde_json::{json, Value}; - -use tracing::{error, instrument, trace}; - #[cfg(not(feature = "std"))] use parity_scale_codec::{alloc::string::String, alloc::vec::Vec, prelude::*}; +use rdf_types::{BlankIdBuf, IriVocabularyMut, vocabulary::no_vocabulary_mut}; +use serde_json::{json, Value}; +use tracing::{error, instrument, trace}; use crate::{ - attributes::{Attribute, Attributes}, - prov::{ - operations::{ - ActivityExists, ActivityUses, ActsOnBehalfOf, AgentExists, ChronicleOperation, - CreateNamespace, DerivationType, EntityDerive, EntityExists, SetAttributes, - WasAssociatedWith, WasAttributedTo, WasGeneratedBy, WasInformedBy, - }, - vocab::{self, Chronicle, Prov}, - ActivityId, AgentId, DomaintypeId, EntityId, NamespaceId, Role, - }, + attributes::{Attribute, Attributes}, + prov::{ + ActivityId, + AgentId, + DomaintypeId, EntityId, NamespaceId, operations::{ + ActivityExists, ActivityUses, ActsOnBehalfOf, AgentExists, ChronicleOperation, + CreateNamespace, DerivationType, EntityDerive, EntityExists, SetAttributes, + WasAssociatedWith, WasAttributedTo, WasGeneratedBy, WasInformedBy, + }, Role, vocab::{self, Chronicle, Prov}, + }, }; - use crate::prov::{Activity, Agent, Entity, ProcessorError, ProvModel}; pub struct ContextLoader; impl Loader for ContextLoader { - type Error = (); - type Output = json_ld::syntax::Value; - - // This is only used to load the context, so we can just return it directly - fn load_with<'b>( - &'b mut self, - vocabulary: &'b mut (impl Sync + Send + IriVocabularyMut), - url: IriBuf, - ) -> BoxFuture, Self::Error>> - where - IriBuf: 'b, - { - use hashbrown::HashSet; - use std::str::FromStr; - let mut profiles = HashSet::new(); - profiles.insert(Profile::new(url.as_iri(), vocabulary)); - trace!("Loading context from {}", url); - async move { - let json = json!({ + type Error = (); + type Output = json_ld::syntax::Value; + + // This is only used to load the context, so we can just return it directly + fn load_with<'b>( + &'b mut self, + vocabulary: &'b mut (impl Sync + Send + IriVocabularyMut), + url: IriBuf, + ) -> BoxFuture, Self::Error>> + where + IriBuf: 'b, + { + use hashbrown::HashSet; + use std::str::FromStr; + let mut profiles = HashSet::new(); + profiles.insert(Profile::new(url.as_iri(), vocabulary)); + trace!("Loading context from {}", url); + async move { + let json = json!({ "@context": crate::context::PROV.clone() }); - let value = json_ld::syntax::Value::from_serde_json(json, |_| ()); - Ok(json_ld::RemoteDocument::new_full( - Some(url), - Some(Mime::from_str("application/json").unwrap()), - None, - profiles, - value, - )) - } - .boxed() - } + let value = json_ld::syntax::Value::from_serde_json(json, |_| ()); + Ok(json_ld::RemoteDocument::new_full( + Some(url), + Some(Mime::from_str("application/json").unwrap()), + None, + profiles, + value, + )) + } + .boxed() + } } fn as_json(node: &Node) -> serde_json::Value { - node.clone().into_json_meta_with((), no_vocabulary_mut()).into_value().into() + node.clone().into_json_meta_with((), no_vocabulary_mut()).into_value().into() } // Convert with coercion from our vocab iris, this is safe as sourced from constants fn id_from_iri_string>(iri: I) -> json_ld::Id { - json_ld::Id::Valid(json_ld::ValidId::Iri(IriBuf::try_from(iri.into().to_string()).unwrap())) + json_ld::Id::Valid(json_ld::ValidId::Iri(IriBuf::try_from(iri.into().to_string()).unwrap())) } fn extract_reference_ids>( - iri: I, - node: &Node, + iri: I, + node: &Node, ) -> Result, ProcessorError> { - let ids: Result, _> = node - .get(&id_from_iri_string(iri)) - .map(|o| o.id().ok_or_else(|| ProcessorError::MissingId { object: as_json(node) })) - .map(|id| { - id.and_then(|id| { - id.as_iri().ok_or_else(|| ProcessorError::MissingId { object: as_json(node) }) - }) - }) - .map(|id| id.map(|id| id.to_owned())) - .collect(); - - ids + let ids: Result, _> = node + .get(&id_from_iri_string(iri)) + .map(|o| o.id().ok_or_else(|| ProcessorError::MissingId { object: as_json(node) })) + .map(|id| { + id.and_then(|id| { + id.as_iri().ok_or_else(|| ProcessorError::MissingId { object: as_json(node) }) + }) + }) + .map(|id| id.map(|id| id.to_owned())) + .collect(); + + ids } fn extract_scalar_prop + Clone>( - iri: I, - node: &Node, + iri: I, + node: &Node, ) -> Result<&Indexed, ()>, ProcessorError> { - if let Some(object) = node.get_any(&id_from_iri_string(iri.clone())) { - Ok(object) - } else { - Err(ProcessorError::MissingProperty { iri: iri.into().to_string(), object: as_json(node) }) - } + if let Some(object) = node.get_any(&id_from_iri_string(iri.clone())) { + Ok(object) + } else { + Err(ProcessorError::MissingProperty { iri: iri.into().to_string(), object: as_json(node) }) + } } fn extract_namespace(agent: &Node) -> Result { - Ok(NamespaceId::try_from( - extract_scalar_prop(Chronicle::HasNamespace, agent)? - .id() - .ok_or(ProcessorError::MissingId { object: as_json(agent) })? - .to_string(), - )?) + Ok(NamespaceId::try_from( + extract_scalar_prop(Chronicle::HasNamespace, agent)? + .id() + .ok_or(ProcessorError::MissingId { object: as_json(agent) })? + .to_string(), + )?) } impl ProvModel { - pub async fn apply_json_ld_str(&mut self, buf: &str) -> Result<(), ProcessorError> { - self.apply_json_ld(serde_json::from_str(buf)?).await?; - - Ok(()) - } - - pub async fn apply_json_ld_bytes(&mut self, buf: &[u8]) -> Result<(), ProcessorError> { - self.apply_json_ld(serde_json::from_slice(buf)?).await?; - - Ok(()) - } - - /// Take a Json-Ld input document, assuming it is in compact form, expand it and apply the state - /// to the prov model Replace @context with our resource context - /// We rely on reified @types, so subclassing must also include supertypes - #[instrument(level = "trace", skip(self, json))] - pub async fn apply_json_ld(&mut self, json: serde_json::Value) -> Result<(), ProcessorError> { - if let serde_json::Value::Object(mut map) = json { - map.insert( - "@context".to_string(), - serde_json::Value::String("http://chronicle.works/chr/1.0/c.jsonld".to_string()), - ); - let json = serde_json::Value::Object(map); - - trace!(to_apply_compact=%serde_json::to_string_pretty(&json)?); - - use json_ld::Expand; - let output = json_ld::syntax::Value::from_serde_json(json.clone(), |_| ()) - .expand(&mut ContextLoader) - .await - .map_err(|e| ProcessorError::Expansion { inner: format!("{e:?}") })?; - - for o in output.into_value().into_objects() { - let o = - o.value().inner().as_node().ok_or(ProcessorError::NotANode(json.clone()))?; - - if o.has_type(&id_from_iri_string(Chronicle::Namespace)) { - self.apply_node_as_namespace(o)?; - } - if o.has_type(&id_from_iri_string(Prov::Agent)) { - self.apply_node_as_agent(o)?; - } else if o.has_type(&id_from_iri_string(Prov::Activity)) { - self.apply_node_as_activity(o)?; - } else if o.has_type(&id_from_iri_string(Prov::Entity)) { - self.apply_node_as_entity(o)?; - } else if o.has_type(&id_from_iri_string(Prov::Delegation)) { - self.apply_node_as_delegation(o)?; - } else if o.has_type(&id_from_iri_string(Prov::Association)) { - self.apply_node_as_association(o)?; - } else if o.has_type(&id_from_iri_string(Prov::Attribution)) { - self.apply_node_as_attribution(o)?; - } - } - Ok(()) - } else { - Err(ProcessorError::NotAnObject) - } - } - - /// Extract the types and find the first that is not prov::, as we currently only alow zero or - /// one domain types this should be sufficient - fn extract_attributes( - node: &Node, - ) -> Result { - let typ = node - .types() - .iter() - .filter_map(|x| x.as_iri()) - .find(|x| x.as_str().contains("domaintype")) - .map(|iri| Ok::<_, ProcessorError>(DomaintypeId::try_from(iri.to_string())?)) - .transpose(); - - if let serde_json::Value::Object(map) = as_json(node) { - if let Some(serde_json::Value::Array(array)) = map.get(Chronicle::Value.as_str()) { - if array.len() == 1 { - let o = array.first().unwrap(); - let serde_object = &o["@value"]; - - if let serde_json::Value::Object(object) = serde_object { - let attributes = object - .into_iter() - .map(|(typ, value)| Attribute::new(typ, value.clone())) - .collect(); - - return Ok(Attributes::new(typ?, attributes)); - } - } - } - } - - Err(ProcessorError::NotAnObject) - } - - fn apply_node_as_namespace( - &mut self, - ns: &Node, - ) -> Result<(), ProcessorError> { - let ns = ns.id().ok_or_else(|| ProcessorError::MissingId { object: as_json(ns) })?; - - self.namespace_context(&NamespaceId::try_from(ns.to_string())?); - - Ok(()) - } - - fn apply_node_as_delegation( - &mut self, - delegation: &Node, - ) -> Result<(), ProcessorError> { - let namespace_id = extract_namespace(delegation)?; - - let role = extract_scalar_prop(Prov::HadRole, delegation) - .ok() - .and_then(|x| x.as_str().map(Role::from)); - - let responsible_id = extract_reference_ids(Prov::ActedOnBehalfOf, delegation)? - .into_iter() - .next() - .ok_or_else(|| ProcessorError::MissingProperty { - object: as_json(delegation), - iri: Prov::ActedOnBehalfOf.to_string(), - }) - .and_then(|x| Ok(AgentId::try_from(x.to_string())?))?; - - let delegate_id = extract_reference_ids(Prov::Delegate, delegation)? - .into_iter() - .next() - .ok_or_else(|| ProcessorError::MissingProperty { - object: as_json(delegation), - iri: Prov::Delegate.to_string(), - }) - .and_then(|x| Ok(AgentId::try_from(x.to_string())?))?; - - let activity_id = extract_reference_ids(Prov::HadActivity, delegation)? - .into_iter() - .next() - .map(|x| ActivityId::try_from(x.to_string())) - .transpose()?; - - self.qualified_delegation(&namespace_id, &responsible_id, &delegate_id, activity_id, role); - Ok(()) - } - - fn apply_node_as_association( - &mut self, - association: &Node, - ) -> Result<(), ProcessorError> { - let namespace_id = extract_namespace(association)?; - - let role = extract_scalar_prop(Prov::HadRole, association) - .ok() - .and_then(|x| x.as_str().map(Role::from)); - - let agent_id = extract_reference_ids(Prov::Responsible, association)? - .into_iter() - .next() - .ok_or_else(|| ProcessorError::MissingProperty { - object: as_json(association), - iri: Prov::Responsible.to_string(), - }) - .and_then(|x| Ok(AgentId::try_from(x.to_string())?))?; - - let activity_id = extract_reference_ids(Prov::HadActivity, association)? - .into_iter() - .next() - .ok_or_else(|| ProcessorError::MissingProperty { - object: as_json(association), - iri: Prov::HadActivity.to_string(), - }) - .and_then(|x| Ok(ActivityId::try_from(x.to_string())?))?; - - self.qualified_association(&namespace_id, &activity_id, &agent_id, role); - - Ok(()) - } - - fn apply_node_as_attribution( - &mut self, - attribution: &Node, - ) -> Result<(), ProcessorError> { - let namespace_id = extract_namespace(attribution)?; - - let role = extract_scalar_prop(Prov::HadRole, attribution) - .ok() - .and_then(|x| x.as_str().map(Role::from)); - - let agent_id = extract_reference_ids(Prov::Responsible, attribution)? - .into_iter() - .next() - .ok_or_else(|| ProcessorError::MissingProperty { - object: as_json(attribution), - iri: Prov::Responsible.to_string(), - }) - .and_then(|x| Ok(AgentId::try_from(x.to_string())?))?; - - let entity_id = extract_reference_ids(Prov::HadEntity, attribution)? - .into_iter() - .next() - .ok_or_else(|| ProcessorError::MissingProperty { - object: as_json(attribution), - iri: Prov::HadEntity.to_string(), - }) - .and_then(|x| Ok(EntityId::try_from(x.to_string())?))?; - - self.qualified_attribution(&namespace_id, &entity_id, &agent_id, role); - - Ok(()) - } - - fn apply_node_as_agent( - &mut self, - agent: &Node, - ) -> Result<(), ProcessorError> { - let id = AgentId::try_from( - agent - .id() - .ok_or_else(|| ProcessorError::MissingId { object: as_json(agent) })? - .to_string(), - )?; - - let namespaceid = extract_namespace(agent)?; - - let attributes = Self::extract_attributes(agent)?; - - let agent = Agent::exists(namespaceid, id).has_attributes(attributes); - - self.add_agent(agent); - - Ok(()) - } - - fn apply_node_as_activity( - &mut self, - activity: &Node, - ) -> Result<(), ProcessorError> { - let id = ActivityId::try_from( - activity - .id() - .ok_or_else(|| ProcessorError::MissingId { object: as_json(activity) })? - .to_string(), - )?; - - let namespaceid = extract_namespace(activity)?; - - let started = extract_scalar_prop(Prov::StartedAtTime, activity) - .ok() - .and_then(|x| x.as_str().map(DateTime::parse_from_rfc3339)); - - let ended = extract_scalar_prop(Prov::EndedAtTime, activity) - .ok() - .and_then(|x| x.as_str().map(DateTime::parse_from_rfc3339)); - - let used = extract_reference_ids(Prov::Used, activity)? - .into_iter() - .map(|id| EntityId::try_from(id.to_string())) - .collect::, _>>()?; - - let was_informed_by = extract_reference_ids(Prov::WasInformedBy, activity)? - .into_iter() - .map(|id| ActivityId::try_from(id.to_string())) - .collect::, _>>()?; - - let attributes = Self::extract_attributes(activity)?; - - let mut activity = Activity::exists(namespaceid.clone(), id).has_attributes(attributes); - - if let Some(started) = started { - activity.started = Some(DateTime::::from(started?).into()); - } - - if let Some(ended) = ended { - activity.ended = Some(DateTime::::from(ended?).into()); - } - - for entity in used { - self.used(namespaceid.clone(), &activity.id, &entity); - } - - for informing_activity in was_informed_by { - self.was_informed_by(namespaceid.clone(), &activity.id, &informing_activity); - } - - self.add_activity(activity); - - Ok(()) - } - - fn apply_node_as_entity( - &mut self, - entity: &Node, - ) -> Result<(), ProcessorError> { - let id = EntityId::try_from( - entity - .id() - .ok_or_else(|| ProcessorError::MissingId { object: as_json(entity) })? - .to_string(), - )?; - - let namespaceid = extract_namespace(entity)?; - - let generatedby = extract_reference_ids(Prov::WasGeneratedBy, entity)? - .into_iter() - .map(|id| ActivityId::try_from(id.to_string())) - .collect::, _>>()?; - - for derived in extract_reference_ids(Prov::WasDerivedFrom, entity)? - .into_iter() - .map(|id| EntityId::try_from(id.to_string())) - { - self.was_derived_from( - namespaceid.clone(), - DerivationType::None, - derived?, - id.clone(), - None, - ); - } - - for derived in extract_reference_ids(Prov::WasQuotedFrom, entity)? - .into_iter() - .map(|id| EntityId::try_from(id.to_string())) - { - self.was_derived_from( - namespaceid.clone(), - DerivationType::quotation(), - derived?, - id.clone(), - None, - ); - } - - for derived in extract_reference_ids(Prov::WasRevisionOf, entity)? - .into_iter() - .map(|id| EntityId::try_from(id.to_string())) - { - self.was_derived_from( - namespaceid.clone(), - DerivationType::revision(), - derived?, - id.clone(), - None, - ); - } - - for derived in extract_reference_ids(Prov::HadPrimarySource, entity)? - .into_iter() - .map(|id| EntityId::try_from(id.to_string())) - { - self.was_derived_from( - namespaceid.clone(), - DerivationType::primary_source(), - derived?, - id.clone(), - None, - ); - } - - for activity in generatedby { - self.was_generated_by(namespaceid.clone(), &id, &activity); - } - - let attributes = Self::extract_attributes(entity)?; - self.add_entity(Entity::exists(namespaceid, id).has_attributes(attributes)); - - Ok(()) - } + pub async fn apply_json_ld_str(&mut self, buf: &str) -> Result<(), ProcessorError> { + self.apply_json_ld(serde_json::from_str(buf)?).await?; + + Ok(()) + } + + pub async fn apply_json_ld_bytes(&mut self, buf: &[u8]) -> Result<(), ProcessorError> { + self.apply_json_ld(serde_json::from_slice(buf)?).await?; + + Ok(()) + } + + /// Take a Json-Ld input document, assuming it is in compact form, expand it and apply the state + /// to the prov model Replace @context with our resource context + /// We rely on reified @types, so subclassing must also include supertypes + #[instrument(level = "trace", skip(self, json))] + pub async fn apply_json_ld(&mut self, json: serde_json::Value) -> Result<(), ProcessorError> { + if let serde_json::Value::Object(mut map) = json { + map.insert( + "@context".to_string(), + serde_json::Value::String("http://chronicle.works/chr/1.0/c.jsonld".to_string()), + ); + let json = serde_json::Value::Object(map); + + trace!(to_apply_compact=%serde_json::to_string_pretty(&json)?); + + use json_ld::Expand; + let output = json_ld::syntax::Value::from_serde_json(json.clone(), |_| ()) + .expand(&mut ContextLoader) + .await + .map_err(|e| ProcessorError::Expansion { inner: format!("{e:?}") })?; + + for o in output.into_value().into_objects() { + let o = + o.value().inner().as_node().ok_or(ProcessorError::NotANode(json.clone()))?; + + if o.has_type(&id_from_iri_string(Chronicle::Namespace)) { + self.apply_node_as_namespace(o)?; + } + if o.has_type(&id_from_iri_string(Prov::Agent)) { + self.apply_node_as_agent(o)?; + } else if o.has_type(&id_from_iri_string(Prov::Activity)) { + self.apply_node_as_activity(o)?; + } else if o.has_type(&id_from_iri_string(Prov::Entity)) { + self.apply_node_as_entity(o)?; + } else if o.has_type(&id_from_iri_string(Prov::Delegation)) { + self.apply_node_as_delegation(o)?; + } else if o.has_type(&id_from_iri_string(Prov::Association)) { + self.apply_node_as_association(o)?; + } else if o.has_type(&id_from_iri_string(Prov::Attribution)) { + self.apply_node_as_attribution(o)?; + } + } + Ok(()) + } else { + Err(ProcessorError::NotAnObject) + } + } + + /// Extract the types and find the first that is not prov::, as we currently only alow zero or + /// one domain types this should be sufficient + fn extract_attributes( + node: &Node, + ) -> Result { + let typ = node + .types() + .iter() + .filter_map(|x| x.as_iri()) + .find(|x| x.as_str().contains("domaintype")) + .map(|iri| Ok::<_, ProcessorError>(DomaintypeId::try_from(iri.to_string())?)) + .transpose(); + + if let serde_json::Value::Object(map) = as_json(node) { + if let Some(serde_json::Value::Array(array)) = map.get(Chronicle::Value.as_str()) { + if array.len() == 1 { + let o = array.first().unwrap(); + let serde_object = &o["@value"]; + + if let serde_json::Value::Object(object) = serde_object { + let attributes = object + .into_iter() + .map(|(typ, value)| Attribute::new(typ, value.clone())) + .collect(); + + return Ok(Attributes::new(typ?, attributes)); + } + } + } + } + + Err(ProcessorError::NotAnObject) + } + + fn apply_node_as_namespace( + &mut self, + ns: &Node, + ) -> Result<(), ProcessorError> { + let ns = ns.id().ok_or_else(|| ProcessorError::MissingId { object: as_json(ns) })?; + + self.namespace_context(&NamespaceId::try_from(ns.to_string())?); + + Ok(()) + } + + fn apply_node_as_delegation( + &mut self, + delegation: &Node, + ) -> Result<(), ProcessorError> { + let namespace_id = extract_namespace(delegation)?; + + let role = extract_scalar_prop(Prov::HadRole, delegation) + .ok() + .and_then(|x| x.as_str().map(Role::from)); + + let responsible_id = extract_reference_ids(Prov::ActedOnBehalfOf, delegation)? + .into_iter() + .next() + .ok_or_else(|| ProcessorError::MissingProperty { + object: as_json(delegation), + iri: Prov::ActedOnBehalfOf.to_string(), + }) + .and_then(|x| Ok(AgentId::try_from(x.to_string())?))?; + + let delegate_id = extract_reference_ids(Prov::Delegate, delegation)? + .into_iter() + .next() + .ok_or_else(|| ProcessorError::MissingProperty { + object: as_json(delegation), + iri: Prov::Delegate.to_string(), + }) + .and_then(|x| Ok(AgentId::try_from(x.to_string())?))?; + + let activity_id = extract_reference_ids(Prov::HadActivity, delegation)? + .into_iter() + .next() + .map(|x| ActivityId::try_from(x.to_string())) + .transpose()?; + + self.qualified_delegation(&namespace_id, &responsible_id, &delegate_id, activity_id, role); + Ok(()) + } + + fn apply_node_as_association( + &mut self, + association: &Node, + ) -> Result<(), ProcessorError> { + let namespace_id = extract_namespace(association)?; + + let role = extract_scalar_prop(Prov::HadRole, association) + .ok() + .and_then(|x| x.as_str().map(Role::from)); + + let agent_id = extract_reference_ids(Prov::Responsible, association)? + .into_iter() + .next() + .ok_or_else(|| ProcessorError::MissingProperty { + object: as_json(association), + iri: Prov::Responsible.to_string(), + }) + .and_then(|x| Ok(AgentId::try_from(x.to_string())?))?; + + let activity_id = extract_reference_ids(Prov::HadActivity, association)? + .into_iter() + .next() + .ok_or_else(|| ProcessorError::MissingProperty { + object: as_json(association), + iri: Prov::HadActivity.to_string(), + }) + .and_then(|x| Ok(ActivityId::try_from(x.to_string())?))?; + + self.qualified_association(&namespace_id, &activity_id, &agent_id, role); + + Ok(()) + } + + fn apply_node_as_attribution( + &mut self, + attribution: &Node, + ) -> Result<(), ProcessorError> { + let namespace_id = extract_namespace(attribution)?; + + let role = extract_scalar_prop(Prov::HadRole, attribution) + .ok() + .and_then(|x| x.as_str().map(Role::from)); + + let agent_id = extract_reference_ids(Prov::Responsible, attribution)? + .into_iter() + .next() + .ok_or_else(|| ProcessorError::MissingProperty { + object: as_json(attribution), + iri: Prov::Responsible.to_string(), + }) + .and_then(|x| Ok(AgentId::try_from(x.to_string())?))?; + + let entity_id = extract_reference_ids(Prov::HadEntity, attribution)? + .into_iter() + .next() + .ok_or_else(|| ProcessorError::MissingProperty { + object: as_json(attribution), + iri: Prov::HadEntity.to_string(), + }) + .and_then(|x| Ok(EntityId::try_from(x.to_string())?))?; + + self.qualified_attribution(&namespace_id, &entity_id, &agent_id, role); + + Ok(()) + } + + fn apply_node_as_agent( + &mut self, + agent: &Node, + ) -> Result<(), ProcessorError> { + let id = AgentId::try_from( + agent + .id() + .ok_or_else(|| ProcessorError::MissingId { object: as_json(agent) })? + .to_string(), + )?; + + let namespaceid = extract_namespace(agent)?; + + let attributes = Self::extract_attributes(agent)?; + + let agent = Agent::exists(namespaceid, id).has_attributes(attributes); + + self.add_agent(agent); + + Ok(()) + } + + fn apply_node_as_activity( + &mut self, + activity: &Node, + ) -> Result<(), ProcessorError> { + let id = ActivityId::try_from( + activity + .id() + .ok_or_else(|| ProcessorError::MissingId { object: as_json(activity) })? + .to_string(), + )?; + + let namespaceid = extract_namespace(activity)?; + + let started = extract_scalar_prop(Prov::StartedAtTime, activity) + .ok() + .and_then(|x| x.as_str().map(DateTime::parse_from_rfc3339)); + + let ended = extract_scalar_prop(Prov::EndedAtTime, activity) + .ok() + .and_then(|x| x.as_str().map(DateTime::parse_from_rfc3339)); + + let used = extract_reference_ids(Prov::Used, activity)? + .into_iter() + .map(|id| EntityId::try_from(id.to_string())) + .collect::, _>>()?; + + let was_informed_by = extract_reference_ids(Prov::WasInformedBy, activity)? + .into_iter() + .map(|id| ActivityId::try_from(id.to_string())) + .collect::, _>>()?; + + let attributes = Self::extract_attributes(activity)?; + + let mut activity = Activity::exists(namespaceid.clone(), id).has_attributes(attributes); + + if let Some(started) = started { + activity.started = Some(DateTime::::from(started?).into()); + } + + if let Some(ended) = ended { + activity.ended = Some(DateTime::::from(ended?).into()); + } + + for entity in used { + self.used(namespaceid.clone(), &activity.id, &entity); + } + + for informing_activity in was_informed_by { + self.was_informed_by(namespaceid.clone(), &activity.id, &informing_activity); + } + + self.add_activity(activity); + + Ok(()) + } + + fn apply_node_as_entity( + &mut self, + entity: &Node, + ) -> Result<(), ProcessorError> { + let id = EntityId::try_from( + entity + .id() + .ok_or_else(|| ProcessorError::MissingId { object: as_json(entity) })? + .to_string(), + )?; + + let namespaceid = extract_namespace(entity)?; + + let generatedby = extract_reference_ids(Prov::WasGeneratedBy, entity)? + .into_iter() + .map(|id| ActivityId::try_from(id.to_string())) + .collect::, _>>()?; + + for derived in extract_reference_ids(Prov::WasDerivedFrom, entity)? + .into_iter() + .map(|id| EntityId::try_from(id.to_string())) + { + self.was_derived_from( + namespaceid.clone(), + DerivationType::None, + derived?, + id.clone(), + None, + ); + } + + for derived in extract_reference_ids(Prov::WasQuotedFrom, entity)? + .into_iter() + .map(|id| EntityId::try_from(id.to_string())) + { + self.was_derived_from( + namespaceid.clone(), + DerivationType::quotation(), + derived?, + id.clone(), + None, + ); + } + + for derived in extract_reference_ids(Prov::WasRevisionOf, entity)? + .into_iter() + .map(|id| EntityId::try_from(id.to_string())) + { + self.was_derived_from( + namespaceid.clone(), + DerivationType::revision(), + derived?, + id.clone(), + None, + ); + } + + for derived in extract_reference_ids(Prov::HadPrimarySource, entity)? + .into_iter() + .map(|id| EntityId::try_from(id.to_string())) + { + self.was_derived_from( + namespaceid.clone(), + DerivationType::primary_source(), + derived?, + id.clone(), + None, + ); + } + + for activity in generatedby { + self.was_generated_by(namespaceid.clone(), &id, &activity); + } + + let attributes = Self::extract_attributes(entity)?; + self.add_entity(Entity::exists(namespaceid, id).has_attributes(attributes)); + + Ok(()) + } } + trait Operation { - fn namespace(&self) -> Option; - fn agent(&self) -> Option; - fn delegate(&self) -> Option; - fn responsible(&self) -> Option; - - fn activity(&self) -> Option; - fn optional_role(&self) -> Option; - fn start_time(&self) -> Option; - fn locator(&self) -> Option; - fn end_time(&self) -> Option; - fn entity(&self) -> Option; - fn used_entity(&self) -> Option; - fn derivation(&self) -> DerivationType; - fn domain(&self) -> Option; - fn attributes(&self) -> Vec; - fn informing_activity(&self) -> Option; + fn namespace(&self) -> Option; + fn agent(&self) -> Option; + fn delegate(&self) -> Option; + fn responsible(&self) -> Option; + + fn activity(&self) -> Option; + fn optional_role(&self) -> Option; + fn start_time(&self) -> Option; + fn locator(&self) -> Option; + fn end_time(&self) -> Option; + fn entity(&self) -> Option; + fn used_entity(&self) -> Option; + fn derivation(&self) -> DerivationType; + fn domain(&self) -> Option; + fn attributes(&self) -> Vec; + fn informing_activity(&self) -> Option; } impl Operation for Node { - fn namespace(&self) -> Option { - let mut uuid_objects = - self.get(&id_from_iri_string(vocab::ChronicleOperation::NamespaceUuid)); - let uuid = uuid_objects.next()?.as_str()?; - let mut name_objects = - self.get(&id_from_iri_string(vocab::ChronicleOperation::NamespaceName)); - let external_id = name_objects.next()?.as_str()?; - let uuid = uuid::Uuid::parse_str(uuid).ok()?; - Some(NamespaceId::from_external_id(external_id, uuid)) - } - - fn agent(&self) -> Option { - let mut name_objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::AgentName)); - let external_id = name_objects.next()?.as_str()?; - Some(AgentId::from_external_id(external_id)) - } - - fn delegate(&self) -> Option { - let mut name_objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::DelegateId)); - let external_id = name_objects.next()?.as_str()?; - Some(AgentId::from_external_id(external_id)) - } - - fn start_time(&self) -> Option { - let mut objects = - self.get(&id_from_iri_string(vocab::ChronicleOperation::StartActivityTime)); - let time = objects.next()?.as_str()?; - Some(time.to_owned()) - } - - fn end_time(&self) -> Option { - let mut objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::EndActivityTime)); - let time = objects.next()?.as_str()?; - Some(time.to_owned()) - } - - fn entity(&self) -> Option { - let mut name_objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::EntityName)); - let external_id = name_objects.next()?.as_str()?; - Some(EntityId::from_external_id(external_id)) - } - - fn used_entity(&self) -> Option { - let mut name_objects = - self.get(&id_from_iri_string(vocab::ChronicleOperation::UsedEntityName)); - let external_id = name_objects.next()?.as_str()?; - Some(EntityId::from_external_id(external_id)) - } - - fn derivation(&self) -> DerivationType { - let mut objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::DerivationType)); - if let Some(object) = objects.next() { - if let Some(derivation) = object.as_str() { - return match derivation { - "Revision" => DerivationType::Revision, - "Quotation" => DerivationType::Quotation, - "PrimarySource" => DerivationType::PrimarySource, - _ => DerivationType::None, - }; - } - } - DerivationType::None - } - - fn domain(&self) -> Option { - let mut objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::DomaintypeId)); - let d = objects.next()?.as_str()?; - Some(DomaintypeId::from_external_id(d)) - } - - fn attributes(&self) -> Vec { - self.get(&id_from_iri_string(vocab::ChronicleOperation::Attributes)) - .filter_map(|o| { - let serde_object = - if let Some(json_ld::object::Value::Json(Meta(json, _))) = o.as_value() { - Some(json.clone().into()) - } else { - serde_json::from_str(&as_json(o.as_node()?)["@value"].to_string()).ok() - }; - - serde_object.and_then(|obj: serde_json::Value| { - if let serde_json::Value::Object(object) = obj { - Some( - object - .into_iter() - .map(|(typ, value)| Attribute { typ, value: value.into() }) - .collect::>(), - ) - } else { - None - } - }) - }) - .flatten() - .collect() - } - - fn responsible(&self) -> Option { - let mut name_objects = - self.get(&id_from_iri_string(vocab::ChronicleOperation::ResponsibleId)); - let external_id = name_objects.next()?.as_str()?; - Some(AgentId::from_external_id(external_id)) - } - - fn optional_role(&self) -> Option { - let mut name_objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::Role)); - let object = name_objects.next()?; - Some(Role::from(object.as_str()?)) - } - - fn activity(&self) -> Option { - let mut name_objects = - self.get(&id_from_iri_string(vocab::ChronicleOperation::ActivityName)); - let external_id = name_objects.next()?.as_str()?; - Some(ActivityId::from_external_id(external_id)) - } - - fn locator(&self) -> Option { - let mut objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::Locator)); - let locator = objects.next()?; - Some(locator.as_str()?.to_owned()) - } - - fn informing_activity(&self) -> Option { - let mut name_objects = - self.get(&id_from_iri_string(vocab::ChronicleOperation::InformingActivityName)); - let external_id = name_objects.next()?.as_str()?; - Some(ActivityId::from_external_id(external_id)) - } + fn namespace(&self) -> Option { + let mut uuid_objects = + self.get(&id_from_iri_string(vocab::ChronicleOperation::NamespaceUuid)); + let uuid = uuid_objects.next()?.as_str()?; + let mut name_objects = + self.get(&id_from_iri_string(vocab::ChronicleOperation::NamespaceName)); + let external_id = name_objects.next()?.as_str()?; + let uuid = uuid::Uuid::parse_str(uuid).ok()?; + Some(NamespaceId::from_external_id(external_id, uuid)) + } + + fn agent(&self) -> Option { + let mut name_objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::AgentName)); + let external_id = name_objects.next()?.as_str()?; + Some(AgentId::from_external_id(external_id)) + } + + fn delegate(&self) -> Option { + let mut name_objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::DelegateId)); + let external_id = name_objects.next()?.as_str()?; + Some(AgentId::from_external_id(external_id)) + } + + fn start_time(&self) -> Option { + let mut objects = + self.get(&id_from_iri_string(vocab::ChronicleOperation::StartActivityTime)); + let time = objects.next()?.as_str()?; + Some(time.to_owned()) + } + + fn end_time(&self) -> Option { + let mut objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::EndActivityTime)); + let time = objects.next()?.as_str()?; + Some(time.to_owned()) + } + + fn entity(&self) -> Option { + let mut name_objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::EntityName)); + let external_id = name_objects.next()?.as_str()?; + Some(EntityId::from_external_id(external_id)) + } + + fn used_entity(&self) -> Option { + let mut name_objects = + self.get(&id_from_iri_string(vocab::ChronicleOperation::UsedEntityName)); + let external_id = name_objects.next()?.as_str()?; + Some(EntityId::from_external_id(external_id)) + } + + fn derivation(&self) -> DerivationType { + let mut objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::DerivationType)); + if let Some(object) = objects.next() { + if let Some(derivation) = object.as_str() { + return match derivation { + "Revision" => DerivationType::Revision, + "Quotation" => DerivationType::Quotation, + "PrimarySource" => DerivationType::PrimarySource, + _ => DerivationType::None, + }; + } + } + DerivationType::None + } + + fn domain(&self) -> Option { + let mut objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::DomaintypeId)); + let d = objects.next()?.as_str()?; + Some(DomaintypeId::from_external_id(d)) + } + + fn attributes(&self) -> Vec { + self.get(&id_from_iri_string(vocab::ChronicleOperation::Attributes)) + .filter_map(|o| { + let serde_object = + if let Some(json_ld::object::Value::Json(Meta(json, _))) = o.as_value() { + Some(json.clone().into()) + } else { + serde_json::from_str(&as_json(o.as_node()?)["@value"].to_string()).ok() + }; + + serde_object.and_then(|obj: serde_json::Value| { + if let serde_json::Value::Object(object) = obj { + Some( + object + .into_iter() + .map(|(typ, value)| Attribute { typ, value: value.into() }) + .collect::>(), + ) + } else { + None + } + }) + }) + .flatten() + .collect() + } + + fn responsible(&self) -> Option { + let mut name_objects = + self.get(&id_from_iri_string(vocab::ChronicleOperation::ResponsibleId)); + let external_id = name_objects.next()?.as_str()?; + Some(AgentId::from_external_id(external_id)) + } + + fn optional_role(&self) -> Option { + let mut name_objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::Role)); + let object = name_objects.next()?; + Some(Role::from(object.as_str()?)) + } + + fn activity(&self) -> Option { + let mut name_objects = + self.get(&id_from_iri_string(vocab::ChronicleOperation::ActivityName)); + let external_id = name_objects.next()?.as_str()?; + Some(ActivityId::from_external_id(external_id)) + } + + fn locator(&self) -> Option { + let mut objects = self.get(&id_from_iri_string(vocab::ChronicleOperation::Locator)); + let locator = objects.next()?; + Some(locator.as_str()?.to_owned()) + } + + fn informing_activity(&self) -> Option { + let mut name_objects = + self.get(&id_from_iri_string(vocab::ChronicleOperation::InformingActivityName)); + let external_id = name_objects.next()?.as_str()?; + Some(ActivityId::from_external_id(external_id)) + } } impl ChronicleOperation { - pub async fn from_json(json: &Value) -> Result { - use json_ld::Expand; - - let mut output = json_ld::syntax::Value::from_serde_json(json.clone(), |_| ()) - .expand(&mut ContextLoader) - .await - .map_err(|e| ProcessorError::Expansion { inner: format!("{e:?}") })?; - - output.canonicalize(); - if let Some(object) = output.into_value().into_objects().into_iter().next() { - let o = - object.value().inner().as_node().ok_or(ProcessorError::NotANode(json.clone()))?; - if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::CreateNamespace)) { - let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; - Ok(ChronicleOperation::CreateNamespace(CreateNamespace { id: namespace })) - } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::AgentExists)) { - let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; - let agent_id = o.agent().ok_or(ProcessorError::MissingAgent)?; - Ok(ChronicleOperation::AgentExists(AgentExists { namespace, id: agent_id })) - } else if o - .has_type(&id_from_iri_string(vocab::ChronicleOperation::AgentActsOnBehalfOf)) - { - let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; - let delegate_id = o.delegate().ok_or(ProcessorError::MissingAgent)?; - let responsible_id = o.responsible().ok_or(ProcessorError::MissingAgent)?; - let activity_id = o.activity(); - - Ok(ChronicleOperation::AgentActsOnBehalfOf(ActsOnBehalfOf::new( - namespace, - responsible_id, - delegate_id, - activity_id, - o.optional_role(), - ))) - } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::ActivityExists)) { - let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; - let activity_id = o.activity().ok_or(ProcessorError::MissingActivity)?; - Ok(ChronicleOperation::ActivityExists(ActivityExists { - namespace, - id: activity_id, - })) - } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::StartActivity)) { - let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; - let id = o.activity().ok_or(ProcessorError::MissingActivity)?; - let time_str = o.start_time().ok_or(ProcessorError::MissingTime)?; - match time_str.parse::>() { - Ok(time) => Ok(ChronicleOperation::start_activity(namespace, id, time)), - Err(e) => Err(ProcessorError::Time(e)), - } - } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::EndActivity)) { - let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; - let id = o.activity().ok_or(ProcessorError::MissingActivity)?; - let time_str = o.end_time().ok_or(ProcessorError::MissingTime)?; - match time_str.parse::>() { - Ok(time) => Ok(ChronicleOperation::end_activity(namespace, id, time)), - Err(e) => Err(ProcessorError::Time(e)), - } - } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::ActivityUses)) { - let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; - let id = o.entity().ok_or(ProcessorError::MissingEntity)?; - let activity = o.activity().ok_or(ProcessorError::MissingActivity)?; - Ok(ChronicleOperation::ActivityUses(ActivityUses { namespace, id, activity })) - } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::EntityExists)) { - let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; - let entity_id = o.entity().ok_or(ProcessorError::MissingEntity)?; - Ok(ChronicleOperation::EntityExists(EntityExists { namespace, id: entity_id })) - } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::WasGeneratedBy)) { - let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; - let id = o.entity().ok_or(ProcessorError::MissingEntity)?; - let activity = o.activity().ok_or(ProcessorError::MissingActivity)?; - Ok(ChronicleOperation::WasGeneratedBy(WasGeneratedBy { namespace, id, activity })) - } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::EntityDerive)) { - let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; - let id = o.entity().ok_or(ProcessorError::MissingEntity)?; - let used_id = o.used_entity().ok_or(ProcessorError::MissingEntity)?; - let activity_id = o.activity(); - let typ = o.derivation(); - Ok(ChronicleOperation::EntityDerive(EntityDerive { - namespace, - id, - used_id, - activity_id, - typ, - })) - } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::SetAttributes)) { - let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; - let domain = o.domain(); - let attrs = o.attributes(); - - let attributes = Attributes::new(domain, attrs); - let actor: SetAttributes = { - if o.has_key(&Term::Id(id_from_iri_string( - vocab::ChronicleOperation::EntityName, - ))) { - let id = o.entity().ok_or(ProcessorError::MissingEntity)?; - SetAttributes::Entity { namespace, id, attributes } - } else if o.has_key(&Term::Id(id_from_iri_string( - vocab::ChronicleOperation::AgentName, - ))) { - let id = o.agent().ok_or(ProcessorError::MissingAgent)?; - SetAttributes::Agent { namespace, id, attributes } - } else { - let id = o.activity().ok_or(ProcessorError::MissingActivity)?; - SetAttributes::Activity { namespace, id, attributes } - } - }; - - Ok(ChronicleOperation::SetAttributes(actor)) - } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::WasAssociatedWith)) - { - Ok(ChronicleOperation::WasAssociatedWith(WasAssociatedWith::new( - o.namespace().ok_or(ProcessorError::MissingNamespace)?, - o.activity().ok_or(ProcessorError::MissingActivity)?, - o.agent().ok_or(ProcessorError::MissingAgent)?, - o.optional_role(), - ))) - } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::WasAttributedTo)) { - Ok(ChronicleOperation::WasAttributedTo(WasAttributedTo::new( - o.namespace().ok_or(ProcessorError::MissingNamespace)?, - o.entity().ok_or(ProcessorError::MissingEntity)?, - o.agent().ok_or(ProcessorError::MissingAgent)?, - o.optional_role(), - ))) - } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::WasInformedBy)) { - let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; - let activity = o.activity().ok_or(ProcessorError::MissingActivity)?; - let informing_activity = - o.informing_activity().ok_or(ProcessorError::MissingActivity)?; - Ok(ChronicleOperation::WasInformedBy(WasInformedBy { - namespace, - activity, - informing_activity, - })) - } else { - error!( + pub async fn from_json(json: &Value) -> Result { + use json_ld::Expand; + + let mut output = json_ld::syntax::Value::from_serde_json(json.clone(), |_| ()) + .expand(&mut ContextLoader) + .await + .map_err(|e| ProcessorError::Expansion { inner: format!("{e:?}") })?; + + output.canonicalize(); + if let Some(object) = output.into_value().into_objects().into_iter().next() { + let o = + object.value().inner().as_node().ok_or(ProcessorError::NotANode(json.clone()))?; + if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::CreateNamespace)) { + let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; + Ok(ChronicleOperation::CreateNamespace(CreateNamespace { id: namespace })) + } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::AgentExists)) { + let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; + let agent_id = o.agent().ok_or(ProcessorError::MissingAgent)?; + Ok(ChronicleOperation::AgentExists(AgentExists { namespace, id: agent_id })) + } else if o + .has_type(&id_from_iri_string(vocab::ChronicleOperation::AgentActsOnBehalfOf)) + { + let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; + let delegate_id = o.delegate().ok_or(ProcessorError::MissingAgent)?; + let responsible_id = o.responsible().ok_or(ProcessorError::MissingAgent)?; + let activity_id = o.activity(); + + Ok(ChronicleOperation::AgentActsOnBehalfOf(ActsOnBehalfOf::new( + namespace, + responsible_id, + delegate_id, + activity_id, + o.optional_role(), + ))) + } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::ActivityExists)) { + let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; + let activity_id = o.activity().ok_or(ProcessorError::MissingActivity)?; + Ok(ChronicleOperation::ActivityExists(ActivityExists { + namespace, + id: activity_id, + })) + } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::StartActivity)) { + let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; + let id = o.activity().ok_or(ProcessorError::MissingActivity)?; + let time_str = o.start_time().ok_or(ProcessorError::MissingTime)?; + match time_str.parse::>() { + Ok(time) => Ok(ChronicleOperation::start_activity(namespace, id, time)), + Err(e) => Err(ProcessorError::Time(e)), + } + } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::EndActivity)) { + let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; + let id = o.activity().ok_or(ProcessorError::MissingActivity)?; + let time_str = o.end_time().ok_or(ProcessorError::MissingTime)?; + match time_str.parse::>() { + Ok(time) => Ok(ChronicleOperation::end_activity(namespace, id, time)), + Err(e) => Err(ProcessorError::Time(e)), + } + } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::ActivityUses)) { + let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; + let id = o.entity().ok_or(ProcessorError::MissingEntity)?; + let activity = o.activity().ok_or(ProcessorError::MissingActivity)?; + Ok(ChronicleOperation::ActivityUses(ActivityUses { namespace, id, activity })) + } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::EntityExists)) { + let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; + let entity_id = o.entity().ok_or(ProcessorError::MissingEntity)?; + Ok(ChronicleOperation::EntityExists(EntityExists { namespace, id: entity_id })) + } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::WasGeneratedBy)) { + let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; + let id = o.entity().ok_or(ProcessorError::MissingEntity)?; + let activity = o.activity().ok_or(ProcessorError::MissingActivity)?; + Ok(ChronicleOperation::WasGeneratedBy(WasGeneratedBy { namespace, id, activity })) + } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::EntityDerive)) { + let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; + let id = o.entity().ok_or(ProcessorError::MissingEntity)?; + let used_id = o.used_entity().ok_or(ProcessorError::MissingEntity)?; + let activity_id = o.activity(); + let typ = o.derivation(); + Ok(ChronicleOperation::EntityDerive(EntityDerive { + namespace, + id, + used_id, + activity_id, + typ, + })) + } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::SetAttributes)) { + let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; + let domain = o.domain(); + let attrs = o.attributes(); + + let attributes = Attributes::new(domain, attrs); + let actor: SetAttributes = { + if o.has_key(&Term::Id(id_from_iri_string( + vocab::ChronicleOperation::EntityName, + ))) { + let id = o.entity().ok_or(ProcessorError::MissingEntity)?; + SetAttributes::Entity { namespace, id, attributes } + } else if o.has_key(&Term::Id(id_from_iri_string( + vocab::ChronicleOperation::AgentName, + ))) { + let id = o.agent().ok_or(ProcessorError::MissingAgent)?; + SetAttributes::Agent { namespace, id, attributes } + } else { + let id = o.activity().ok_or(ProcessorError::MissingActivity)?; + SetAttributes::Activity { namespace, id, attributes } + } + }; + + Ok(ChronicleOperation::SetAttributes(actor)) + } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::WasAssociatedWith)) + { + Ok(ChronicleOperation::WasAssociatedWith(WasAssociatedWith::new( + o.namespace().ok_or(ProcessorError::MissingNamespace)?, + o.activity().ok_or(ProcessorError::MissingActivity)?, + o.agent().ok_or(ProcessorError::MissingAgent)?, + o.optional_role(), + ))) + } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::WasAttributedTo)) { + Ok(ChronicleOperation::WasAttributedTo(WasAttributedTo::new( + o.namespace().ok_or(ProcessorError::MissingNamespace)?, + o.entity().ok_or(ProcessorError::MissingEntity)?, + o.agent().ok_or(ProcessorError::MissingAgent)?, + o.optional_role(), + ))) + } else if o.has_type(&id_from_iri_string(vocab::ChronicleOperation::WasInformedBy)) { + let namespace = o.namespace().ok_or(ProcessorError::MissingNamespace)?; + let activity = o.activity().ok_or(ProcessorError::MissingActivity)?; + let informing_activity = + o.informing_activity().ok_or(ProcessorError::MissingActivity)?; + Ok(ChronicleOperation::WasInformedBy(WasInformedBy { + namespace, + activity, + informing_activity, + })) + } else { + error!( "Unknown operation: {:?} {:?}", o.type_entry(), id_from_iri_string(vocab::ChronicleOperation::SetAttributes) ); - unreachable!() - } - } else { - Err(ProcessorError::NotANode(json.clone())) - } - } + unreachable!() + } + } else { + Err(ProcessorError::NotANode(json.clone())) + } + } } diff --git a/crates/common/src/prov/model/json_ld/mod.rs b/crates/common/src/prov/model/json_ld/mod.rs index abb91f6bf..393829cc6 100644 --- a/crates/common/src/prov/model/json_ld/mod.rs +++ b/crates/common/src/prov/model/json_ld/mod.rs @@ -18,77 +18,77 @@ use thiserror_no_std::Error; #[derive(Error, Debug)] pub enum CompactionError { - #[error("JSON-LD: {inner}")] - JsonLd { inner: String }, - #[error("Tokio")] - Join, - #[error("Serde conversion: {source}")] - Serde { - #[from] - #[source] - source: serde_json::Error, - }, - #[error("Expanded document invalid: {message}")] - InvalidExpanded { message: String }, - #[error("Compacted document not a JSON object: {document}")] - NoObject { document: Value }, + #[error("JSON-LD: {inner}")] + JsonLd { inner: String }, + #[error("Tokio")] + Join, + #[error("Serde conversion: {source}")] + Serde { + #[from] + #[source] + source: serde_json::Error, + }, + #[error("Expanded document invalid: {message}")] + InvalidExpanded { message: String }, + #[error("Compacted document not a JSON object: {document}")] + NoObject { document: Value }, } #[derive(Debug)] pub struct ExpandedJson(pub serde_json::Value); fn construct_context_definition( - json: &serde_json::Value, - metadata: M, + json: &serde_json::Value, + metadata: M, ) -> json_ld::syntax::context::Definition -where - M: Clone + core::fmt::Debug, + where + M: Clone + core::fmt::Debug, { - use json_ld::syntax::{ - context::{ - definition::{Bindings, Version}, - Definition, TermDefinition, - }, - Entry, Nullable, TryFromJson, - }; - if let Value::Object(map) = json { - match map.get("@version") { - None => {}, - Some(Value::Number(version)) if version.as_f64() == Some(1.1) => {}, - Some(json_version) => panic!("unexpected JSON-LD context @version: {json_version}"), - }; - let mut bindings = Bindings::new(); - for (key, value) in map { - if key == "@version" { - // already handled above - } else if let Some('@') = key.chars().next() { - panic!("unexpected JSON-LD context key: {key}"); - } else { - let value = - json_ld::syntax::Value::from_serde_json(value.clone(), |_| metadata.clone()); - let term: Meta, M> = TryFromJson::try_from_json(value) - .expect("failed to convert {value} to term binding"); - bindings.insert( - Meta(key.clone().into(), metadata.clone()), - Meta(Nullable::Some(term.value().clone()), metadata.clone()), - ); - } - } - Definition { - base: None, - import: None, - language: None, - direction: None, - propagate: None, - protected: None, - type_: None, - version: Some(Entry::new(metadata.clone(), Meta::new(Version::V1_1, metadata))), - vocab: None, - bindings, - } - } else { - panic!("failed to convert JSON to LD context: {json:?}"); - } + use json_ld::syntax::{ + context::{ + definition::{Bindings, Version}, + Definition, TermDefinition, + }, + Entry, Nullable, TryFromJson, + }; + if let Value::Object(map) = json { + match map.get("@version") { + None => {} + Some(Value::Number(version)) if version.as_f64() == Some(1.1) => {} + Some(json_version) => panic!("unexpected JSON-LD context @version: {json_version}"), + }; + let mut bindings = Bindings::new(); + for (key, value) in map { + if key == "@version" { + // already handled above + } else if let Some('@') = key.chars().next() { + panic!("unexpected JSON-LD context key: {key}"); + } else { + let value = + json_ld::syntax::Value::from_serde_json(value.clone(), |_| metadata.clone()); + let term: Meta, M> = TryFromJson::try_from_json(value) + .expect("failed to convert {value} to term binding"); + bindings.insert( + Meta(key.clone().into(), metadata.clone()), + Meta(Nullable::Some(term.value().clone()), metadata.clone()), + ); + } + } + Definition { + base: None, + import: None, + language: None, + direction: None, + propagate: None, + protected: None, + type_: None, + version: Some(Entry::new(metadata.clone(), Meta::new(Version::V1_1, metadata))), + vocab: None, + bindings, + } + } else { + panic!("failed to convert JSON to LD context: {json:?}"); + } } lazy_static! { @@ -97,95 +97,95 @@ lazy_static! { } impl ExpandedJson { - async fn compact_unordered(self) -> Result { - use json_ld::{ - syntax::context, Compact, ExpandedDocument, Process, ProcessingMode, TryFromJson, - }; - - let vocabulary = no_vocabulary_mut(); - let mut loader: NoLoader = NoLoader::new(); - - // process context - let value = context::Value::One(Meta::new( - context::Context::Definition(JSON_LD_CONTEXT_DEFS.clone()), - (), - )); - let context_meta = Meta::new(value, ()); - let processed_context = context_meta - .process(vocabulary, &mut loader, None) - .await - .map_err(|e| CompactionError::JsonLd { inner: format!("{:?}", e) })?; - - // compact document - - let expanded_meta = json_ld::syntax::Value::from_serde_json(self.0, |_| ()); - - let expanded_doc: Meta, ()> = - TryFromJson::try_from_json_in(vocabulary, expanded_meta).map_err(|e| { - CompactionError::InvalidExpanded { message: format!("{:?}", e.into_value()) } - })?; - - let output = expanded_doc - .compact_full( - vocabulary, - processed_context.as_ref(), - &mut loader, - json_ld::compaction::Options { - processing_mode: ProcessingMode::JsonLd1_1, - compact_to_relative: true, - compact_arrays: true, - ordered: true, - }, - ) - .await - .map_err(|e| CompactionError::JsonLd { inner: e.to_string() })?; - - // Sort @graph - - // reference context - let json: Value = output.into_value().into(); - - if let Value::Object(mut map) = json { - map.insert( - "@context".to_string(), - Value::String("http://chronicle.works/chr/1.0/c.jsonld".to_string()), - ); - Ok(CompactedJson(Value::Object(map))) - } else { - Err(CompactionError::NoObject { document: json }) - } - } - - // Sort @graph by json value, as they are unstable and we need deterministic output - #[tracing::instrument(level = "trace", skip(self), ret)] - pub async fn compact(self) -> Result { - let mut v: serde_json::Value = - serde_json::from_str(&self.compact_unordered().await?.0.to_string())?; - - if let Some(v) = v.pointer_mut("/@graph").and_then(|p| p.as_array_mut()) { - v.sort_by_cached_key(|v| v.to_string()); - } - - Ok(v) - } - - pub async fn compact_stable_order(self) -> Result { - self.compact().await - } + async fn compact_unordered(self) -> Result { + use json_ld::{ + syntax::context, Compact, ExpandedDocument, Process, ProcessingMode, TryFromJson, + }; + + let vocabulary = no_vocabulary_mut(); + let mut loader: NoLoader = NoLoader::new(); + + // process context + let value = context::Value::One(Meta::new( + context::Context::Definition(JSON_LD_CONTEXT_DEFS.clone()), + (), + )); + let context_meta = Meta::new(value, ()); + let processed_context = context_meta + .process(vocabulary, &mut loader, None) + .await + .map_err(|e| CompactionError::JsonLd { inner: format!("{:?}", e) })?; + + // compact document + + let expanded_meta = json_ld::syntax::Value::from_serde_json(self.0, |_| ()); + + let expanded_doc: Meta, ()> = + TryFromJson::try_from_json_in(vocabulary, expanded_meta).map_err(|e| { + CompactionError::InvalidExpanded { message: format!("{:?}", e.into_value()) } + })?; + + let output = expanded_doc + .compact_full( + vocabulary, + processed_context.as_ref(), + &mut loader, + json_ld::compaction::Options { + processing_mode: ProcessingMode::JsonLd1_1, + compact_to_relative: true, + compact_arrays: true, + ordered: true, + }, + ) + .await + .map_err(|e| CompactionError::JsonLd { inner: e.to_string() })?; + + // Sort @graph + + // reference context + let json: Value = output.into_value().into(); + + if let Value::Object(mut map) = json { + map.insert( + "@context".to_string(), + Value::String("http://chronicle.works/chr/1.0/c.jsonld".to_string()), + ); + Ok(CompactedJson(Value::Object(map))) + } else { + Err(CompactionError::NoObject { document: json }) + } + } + + // Sort @graph by json value, as they are unstable and we need deterministic output + #[tracing::instrument(level = "trace", skip(self), ret)] + pub async fn compact(self) -> Result { + let mut v: serde_json::Value = + serde_json::from_str(&self.compact_unordered().await?.0.to_string())?; + + if let Some(v) = v.pointer_mut("/@graph").and_then(|p| p.as_array_mut()) { + v.sort_by_cached_key(|v| v.to_string()); + } + + Ok(v) + } + + pub async fn compact_stable_order(self) -> Result { + self.compact().await + } } pub struct CompactedJson(pub serde_json::Value); impl core::ops::Deref for CompactedJson { - type Target = serde_json::Value; + type Target = serde_json::Value; - fn deref(&self) -> &Self::Target { - &self.0 - } + fn deref(&self) -> &Self::Target { + &self.0 + } } impl CompactedJson { - pub fn pretty(&self) -> String { - serde_json::to_string_pretty(&self.0).unwrap() - } + pub fn pretty(&self) -> String { + serde_json::to_string_pretty(&self.0).unwrap() + } } diff --git a/crates/common/src/prov/model/json_ld/to_json_ld.rs b/crates/common/src/prov/model/json_ld/to_json_ld.rs index 55f6b73d7..6644d8373 100644 --- a/crates/common/src/prov/model/json_ld/to_json_ld.rs +++ b/crates/common/src/prov/model/json_ld/to_json_ld.rs @@ -2,976 +2,977 @@ use serde_json::{json, Value}; #[cfg(not(feature = "std"))] use parity_scale_codec::{ - alloc::string::{String, ToString}, - alloc::vec::Vec, + alloc::string::{String, ToString}, + alloc::vec::Vec, }; use super::ExpandedJson; use crate::{ - attributes::{Attribute, Attributes}, - prov::{ - operations::{ChronicleOperation, CreateNamespace, DerivationType, *}, - vocab::{self, Chronicle, Prov}, - ChronicleIri, ExternalIdPart, FromCompact, ProvModel, UuidPart, - }, + attributes::{Attribute, Attributes}, + prov::{ + operations::{ChronicleOperation, CreateNamespace, DerivationType, *}, + vocab::{self, Chronicle, Prov}, + ChronicleIri, ExternalIdPart, FromCompact, ProvModel, UuidPart, + }, }; + pub trait ToJson { - fn to_json(&self) -> ExpandedJson; + fn to_json(&self) -> ExpandedJson; } impl ToJson for ProvModel { - fn to_json(&self) -> ExpandedJson { - let mut doc = Vec::new(); + fn to_json(&self) -> ExpandedJson { + let mut doc = Vec::new(); - for (id, ns) in self.namespaces.iter() { - doc.push(json!({ + for (id, ns) in self.namespaces.iter() { + doc.push(json!({ "@id": (*id.de_compact()), "@type": [Chronicle::Namespace.as_str()], "http://chronicle.works/chronicle/ns#externalId": [{ "@value": ns.external_id.as_str(), }] })) - } + } - for ((_, id), agent) in self.agents.iter() { - let mut typ = vec![Prov::Agent.to_string()]; - if let Some(x) = agent.domaintypeid.as_ref() { - typ.push(x.de_compact()) - } + for ((_, id), agent) in self.agents.iter() { + let mut typ = vec![Prov::Agent.to_string()]; + if let Some(x) = agent.domaintypeid.as_ref() { + typ.push(x.de_compact()) + } - if let Value::Object(mut agentdoc) = json!({ + if let Value::Object(mut agentdoc) = json!({ "@id": (*id.de_compact()), "@type": typ, "http://chronicle.works/chronicle/ns#externalId": [{ "@value": agent.external_id.as_str(), }] }) { - if let Some(delegation) = - self.acted_on_behalf_of.get(&(agent.namespaceid.to_owned(), id.to_owned())) - { - let mut ids = Vec::new(); - let mut qualified_ids = Vec::new(); + if let Some(delegation) = + self.acted_on_behalf_of.get(&(agent.namespaceid.to_owned(), id.to_owned())) + { + let mut ids = Vec::new(); + let mut qualified_ids = Vec::new(); - for delegation in delegation.iter() { - ids.push(json!({"@id": delegation.responsible_id.de_compact()})); - qualified_ids.push(json!({"@id": delegation.id.de_compact()})); - } + for delegation in delegation.iter() { + ids.push(json!({"@id": delegation.responsible_id.de_compact()})); + qualified_ids.push(json!({"@id": delegation.id.de_compact()})); + } - agentdoc.insert(Prov::ActedOnBehalfOf.to_string(), Value::Array(ids)); + agentdoc.insert(Prov::ActedOnBehalfOf.to_string(), Value::Array(ids)); - agentdoc - .insert(Prov::QualifiedDelegation.to_string(), Value::Array(qualified_ids)); - } + agentdoc + .insert(Prov::QualifiedDelegation.to_string(), Value::Array(qualified_ids)); + } - let mut values = Vec::new(); + let mut values = Vec::new(); - values.push(json!({ + values.push(json!({ "@id": Value::String(agent.namespaceid.de_compact()), })); - agentdoc.insert(Chronicle::HasNamespace.to_string(), Value::Array(values)); + agentdoc.insert(Chronicle::HasNamespace.to_string(), Value::Array(values)); - Self::write_attributes(&mut agentdoc, agent.attributes.iter()); + Self::write_attributes(&mut agentdoc, agent.attributes.iter()); - doc.push(Value::Object(agentdoc)); - } - } + doc.push(Value::Object(agentdoc)); + } + } - for (_, associations) in self.association.iter() { - for association in (*associations).iter() { - if let Value::Object(mut associationdoc) = json!({ + for (_, associations) in self.association.iter() { + for association in (*associations).iter() { + if let Value::Object(mut associationdoc) = json!({ "@id": association.id.de_compact(), "@type": [Prov::Association.as_str()], }) { - let mut values = Vec::new(); + let mut values = Vec::new(); - values.push(json!({ + values.push(json!({ "@id": Value::String(association.agent_id.de_compact()), })); - associationdoc.insert(Prov::Responsible.to_string(), Value::Array(values)); + associationdoc.insert(Prov::Responsible.to_string(), Value::Array(values)); - associationdoc.insert( - Prov::HadActivity.to_string(), - Value::Array(vec![json!({ + associationdoc.insert( + Prov::HadActivity.to_string(), + Value::Array(vec![json!({ "@id": Value::String(association.activity_id.de_compact()), })]), - ); + ); - if let Some(role) = &association.role { - associationdoc.insert( - Prov::HadRole.to_string(), - json!([{ "@value": role.to_string()}]), - ); - } + if let Some(role) = &association.role { + associationdoc.insert( + Prov::HadRole.to_string(), + json!([{ "@value": role.to_string()}]), + ); + } - let mut values = Vec::new(); + let mut values = Vec::new(); - values.push(json!({ + values.push(json!({ "@id": Value::String(association.namespace_id.de_compact()), })); - associationdoc - .insert(Chronicle::HasNamespace.to_string(), Value::Array(values)); + associationdoc + .insert(Chronicle::HasNamespace.to_string(), Value::Array(values)); - doc.push(Value::Object(associationdoc)); - } - } - } + doc.push(Value::Object(associationdoc)); + } + } + } - for (_, attributions) in self.attribution.iter() { - for attribution in (*attributions).iter() { - if let Value::Object(mut attribution_doc) = json!({ + for (_, attributions) in self.attribution.iter() { + for attribution in (*attributions).iter() { + if let Value::Object(mut attribution_doc) = json!({ "@id": attribution.id.de_compact(), "@type": [Prov::Attribution.as_str()], }) { - let mut values = Vec::new(); + let mut values = Vec::new(); - values.push(json!({ + values.push(json!({ "@id": Value::String(attribution.agent_id.de_compact()), })); - attribution_doc.insert(Prov::Responsible.to_string(), Value::Array(values)); + attribution_doc.insert(Prov::Responsible.to_string(), Value::Array(values)); - attribution_doc.insert( - Prov::HadEntity.to_string(), - Value::Array(vec![json!({ + attribution_doc.insert( + Prov::HadEntity.to_string(), + Value::Array(vec![json!({ "@id": Value::String(attribution.entity_id.de_compact()), })]), - ); + ); - if let Some(role) = &attribution.role { - attribution_doc.insert( - Prov::HadRole.to_string(), - json!([{ "@value": role.to_string()}]), - ); - } + if let Some(role) = &attribution.role { + attribution_doc.insert( + Prov::HadRole.to_string(), + json!([{ "@value": role.to_string()}]), + ); + } - let mut values = Vec::new(); + let mut values = Vec::new(); - values.push(json!({ + values.push(json!({ "@id": Value::String(attribution.namespace_id.de_compact()), })); - attribution_doc - .insert(Chronicle::HasNamespace.to_string(), Value::Array(values)); + attribution_doc + .insert(Chronicle::HasNamespace.to_string(), Value::Array(values)); - doc.push(Value::Object(attribution_doc)); - } - } - } + doc.push(Value::Object(attribution_doc)); + } + } + } - for (_, delegations) in self.delegation.iter() { - for delegation in (*delegations).iter() { - if let Value::Object(mut delegationdoc) = json!({ + for (_, delegations) in self.delegation.iter() { + for delegation in (*delegations).iter() { + if let Value::Object(mut delegationdoc) = json!({ "@id": delegation.id.de_compact(), "@type": [Prov::Delegation.as_str()], }) { - if let Some(activity_id) = &delegation.activity_id { - delegationdoc.insert( - Prov::HadActivity.to_string(), - Value::Array(vec![json!({ + if let Some(activity_id) = &delegation.activity_id { + delegationdoc.insert( + Prov::HadActivity.to_string(), + Value::Array(vec![json!({ "@id": Value::String(activity_id.de_compact()), })]), - ); - } + ); + } - if let Some(role) = &delegation.role { - delegationdoc.insert( - Prov::HadRole.to_string(), - json!([{ "@value": role.to_string()}]), - ); - } + if let Some(role) = &delegation.role { + delegationdoc.insert( + Prov::HadRole.to_string(), + json!([{ "@value": role.to_string()}]), + ); + } - let mut responsible_ids = Vec::new(); - responsible_ids.push( - json!({ "@id": Value::String(delegation.responsible_id.de_compact())}), - ); + let mut responsible_ids = Vec::new(); + responsible_ids.push( + json!({ "@id": Value::String(delegation.responsible_id.de_compact())}), + ); - delegationdoc - .insert(Prov::ActedOnBehalfOf.to_string(), Value::Array(responsible_ids)); + delegationdoc + .insert(Prov::ActedOnBehalfOf.to_string(), Value::Array(responsible_ids)); - let mut delegate_ids = Vec::new(); - delegate_ids - .push(json!({ "@id": Value::String(delegation.delegate_id.de_compact())})); + let mut delegate_ids = Vec::new(); + delegate_ids + .push(json!({ "@id": Value::String(delegation.delegate_id.de_compact())})); - delegationdoc.insert(Prov::Delegate.to_string(), Value::Array(delegate_ids)); + delegationdoc.insert(Prov::Delegate.to_string(), Value::Array(delegate_ids)); - let mut values = Vec::new(); + let mut values = Vec::new(); - values.push(json!({ + values.push(json!({ "@id": Value::String(delegation.namespace_id.de_compact()), })); - delegationdoc.insert(Chronicle::HasNamespace.to_string(), Value::Array(values)); + delegationdoc.insert(Chronicle::HasNamespace.to_string(), Value::Array(values)); - doc.push(Value::Object(delegationdoc)); - } - } - } + doc.push(Value::Object(delegationdoc)); + } + } + } - for ((namespace, id), activity) in self.activities.iter() { - let mut typ = vec![Prov::Activity.de_compact()]; - if let Some(x) = activity.domaintype_id.as_ref() { - typ.push(x.de_compact()) - } + for ((namespace, id), activity) in self.activities.iter() { + let mut typ = vec![Prov::Activity.de_compact()]; + if let Some(x) = activity.domaintype_id.as_ref() { + typ.push(x.de_compact()) + } - if let Value::Object(mut activitydoc) = json!({ + if let Value::Object(mut activitydoc) = json!({ "@id": (*id.de_compact()), "@type": typ, "http://chronicle.works/chronicle/ns#externalId": [{ "@value": activity.external_id.as_str(), }] }) { - if let Some(time) = activity.started { - let mut values = Vec::new(); - values.push(json!({"@value": time.to_rfc3339()})); + if let Some(time) = activity.started { + let mut values = Vec::new(); + values.push(json!({"@value": time.to_rfc3339()})); - activitydoc.insert( - "http://www.w3.org/ns/prov#startedAtTime".to_string(), - Value::Array(values), - ); - } + activitydoc.insert( + "http://www.w3.org/ns/prov#startedAtTime".to_string(), + Value::Array(values), + ); + } - if let Some(time) = activity.ended { - let mut values = Vec::new(); - values.push(json!({"@value": time.to_rfc3339()})); + if let Some(time) = activity.ended { + let mut values = Vec::new(); + values.push(json!({"@value": time.to_rfc3339()})); - activitydoc.insert( - "http://www.w3.org/ns/prov#endedAtTime".to_string(), - Value::Array(values), - ); - } + activitydoc.insert( + "http://www.w3.org/ns/prov#endedAtTime".to_string(), + Value::Array(values), + ); + } - if let Some(asoc) = self.association.get(&(namespace.to_owned(), id.to_owned())) { - let mut ids = Vec::new(); + if let Some(asoc) = self.association.get(&(namespace.to_owned(), id.to_owned())) { + let mut ids = Vec::new(); - let mut qualified_ids = Vec::new(); - for asoc in asoc.iter() { - ids.push(json!({"@id": asoc.agent_id.de_compact()})); - qualified_ids.push(json!({"@id": asoc.id.de_compact()})); - } + let mut qualified_ids = Vec::new(); + for asoc in asoc.iter() { + ids.push(json!({"@id": asoc.agent_id.de_compact()})); + qualified_ids.push(json!({"@id": asoc.id.de_compact()})); + } - activitydoc.insert(Prov::WasAssociatedWith.de_compact(), Value::Array(ids)); + activitydoc.insert(Prov::WasAssociatedWith.de_compact(), Value::Array(ids)); - activitydoc.insert( - Prov::QualifiedAssociation.de_compact(), - Value::Array(qualified_ids), - ); - } + activitydoc.insert( + Prov::QualifiedAssociation.de_compact(), + Value::Array(qualified_ids), + ); + } - if let Some(usage) = self.usage.get(&(namespace.to_owned(), id.to_owned())) { - let mut ids = Vec::new(); + if let Some(usage) = self.usage.get(&(namespace.to_owned(), id.to_owned())) { + let mut ids = Vec::new(); - for usage in usage.iter() { - ids.push(json!({"@id": usage.entity_id.de_compact()})); - } + for usage in usage.iter() { + ids.push(json!({"@id": usage.entity_id.de_compact()})); + } - activitydoc.insert(Prov::Used.de_compact(), Value::Array(ids)); - } + activitydoc.insert(Prov::Used.de_compact(), Value::Array(ids)); + } - let mut values = Vec::new(); + let mut values = Vec::new(); - values.push(json!({ + values.push(json!({ "@id": Value::String(activity.namespace_id.de_compact()), })); - activitydoc.insert(Chronicle::HasNamespace.to_string(), Value::Array(values)); + activitydoc.insert(Chronicle::HasNamespace.to_string(), Value::Array(values)); - if let Some(activities) = - self.was_informed_by.get(&(namespace.to_owned(), id.to_owned())) - { - let mut values = Vec::new(); + if let Some(activities) = + self.was_informed_by.get(&(namespace.to_owned(), id.to_owned())) + { + let mut values = Vec::new(); - for (_, activity) in (*activities).iter() { - values.push(json!({ + for (_, activity) in (*activities).iter() { + values.push(json!({ "@id": Value::String(activity.de_compact()), })); - } - activitydoc.insert(Prov::WasInformedBy.to_string(), Value::Array(values)); - } + } + activitydoc.insert(Prov::WasInformedBy.to_string(), Value::Array(values)); + } - Self::write_attributes(&mut activitydoc, activity.attributes.iter()); + Self::write_attributes(&mut activitydoc, activity.attributes.iter()); - doc.push(Value::Object(activitydoc)); - } - } + doc.push(Value::Object(activitydoc)); + } + } - for ((namespace, id), entity) in self.entities.iter() { - let mut typ = vec![Prov::Entity.de_compact()]; - if let Some(x) = entity.domaintypeid.as_ref() { - typ.push(x.de_compact()) - } + for ((namespace, id), entity) in self.entities.iter() { + let mut typ = vec![Prov::Entity.de_compact()]; + if let Some(x) = entity.domaintypeid.as_ref() { + typ.push(x.de_compact()) + } - if let Value::Object(mut entitydoc) = json!({ + if let Value::Object(mut entitydoc) = json!({ "@id": (*id.de_compact()), "@type": typ, "http://chronicle.works/chronicle/ns#externalId": [{ "@value": entity.external_id.as_str() }] }) { - if let Some(derivation) = - self.derivation.get(&(namespace.to_owned(), id.to_owned())) - { - let mut derived_ids = Vec::new(); - let mut primary_ids = Vec::new(); - let mut quotation_ids = Vec::new(); - let mut revision_ids = Vec::new(); - - for derivation in derivation.iter() { - let id = json!({"@id": derivation.used_id.de_compact()}); - match derivation.typ { - DerivationType::PrimarySource => primary_ids.push(id), - DerivationType::Quotation => quotation_ids.push(id), - DerivationType::Revision => revision_ids.push(id), - DerivationType::None => derived_ids.push(id), - } - } - if !derived_ids.is_empty() { - entitydoc - .insert(Prov::WasDerivedFrom.to_string(), Value::Array(derived_ids)); - } - if !primary_ids.is_empty() { - entitydoc - .insert(Prov::HadPrimarySource.to_string(), Value::Array(primary_ids)); - } - if !quotation_ids.is_empty() { - entitydoc - .insert(Prov::WasQuotedFrom.to_string(), Value::Array(quotation_ids)); - } - if !revision_ids.is_empty() { - entitydoc - .insert(Prov::WasRevisionOf.to_string(), Value::Array(revision_ids)); - } - } - - if let Some(generation) = - self.generation.get(&(namespace.to_owned(), id.to_owned())) - { - let mut ids = Vec::new(); - - for generation in generation.iter() { - ids.push(json!({"@id": generation.activity_id.de_compact()})); - } - - entitydoc.insert(Prov::WasGeneratedBy.to_string(), Value::Array(ids)); - } - - let entity_key = (entity.namespace_id.clone(), entity.id.clone()); - - if let Some(attributions) = self.attribution.get(&entity_key) { - let mut ids = Vec::new(); - - let mut qualified_ids = Vec::new(); - for attribution in attributions.iter() { - ids.push(json!({"@id": attribution.agent_id.de_compact()})); - qualified_ids.push(json!({"@id": attribution.id.de_compact()})); - } - - entitydoc.insert(Prov::WasAttributedTo.de_compact(), Value::Array(ids)); - - entitydoc.insert( - Prov::QualifiedAttribution.de_compact(), - Value::Array(qualified_ids), - ); - } - - let mut values = Vec::new(); - - values.push(json!({ + if let Some(derivation) = + self.derivation.get(&(namespace.to_owned(), id.to_owned())) + { + let mut derived_ids = Vec::new(); + let mut primary_ids = Vec::new(); + let mut quotation_ids = Vec::new(); + let mut revision_ids = Vec::new(); + + for derivation in derivation.iter() { + let id = json!({"@id": derivation.used_id.de_compact()}); + match derivation.typ { + DerivationType::PrimarySource => primary_ids.push(id), + DerivationType::Quotation => quotation_ids.push(id), + DerivationType::Revision => revision_ids.push(id), + DerivationType::None => derived_ids.push(id), + } + } + if !derived_ids.is_empty() { + entitydoc + .insert(Prov::WasDerivedFrom.to_string(), Value::Array(derived_ids)); + } + if !primary_ids.is_empty() { + entitydoc + .insert(Prov::HadPrimarySource.to_string(), Value::Array(primary_ids)); + } + if !quotation_ids.is_empty() { + entitydoc + .insert(Prov::WasQuotedFrom.to_string(), Value::Array(quotation_ids)); + } + if !revision_ids.is_empty() { + entitydoc + .insert(Prov::WasRevisionOf.to_string(), Value::Array(revision_ids)); + } + } + + if let Some(generation) = + self.generation.get(&(namespace.to_owned(), id.to_owned())) + { + let mut ids = Vec::new(); + + for generation in generation.iter() { + ids.push(json!({"@id": generation.activity_id.de_compact()})); + } + + entitydoc.insert(Prov::WasGeneratedBy.to_string(), Value::Array(ids)); + } + + let entity_key = (entity.namespace_id.clone(), entity.id.clone()); + + if let Some(attributions) = self.attribution.get(&entity_key) { + let mut ids = Vec::new(); + + let mut qualified_ids = Vec::new(); + for attribution in attributions.iter() { + ids.push(json!({"@id": attribution.agent_id.de_compact()})); + qualified_ids.push(json!({"@id": attribution.id.de_compact()})); + } + + entitydoc.insert(Prov::WasAttributedTo.de_compact(), Value::Array(ids)); + + entitydoc.insert( + Prov::QualifiedAttribution.de_compact(), + Value::Array(qualified_ids), + ); + } + + let mut values = Vec::new(); + + values.push(json!({ "@id": Value::String(entity.namespace_id.de_compact()), })); - entitydoc.insert(Chronicle::HasNamespace.to_string(), Value::Array(values)); + entitydoc.insert(Chronicle::HasNamespace.to_string(), Value::Array(values)); - Self::write_attributes(&mut entitydoc, entity.attributes.iter()); + Self::write_attributes(&mut entitydoc, entity.attributes.iter()); - doc.push(Value::Object(entitydoc)); - } - } + doc.push(Value::Object(entitydoc)); + } + } - ExpandedJson(Value::Array(doc)) - } + ExpandedJson(Value::Array(doc)) + } } impl ProvModel { - fn write_attributes<'a, I: Iterator>( - doc: &mut serde_json::Map, - attributes: I, - ) { - let mut attribute_node = serde_json::Map::new(); - - for attribute in attributes { - attribute_node.insert(attribute.typ.clone(), attribute.value.0.clone()); - } - - doc.insert( - Chronicle::Value.to_string(), - json!([{"@value" : Value::Object(attribute_node), "@type": "@json"}]), - ); - } + fn write_attributes<'a, I: Iterator>( + doc: &mut serde_json::Map, + attributes: I, + ) { + let mut attribute_node = serde_json::Map::new(); + + for attribute in attributes { + attribute_node.insert(attribute.typ.clone(), attribute.value.0.clone()); + } + + doc.insert( + Chronicle::Value.to_string(), + json!([{"@value" : Value::Object(attribute_node), "@type": "@json"}]), + ); + } } impl ToJson for ChronicleOperation { - fn to_json(&self) -> ExpandedJson { - let mut operation: Vec = Vec::new(); - - let o = match self { - ChronicleOperation::CreateNamespace(CreateNamespace { id, .. }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::CreateNamespace); - - o.has_value( - OperationValue::string(id.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(id.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o - }, - ChronicleOperation::AgentExists(AgentExists { namespace, id }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::AgentExists); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(id.external_id_part()), - vocab::ChronicleOperation::AgentName, - ); - - o - }, - ChronicleOperation::AgentActsOnBehalfOf(ActsOnBehalfOf { - namespace, - id: _, // This is derivable from components - delegate_id, - activity_id, - role, - responsible_id, - }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::AgentActsOnBehalfOf); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(delegate_id.external_id_part()), - vocab::ChronicleOperation::DelegateId, - ); - - o.has_value( - OperationValue::string(responsible_id.external_id_part()), - vocab::ChronicleOperation::ResponsibleId, - ); - - if let Some(role) = role { - o.has_value(OperationValue::string(role), vocab::ChronicleOperation::Role); - } - - if let Some(activity_id) = activity_id { - o.has_value( - OperationValue::string(activity_id.external_id_part()), - vocab::ChronicleOperation::ActivityName, - ); - } - - o - }, - ChronicleOperation::ActivityExists(ActivityExists { namespace, id }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::ActivityExists); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(id.external_id_part()), - vocab::ChronicleOperation::ActivityName, - ); - - o - }, - ChronicleOperation::StartActivity(StartActivity { namespace, id, time }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::StartActivity); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(id.external_id_part()), - vocab::ChronicleOperation::ActivityName, - ); - - o.has_value( - OperationValue::string(time.to_rfc3339()), - vocab::ChronicleOperation::StartActivityTime, - ); - - o - }, - ChronicleOperation::EndActivity(EndActivity { namespace, id, time }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::EndActivity); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(id.external_id_part()), - vocab::ChronicleOperation::ActivityName, - ); - - o.has_value( - OperationValue::string(time.to_rfc3339()), - vocab::ChronicleOperation::EndActivityTime, - ); - - o - }, - ChronicleOperation::ActivityUses(ActivityUses { namespace, id, activity }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::ActivityUses); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(id.external_id_part()), - vocab::ChronicleOperation::EntityName, - ); - - o.has_value( - OperationValue::string(activity.external_id_part()), - vocab::ChronicleOperation::ActivityName, - ); - - o - }, - ChronicleOperation::EntityExists(EntityExists { namespace, id }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::EntityExists); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(id.external_id_part()), - vocab::ChronicleOperation::EntityName, - ); - - o - }, - ChronicleOperation::WasGeneratedBy(WasGeneratedBy { namespace, id, activity }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::WasGeneratedBy); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(id.external_id_part()), - vocab::ChronicleOperation::EntityName, - ); - - o.has_value( - OperationValue::string(activity.external_id_part()), - vocab::ChronicleOperation::ActivityName, - ); - - o - }, - ChronicleOperation::WasInformedBy(WasInformedBy { - namespace, - activity, - informing_activity, - }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::WasInformedBy); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(activity.external_id_part()), - vocab::ChronicleOperation::ActivityName, - ); - - o.has_value( - OperationValue::string(informing_activity.external_id_part()), - vocab::ChronicleOperation::InformingActivityName, - ); - - o - }, - ChronicleOperation::EntityDerive(EntityDerive { - namespace, - id, - used_id, - activity_id, - typ, - }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::EntityDerive); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(id.external_id_part()), - vocab::ChronicleOperation::EntityName, - ); - - o.has_value( - OperationValue::string(used_id.external_id_part()), - vocab::ChronicleOperation::UsedEntityName, - ); - - if let Some(activity) = activity_id { - o.has_value( - OperationValue::string(activity.external_id_part()), - vocab::ChronicleOperation::ActivityName, - ); - } - - if *typ != DerivationType::None { - o.derivation(typ); - } - - o - }, - ChronicleOperation::SetAttributes(SetAttributes::Entity { - namespace, - id, - attributes, - }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::SetAttributes); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(id.external_id_part()), - vocab::ChronicleOperation::EntityName, - ); - - if let Some(domaintypeid) = attributes.get_typ() { - let id = OperationValue::string(domaintypeid.external_id_part()); - o.has_value(id, vocab::ChronicleOperation::DomaintypeId); - } - - o.attributes_object(attributes); - - o - }, - ChronicleOperation::SetAttributes(SetAttributes::Activity { - namespace, - id, - attributes, - }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::SetAttributes); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(id.external_id_part()), - vocab::ChronicleOperation::ActivityName, - ); - - if let Some(domaintypeid) = attributes.get_typ() { - let id = OperationValue::string(domaintypeid.external_id_part()); - o.has_value(id, vocab::ChronicleOperation::DomaintypeId); - } - - o.attributes_object(attributes); - - o - }, - ChronicleOperation::SetAttributes(SetAttributes::Agent { - namespace, - id, - attributes, - }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::SetAttributes); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(id.external_id_part()), - vocab::ChronicleOperation::AgentName, - ); - - if let Some(domaintypeid) = attributes.get_typ() { - let id = OperationValue::string(domaintypeid.external_id_part()); - o.has_value(id, vocab::ChronicleOperation::DomaintypeId); - } - - o.attributes_object(attributes); - - o - }, - ChronicleOperation::WasAssociatedWith(WasAssociatedWith { - id: _, - role, - namespace, - activity_id, - agent_id, - }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::WasAssociatedWith); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(activity_id.external_id_part()), - vocab::ChronicleOperation::ActivityName, - ); - - o.has_value( - OperationValue::string(agent_id.external_id_part()), - vocab::ChronicleOperation::AgentName, - ); - - if let Some(role) = role { - o.has_value(OperationValue::string(role), vocab::ChronicleOperation::Role); - } - - o - }, - ChronicleOperation::WasAttributedTo(WasAttributedTo { - id: _, - role, - namespace, - entity_id, - agent_id, - }) => { - let mut o = Value::new_operation(vocab::ChronicleOperation::WasAttributedTo); - - o.has_value( - OperationValue::string(namespace.external_id_part()), - vocab::ChronicleOperation::NamespaceName, - ); - - o.has_value( - OperationValue::string(namespace.uuid_part()), - vocab::ChronicleOperation::NamespaceUuid, - ); - - o.has_value( - OperationValue::string(entity_id.external_id_part()), - vocab::ChronicleOperation::EntityName, - ); - - o.has_value( - OperationValue::string(agent_id.external_id_part()), - vocab::ChronicleOperation::AgentName, - ); - - if let Some(role) = role { - o.has_value(OperationValue::string(role), vocab::ChronicleOperation::Role); - } - - o - }, - }; - operation.push(o); - super::ExpandedJson(operation.into()) - } + fn to_json(&self) -> ExpandedJson { + let mut operation: Vec = Vec::new(); + + let o = match self { + ChronicleOperation::CreateNamespace(CreateNamespace { id, .. }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::CreateNamespace); + + o.has_value( + OperationValue::string(id.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(id.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o + } + ChronicleOperation::AgentExists(AgentExists { namespace, id }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::AgentExists); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(id.external_id_part()), + vocab::ChronicleOperation::AgentName, + ); + + o + } + ChronicleOperation::AgentActsOnBehalfOf(ActsOnBehalfOf { + namespace, + id: _, // This is derivable from components + delegate_id, + activity_id, + role, + responsible_id, + }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::AgentActsOnBehalfOf); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(delegate_id.external_id_part()), + vocab::ChronicleOperation::DelegateId, + ); + + o.has_value( + OperationValue::string(responsible_id.external_id_part()), + vocab::ChronicleOperation::ResponsibleId, + ); + + if let Some(role) = role { + o.has_value(OperationValue::string(role), vocab::ChronicleOperation::Role); + } + + if let Some(activity_id) = activity_id { + o.has_value( + OperationValue::string(activity_id.external_id_part()), + vocab::ChronicleOperation::ActivityName, + ); + } + + o + } + ChronicleOperation::ActivityExists(ActivityExists { namespace, id }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::ActivityExists); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(id.external_id_part()), + vocab::ChronicleOperation::ActivityName, + ); + + o + } + ChronicleOperation::StartActivity(StartActivity { namespace, id, time }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::StartActivity); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(id.external_id_part()), + vocab::ChronicleOperation::ActivityName, + ); + + o.has_value( + OperationValue::string(time.to_rfc3339()), + vocab::ChronicleOperation::StartActivityTime, + ); + + o + } + ChronicleOperation::EndActivity(EndActivity { namespace, id, time }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::EndActivity); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(id.external_id_part()), + vocab::ChronicleOperation::ActivityName, + ); + + o.has_value( + OperationValue::string(time.to_rfc3339()), + vocab::ChronicleOperation::EndActivityTime, + ); + + o + } + ChronicleOperation::ActivityUses(ActivityUses { namespace, id, activity }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::ActivityUses); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(id.external_id_part()), + vocab::ChronicleOperation::EntityName, + ); + + o.has_value( + OperationValue::string(activity.external_id_part()), + vocab::ChronicleOperation::ActivityName, + ); + + o + } + ChronicleOperation::EntityExists(EntityExists { namespace, id }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::EntityExists); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(id.external_id_part()), + vocab::ChronicleOperation::EntityName, + ); + + o + } + ChronicleOperation::WasGeneratedBy(WasGeneratedBy { namespace, id, activity }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::WasGeneratedBy); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(id.external_id_part()), + vocab::ChronicleOperation::EntityName, + ); + + o.has_value( + OperationValue::string(activity.external_id_part()), + vocab::ChronicleOperation::ActivityName, + ); + + o + } + ChronicleOperation::WasInformedBy(WasInformedBy { + namespace, + activity, + informing_activity, + }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::WasInformedBy); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(activity.external_id_part()), + vocab::ChronicleOperation::ActivityName, + ); + + o.has_value( + OperationValue::string(informing_activity.external_id_part()), + vocab::ChronicleOperation::InformingActivityName, + ); + + o + } + ChronicleOperation::EntityDerive(EntityDerive { + namespace, + id, + used_id, + activity_id, + typ, + }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::EntityDerive); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(id.external_id_part()), + vocab::ChronicleOperation::EntityName, + ); + + o.has_value( + OperationValue::string(used_id.external_id_part()), + vocab::ChronicleOperation::UsedEntityName, + ); + + if let Some(activity) = activity_id { + o.has_value( + OperationValue::string(activity.external_id_part()), + vocab::ChronicleOperation::ActivityName, + ); + } + + if *typ != DerivationType::None { + o.derivation(typ); + } + + o + } + ChronicleOperation::SetAttributes(SetAttributes::Entity { + namespace, + id, + attributes, + }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::SetAttributes); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(id.external_id_part()), + vocab::ChronicleOperation::EntityName, + ); + + if let Some(domaintypeid) = attributes.get_typ() { + let id = OperationValue::string(domaintypeid.external_id_part()); + o.has_value(id, vocab::ChronicleOperation::DomaintypeId); + } + + o.attributes_object(attributes); + + o + } + ChronicleOperation::SetAttributes(SetAttributes::Activity { + namespace, + id, + attributes, + }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::SetAttributes); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(id.external_id_part()), + vocab::ChronicleOperation::ActivityName, + ); + + if let Some(domaintypeid) = attributes.get_typ() { + let id = OperationValue::string(domaintypeid.external_id_part()); + o.has_value(id, vocab::ChronicleOperation::DomaintypeId); + } + + o.attributes_object(attributes); + + o + } + ChronicleOperation::SetAttributes(SetAttributes::Agent { + namespace, + id, + attributes, + }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::SetAttributes); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(id.external_id_part()), + vocab::ChronicleOperation::AgentName, + ); + + if let Some(domaintypeid) = attributes.get_typ() { + let id = OperationValue::string(domaintypeid.external_id_part()); + o.has_value(id, vocab::ChronicleOperation::DomaintypeId); + } + + o.attributes_object(attributes); + + o + } + ChronicleOperation::WasAssociatedWith(WasAssociatedWith { + id: _, + role, + namespace, + activity_id, + agent_id, + }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::WasAssociatedWith); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(activity_id.external_id_part()), + vocab::ChronicleOperation::ActivityName, + ); + + o.has_value( + OperationValue::string(agent_id.external_id_part()), + vocab::ChronicleOperation::AgentName, + ); + + if let Some(role) = role { + o.has_value(OperationValue::string(role), vocab::ChronicleOperation::Role); + } + + o + } + ChronicleOperation::WasAttributedTo(WasAttributedTo { + id: _, + role, + namespace, + entity_id, + agent_id, + }) => { + let mut o = Value::new_operation(vocab::ChronicleOperation::WasAttributedTo); + + o.has_value( + OperationValue::string(namespace.external_id_part()), + vocab::ChronicleOperation::NamespaceName, + ); + + o.has_value( + OperationValue::string(namespace.uuid_part()), + vocab::ChronicleOperation::NamespaceUuid, + ); + + o.has_value( + OperationValue::string(entity_id.external_id_part()), + vocab::ChronicleOperation::EntityName, + ); + + o.has_value( + OperationValue::string(agent_id.external_id_part()), + vocab::ChronicleOperation::AgentName, + ); + + if let Some(role) = role { + o.has_value(OperationValue::string(role), vocab::ChronicleOperation::Role); + } + + o + } + }; + operation.push(o); + super::ExpandedJson(operation.into()) + } } struct OperationValue(String); impl OperationValue { - fn string(value: impl ToString) -> Self { - OperationValue(value.to_string()) - } - - #[allow(dead_code)] - fn identity(id: ChronicleIri) -> Self { - OperationValue(id.to_string()) - } + fn string(value: impl ToString) -> Self { + OperationValue(value.to_string()) + } + + #[allow(dead_code)] + fn identity(id: ChronicleIri) -> Self { + OperationValue(id.to_string()) + } } trait Operate { - fn new_operation(op: vocab::ChronicleOperation) -> Self; - fn new_type(id: OperationValue, op: vocab::ChronicleOperation) -> Self; - fn new_value(id: OperationValue) -> Self; - fn new_id(id: OperationValue) -> Self; - fn has_value(&mut self, value: OperationValue, op: vocab::ChronicleOperation); - fn has_id(&mut self, id: OperationValue, op: vocab::ChronicleOperation); - fn attributes_object(&mut self, attributes: &Attributes); - fn derivation(&mut self, typ: &DerivationType); + fn new_operation(op: vocab::ChronicleOperation) -> Self; + fn new_type(id: OperationValue, op: vocab::ChronicleOperation) -> Self; + fn new_value(id: OperationValue) -> Self; + fn new_id(id: OperationValue) -> Self; + fn has_value(&mut self, value: OperationValue, op: vocab::ChronicleOperation); + fn has_id(&mut self, id: OperationValue, op: vocab::ChronicleOperation); + fn attributes_object(&mut self, attributes: &Attributes); + fn derivation(&mut self, typ: &DerivationType); } impl Operate for Value { - fn new_type(id: OperationValue, op: vocab::ChronicleOperation) -> Self { - json!({ + fn new_type(id: OperationValue, op: vocab::ChronicleOperation) -> Self { + json!({ "@id": id.0, "@type": [op.as_str()], }) - } + } - fn new_value(id: OperationValue) -> Self { - json!({ + fn new_value(id: OperationValue) -> Self { + json!({ "@value": id.0 }) - } + } - fn new_id(id: OperationValue) -> Self { - json!({ + fn new_id(id: OperationValue) -> Self { + json!({ "@id": id.0 }) - } - - fn has_value(&mut self, value: OperationValue, op: vocab::ChronicleOperation) { - if let Value::Object(map) = self { - let key = op.to_string(); - let mut values: Vec = Vec::new(); - let object = Self::new_value(value); - values.push(object); - map.insert(key, Value::Array(values)); - } else { - panic!("use on JSON objects only"); - } - } - - fn has_id(&mut self, id: OperationValue, op: vocab::ChronicleOperation) { - if let Value::Object(map) = self { - let key = op.to_string(); - let mut value: Vec = Vec::new(); - let object = Self::new_id(id); - value.push(object); - map.insert(key, Value::Array(value)); - } else { - panic!("use on JSON objects only"); - } - } - - fn new_operation(op: vocab::ChronicleOperation) -> Self { - let id = OperationValue::string("_:n1"); - Self::new_type(id, op) - } - - fn attributes_object(&mut self, attributes: &Attributes) { - if let Value::Object(map) = self { - let mut attribute_node = serde_json::Map::new(); - for attribute in attributes.get_values() { - attribute_node.insert(attribute.typ.clone(), attribute.value.0.clone()); - } - map.insert( - vocab::ChronicleOperation::Attributes.to_string(), - json!([{"@value" : attribute_node, "@type": "@json"}]), - ); - } else { - panic!("use on JSON objects only"); - } - } - - fn derivation(&mut self, typ: &DerivationType) { - let typ = match typ { - DerivationType::None => panic!("should never handle a None derivation type"), - DerivationType::Revision => "Revision", - DerivationType::Quotation => "Quotation", - DerivationType::PrimarySource => "PrimarySource", - }; - let id = OperationValue::string(typ); - - self.has_value(id, vocab::ChronicleOperation::DerivationType); - } + } + + fn has_value(&mut self, value: OperationValue, op: vocab::ChronicleOperation) { + if let Value::Object(map) = self { + let key = op.to_string(); + let mut values: Vec = Vec::new(); + let object = Self::new_value(value); + values.push(object); + map.insert(key, Value::Array(values)); + } else { + panic!("use on JSON objects only"); + } + } + + fn has_id(&mut self, id: OperationValue, op: vocab::ChronicleOperation) { + if let Value::Object(map) = self { + let key = op.to_string(); + let mut value: Vec = Vec::new(); + let object = Self::new_id(id); + value.push(object); + map.insert(key, Value::Array(value)); + } else { + panic!("use on JSON objects only"); + } + } + + fn new_operation(op: vocab::ChronicleOperation) -> Self { + let id = OperationValue::string("_:n1"); + Self::new_type(id, op) + } + + fn attributes_object(&mut self, attributes: &Attributes) { + if let Value::Object(map) = self { + let mut attribute_node = serde_json::Map::new(); + for attribute in attributes.get_values() { + attribute_node.insert(attribute.typ.clone(), attribute.value.0.clone()); + } + map.insert( + vocab::ChronicleOperation::Attributes.to_string(), + json!([{"@value" : attribute_node, "@type": "@json"}]), + ); + } else { + panic!("use on JSON objects only"); + } + } + + fn derivation(&mut self, typ: &DerivationType) { + let typ = match typ { + DerivationType::None => panic!("should never handle a None derivation type"), + DerivationType::Revision => "Revision", + DerivationType::Quotation => "Quotation", + DerivationType::PrimarySource => "PrimarySource", + }; + let id = OperationValue::string(typ); + + self.has_value(id, vocab::ChronicleOperation::DerivationType); + } } diff --git a/crates/common/src/prov/model/mod.rs b/crates/common/src/prov/model/mod.rs index 47615bb75..2133d5b28 100644 --- a/crates/common/src/prov/model/mod.rs +++ b/crates/common/src/prov/model/mod.rs @@ -1,4 +1,5 @@ mod contradiction; + pub use contradiction::Contradiction; #[cfg(feature = "json-ld")] @@ -11,19 +12,19 @@ mod proptest; use core::{convert::Infallible, fmt::Debug}; #[cfg(not(feature = "std"))] use parity_scale_codec::{ - alloc::collections::{BTreeMap, BTreeSet}, - alloc::string::String, - alloc::vec::Vec, + alloc::collections::{BTreeMap, BTreeSet}, + alloc::string::String, + alloc::vec::Vec, }; #[cfg(not(feature = "std"))] use scale_info::{ - prelude::borrow::ToOwned, prelude::string::ToString, prelude::sync::Arc, prelude::*, + prelude::borrow::ToOwned, prelude::string::ToString, prelude::sync::Arc, prelude::*, }; use serde::Serialize; #[cfg(feature = "std")] use std::{ - collections::{BTreeMap, BTreeSet}, - sync::Arc, + collections::{BTreeMap, BTreeSet}, + sync::Arc, }; #[cfg(feature = "std")] @@ -35,525 +36,524 @@ use tracing::{instrument, trace}; use uuid::Uuid; use crate::{ - attributes::{Attribute, Attributes}, - identity::IdentityError, - prov::operations::WasAttributedTo, + attributes::{Attribute, Attributes}, + identity::IdentityError, + prov::operations::WasAttributedTo, }; use super::{ - id, - operations::{ - ActivityExists, ActivityUses, ActsOnBehalfOf, AgentExists, ChronicleOperation, - CreateNamespace, DerivationType, EndActivity, EntityDerive, EntityExists, SetAttributes, - StartActivity, TimeWrapper, WasAssociatedWith, WasGeneratedBy, WasInformedBy, - }, - ActivityId, AgentId, AssociationId, AttributionId, ChronicleIri, DelegationId, DomaintypeId, - EntityId, ExternalId, ExternalIdPart, NamespaceId, Role, UuidPart, + id, + operations::{ + ActivityExists, ActivityUses, ActsOnBehalfOf, AgentExists, ChronicleOperation, + CreateNamespace, DerivationType, EndActivity, EntityDerive, EntityExists, SetAttributes, + StartActivity, TimeWrapper, WasAssociatedWith, WasGeneratedBy, WasInformedBy, + }, + ActivityId, AgentId, AssociationId, AttributionId, ChronicleIri, DelegationId, DomaintypeId, + EntityId, ExternalId, ExternalIdPart, NamespaceId, Role, UuidPart, }; #[cfg(feature = "json-ld")] #[derive(Error, Debug)] pub enum ProcessorError { - #[error("Invalid address")] - Address, - #[error("Json Ld Error {0}")] - Compaction( - #[from] - #[source] - json_ld::CompactionError, - ), - #[error("Contradiction {0}")] - Contradiction(Contradiction), - #[error("Json Ld Error {inner}")] - Expansion { inner: String }, - #[error("IdentityError {0}")] - Identity( - #[from] - #[source] - IdentityError, - ), - #[error("Invalid IRI {0}")] - IRef( - #[from] - #[source] - iref::Error, - ), - #[error("Not a Chronicle IRI {0}")] - NotAChronicleIri( - #[from] - #[source] - id::ParseIriError, - ), - #[error("Missing @id {object:?}")] - MissingId { object: serde_json::Value }, - #[error("Missing property {iri}:{object:?}")] - MissingProperty { iri: String, object: serde_json::Value }, - #[error("Json LD object is not a node {0}")] - NotANode(serde_json::Value), - #[error("Chronicle value is not a JSON object")] - NotAnObject, - - #[error("Missing activity")] - MissingActivity, - - #[error("Missing namespace")] - MissingNamespace, - #[error("Missing entity")] - MissingEntity, - #[error("Missing agent")] - MissingAgent, - #[error("Missing time")] - MissingTime, - #[error("Missing derivation")] - MissingDerivation, - #[error("Missing domain type")] - MissingDomainType, - - #[error("OpaExecutorError: {0}")] - OpaExecutor( - #[from] - #[source] - anyhow::Error, - ), - #[error("Malformed JSON {0}")] - SerdeJson( - #[from] - #[source] - serde_json::Error, - ), - - #[error("Submission {0}")] - SubmissionFormat( - #[from] - #[source] - PayloadError, - ), - #[error("Submission body format: {0}")] - Time( - #[from] - #[source] - chrono::ParseError, - ), - #[error("Tokio Error")] - Tokio, - #[error("State is not valid utf8 {0}")] - Utf8( - #[from] - #[source] - core::str::Utf8Error, - ), + #[error("Invalid address")] + Address, + #[error("Json Ld Error {0}")] + Compaction( + #[from] + #[source] + json_ld::CompactionError, + ), + #[error("Contradiction {0}")] + Contradiction(Contradiction), + #[error("Json Ld Error {inner}")] + Expansion { inner: String }, + #[error("IdentityError {0}")] + Identity( + #[from] + #[source] + IdentityError, + ), + #[error("Invalid IRI {0}")] + IRef( + #[from] + #[source] + iref::Error, + ), + #[error("Not a Chronicle IRI {0}")] + NotAChronicleIri( + #[from] + #[source] + id::ParseIriError, + ), + #[error("Missing @id {object:?}")] + MissingId { object: serde_json::Value }, + #[error("Missing property {iri}:{object:?}")] + MissingProperty { iri: String, object: serde_json::Value }, + #[error("Json LD object is not a node {0}")] + NotANode(serde_json::Value), + #[error("Chronicle value is not a JSON object")] + NotAnObject, + + #[error("Missing activity")] + MissingActivity, + + #[error("Missing namespace")] + MissingNamespace, + #[error("Missing entity")] + MissingEntity, + #[error("Missing agent")] + MissingAgent, + #[error("Missing time")] + MissingTime, + #[error("Missing derivation")] + MissingDerivation, + #[error("Missing domain type")] + MissingDomainType, + + #[error("OpaExecutorError: {0}")] + OpaExecutor( + #[from] + #[source] + anyhow::Error, + ), + #[error("Malformed JSON {0}")] + SerdeJson( + #[from] + #[source] + serde_json::Error, + ), + + #[error("Submission {0}")] + SubmissionFormat( + #[from] + #[source] + PayloadError, + ), + #[error("Submission body format: {0}")] + Time( + #[from] + #[source] + chrono::ParseError, + ), + #[error("Tokio Error")] + Tokio, + #[error("State is not valid utf8 {0}")] + Utf8( + #[from] + #[source] + core::str::Utf8Error, + ), } #[cfg(not(feature = "json-ld"))] #[derive(Error, Debug)] pub enum ProcessorError { - #[error("Invalid address")] - Address, - #[error("Contradiction {0}")] - Contradiction(Contradiction), - #[error("IdentityError {0}")] - Identity( - #[from] - #[source] - IdentityError, - ), - #[error("Not a Chronicle IRI {0}")] - NotAChronicleIri( - #[from] - #[source] - id::ParseIriError, - ), - #[error("Missing @id {object:?}")] - MissingId { object: serde_json::Value }, - #[error("Missing property {iri}:{object:?}")] - MissingProperty { iri: String, object: serde_json::Value }, - #[error("Json LD object is not a node {0}")] - NotANode(serde_json::Value), - #[error("Chronicle value is not a JSON object")] - NotAnObject, - #[error("OpaExecutorError: {0}")] - OpaExecutor( - #[from] - #[source] - anyhow::Error, - ), - #[error("Malformed JSON {0}")] - SerdeJson( - #[from] - #[source] - serde_json::Error, - ), - #[error("Unparsable date/time {0}")] - SubmissionFormat( - #[from] - #[source] - PayloadError, - ), - #[error("Submission body format: {0}")] - Time( - #[from] - #[source] - chrono::ParseError, - ), - #[error("Tokio Error")] - Tokio, - #[error("State is not valid utf8 {0}")] - Utf8( - #[from] - #[source] - core::str::Utf8Error, - ), + #[error("Invalid address")] + Address, + #[error("Contradiction {0}")] + Contradiction(Contradiction), + #[error("IdentityError {0}")] + Identity( + #[from] + #[source] + IdentityError, + ), + #[error("Not a Chronicle IRI {0}")] + NotAChronicleIri( + #[from] + #[source] + id::ParseIriError, + ), + #[error("Missing @id {object:?}")] + MissingId { object: serde_json::Value }, + #[error("Missing property {iri}:{object:?}")] + MissingProperty { iri: String, object: serde_json::Value }, + #[error("Json LD object is not a node {0}")] + NotANode(serde_json::Value), + #[error("Chronicle value is not a JSON object")] + NotAnObject, + #[error("OpaExecutorError: {0}")] + OpaExecutor( + #[from] + #[source] + anyhow::Error, + ), + #[error("Malformed JSON {0}")] + SerdeJson( + #[from] + #[source] + serde_json::Error, + ), + #[error("Unparsable date/time {0}")] + SubmissionFormat( + #[from] + #[source] + PayloadError, + ), + #[error("Submission body format: {0}")] + Time( + #[from] + #[source] + chrono::ParseError, + ), + #[error("Tokio Error")] + Tokio, + #[error("State is not valid utf8 {0}")] + Utf8( + #[from] + #[source] + core::str::Utf8Error, + ), } #[derive(Error, Debug)] pub enum PayloadError { - #[error("No list of Chronicle operations")] - OpsNotAList, - #[error("Not a JSON object")] - NotAnObject, - #[error("No version number")] - VersionMissing, - #[error("Unknown version number")] - VersionUnknown, + #[error("No list of Chronicle operations")] + OpsNotAList, + #[error("Not a JSON object")] + NotAnObject, + #[error("No version number")] + VersionMissing, + #[error("Unknown version number")] + VersionUnknown, } impl From for ProcessorError { - fn from(_: Infallible) -> Self { - unreachable!() - } + fn from(_: Infallible) -> Self { + unreachable!() + } } #[derive(Error, Debug)] pub enum ChronicleTransactionIdError { - #[error("Invalid transaction id {id}")] - InvalidTransactionId { id: String }, + #[error("Invalid transaction id {id}")] + InvalidTransactionId { id: String }, } #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Copy, Default)] pub struct ChronicleTransactionId([u8; 16]); impl core::ops::Deref for ChronicleTransactionId { - type Target = [u8; 16]; + type Target = [u8; 16]; - fn deref(&self) -> &Self::Target { - &self.0 - } + fn deref(&self) -> &Self::Target { + &self.0 + } } impl core::fmt::Display for ChronicleTransactionId { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str(&hex::encode(self.0)) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(&hex::encode(self.0)) + } } impl From for ChronicleTransactionId { - fn from(u: Uuid) -> Self { - Self(u.into_bytes()) - } + fn from(u: Uuid) -> Self { + Self(u.into_bytes()) + } } impl From<[u8; 16]> for ChronicleTransactionId { - fn from(u: [u8; 16]) -> Self { - Self(u) - } + fn from(u: [u8; 16]) -> Self { + Self(u) + } } impl core::convert::TryFrom for ChronicleTransactionId { - type Error = hex::FromHexError; + type Error = hex::FromHexError; - fn try_from(s: String) -> Result { - Self::try_from(s.as_str()) - } + fn try_from(s: String) -> Result { + Self::try_from(s.as_str()) + } } impl core::convert::TryFrom<&str> for ChronicleTransactionId { - type Error = hex::FromHexError; - - fn try_from(s: &str) -> Result { - let bytes = hex::decode(s)?; - let mut array = [0; 16]; - array.copy_from_slice(&bytes[0..16]); - Ok(Self(array)) - } + type Error = hex::FromHexError; + + fn try_from(s: &str) -> Result { + let bytes = hex::decode(s)?; + let mut array = [0; 16]; + array.copy_from_slice(&bytes[0..16]); + Ok(Self(array)) + } } #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Namespace { - pub id: NamespaceId, - pub uuid: [u8; 16], - pub external_id: ExternalId, + pub id: NamespaceId, + pub uuid: [u8; 16], + pub external_id: ExternalId, } impl Namespace { - pub fn new(id: NamespaceId, uuid: Uuid, external_id: &ExternalId) -> Self { - Self { id, uuid: uuid.into_bytes(), external_id: external_id.to_owned() } - } + pub fn new(id: NamespaceId, uuid: Uuid, external_id: &ExternalId) -> Self { + Self { id, uuid: uuid.into_bytes(), external_id: external_id.to_owned() } + } } #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Agent { - pub id: AgentId, - pub namespaceid: NamespaceId, - pub external_id: ExternalId, - pub domaintypeid: Option, - pub attributes: Vec, + pub id: AgentId, + pub namespaceid: NamespaceId, + pub external_id: ExternalId, + pub domaintypeid: Option, + pub attributes: Vec, } impl Agent { - pub fn has_attributes(self, attributes: Attributes) -> Self { - let Self { id, namespaceid, external_id, .. } = self; - - Self { - id, - namespaceid, - external_id, - domaintypeid: attributes.get_typ().clone(), - attributes: attributes.get_items().to_vec(), - } - } - - // Create a prototypical agent from its IRI, we can only determine external_id - pub fn exists(namespaceid: NamespaceId, id: AgentId) -> Self { - Self { - namespaceid, - external_id: id.external_id_part().to_owned(), - id, - domaintypeid: None, - attributes: Vec::new(), - } - } + pub fn has_attributes(self, attributes: Attributes) -> Self { + let Self { id, namespaceid, external_id, .. } = self; + + Self { + id, + namespaceid, + external_id, + domaintypeid: attributes.get_typ().clone(), + attributes: attributes.get_items().to_vec(), + } + } + + // Create a prototypical agent from its IRI, we can only determine external_id + pub fn exists(namespaceid: NamespaceId, id: AgentId) -> Self { + Self { + namespaceid, + external_id: id.external_id_part().to_owned(), + id, + domaintypeid: None, + attributes: Vec::new(), + } + } } #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Activity { - pub id: ActivityId, - pub namespace_id: NamespaceId, - pub external_id: ExternalId, - pub domaintype_id: Option, - pub attributes: Vec, - pub started: Option, - pub ended: Option, + pub id: ActivityId, + pub namespace_id: NamespaceId, + pub external_id: ExternalId, + pub domaintype_id: Option, + pub attributes: Vec, + pub started: Option, + pub ended: Option, } impl Activity { - pub fn has_attributes(self, attributes: Attributes) -> Self { - let Self { id, namespace_id, external_id, started, ended, .. } = self; - Self { - id, - namespace_id, - external_id, - started, - ended, - domaintype_id: attributes.get_typ().clone(), - attributes: attributes.get_items().to_vec(), - } - } - - // Create a prototypical agent from its IRI, we can only determine external_id - pub fn exists(namespace_id: NamespaceId, id: ActivityId) -> Self { - Self { - namespace_id, - external_id: id.external_id_part().to_owned(), - id, - started: None, - ended: None, - domaintype_id: None, - attributes: Vec::new(), - } - } + pub fn has_attributes(self, attributes: Attributes) -> Self { + let Self { id, namespace_id, external_id, started, ended, .. } = self; + Self { + id, + namespace_id, + external_id, + started, + ended, + domaintype_id: attributes.get_typ().clone(), + attributes: attributes.get_items().to_vec(), + } + } + + // Create a prototypical agent from its IRI, we can only determine external_id + pub fn exists(namespace_id: NamespaceId, id: ActivityId) -> Self { + Self { + namespace_id, + external_id: id.external_id_part().to_owned(), + id, + started: None, + ended: None, + domaintype_id: None, + attributes: Vec::new(), + } + } } #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Entity { - pub id: EntityId, - pub namespace_id: NamespaceId, - pub external_id: ExternalId, - pub domaintypeid: Option, - pub attributes: Vec, + pub id: EntityId, + pub namespace_id: NamespaceId, + pub external_id: ExternalId, + pub domaintypeid: Option, + pub attributes: Vec, } impl Entity { - pub fn has_attributes(self, attributes: Attributes) -> Self { - let Self { id, namespace_id: namespaceid, external_id, .. } = self; - Self { - id, - namespace_id: namespaceid, - external_id, - domaintypeid: attributes.get_typ().clone(), - attributes: attributes.get_items().to_vec(), - } - } - - pub fn exists(namespaceid: NamespaceId, id: EntityId) -> Self { - Self { - external_id: id.external_id_part().to_owned(), - id, - namespace_id: namespaceid, - domaintypeid: None, - attributes: Vec::new(), - } - } + pub fn has_attributes(self, attributes: Attributes) -> Self { + let Self { id, namespace_id: namespaceid, external_id, .. } = self; + Self { + id, + namespace_id: namespaceid, + external_id, + domaintypeid: attributes.get_typ().clone(), + attributes: attributes.get_items().to_vec(), + } + } + + pub fn exists(namespaceid: NamespaceId, id: EntityId) -> Self { + Self { + external_id: id.external_id_part().to_owned(), + id, + namespace_id: namespaceid, + domaintypeid: None, + attributes: Vec::new(), + } + } } #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)] #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] pub struct Derivation { - pub generated_id: EntityId, - pub used_id: EntityId, - pub activity_id: Option, - pub typ: DerivationType, + pub generated_id: EntityId, + pub used_id: EntityId, + pub activity_id: Option, + pub typ: DerivationType, } #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)] #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] pub struct Delegation { - pub namespace_id: NamespaceId, - pub id: DelegationId, - pub delegate_id: AgentId, - pub responsible_id: AgentId, - pub activity_id: Option, - pub role: Option, + pub namespace_id: NamespaceId, + pub id: DelegationId, + pub delegate_id: AgentId, + pub responsible_id: AgentId, + pub activity_id: Option, + pub role: Option, } impl Delegation { - pub fn new( - namespace_id: &NamespaceId, - delegate_id: &AgentId, - responsible_id: &AgentId, - activity_id: Option<&ActivityId>, - role: Option, - ) -> Self { - Self { - namespace_id: namespace_id.clone(), - id: DelegationId::from_component_ids( - delegate_id, - responsible_id, - activity_id, - role.as_ref(), - ), - delegate_id: delegate_id.clone(), - responsible_id: responsible_id.clone(), - activity_id: activity_id.cloned(), - role, - } - } + pub fn new( + namespace_id: &NamespaceId, + delegate_id: &AgentId, + responsible_id: &AgentId, + activity_id: Option<&ActivityId>, + role: Option, + ) -> Self { + Self { + namespace_id: namespace_id.clone(), + id: DelegationId::from_component_ids( + delegate_id, + responsible_id, + activity_id, + role.as_ref(), + ), + delegate_id: delegate_id.clone(), + responsible_id: responsible_id.clone(), + activity_id: activity_id.cloned(), + role, + } + } } #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)] #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] - pub struct Association { - pub namespace_id: NamespaceId, - pub id: AssociationId, - pub agent_id: AgentId, - pub activity_id: ActivityId, - pub role: Option, + pub namespace_id: NamespaceId, + pub id: AssociationId, + pub agent_id: AgentId, + pub activity_id: ActivityId, + pub role: Option, } impl Association { - pub fn new( - namespace_id: &NamespaceId, - agent_id: &AgentId, - activity_id: &ActivityId, - role: Option, - ) -> Self { - Self { - namespace_id: namespace_id.clone(), - id: AssociationId::from_component_ids(agent_id, activity_id, role.as_ref()), - agent_id: agent_id.clone(), - activity_id: activity_id.clone(), - role, - } - } + pub fn new( + namespace_id: &NamespaceId, + agent_id: &AgentId, + activity_id: &ActivityId, + role: Option, + ) -> Self { + Self { + namespace_id: namespace_id.clone(), + id: AssociationId::from_component_ids(agent_id, activity_id, role.as_ref()), + agent_id: agent_id.clone(), + activity_id: activity_id.clone(), + role, + } + } } #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)] #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] pub struct Usage { - pub activity_id: ActivityId, - pub entity_id: EntityId, + pub activity_id: ActivityId, + pub entity_id: EntityId, } #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)] #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] pub struct Generation { - pub activity_id: ActivityId, - pub generated_id: EntityId, + pub activity_id: ActivityId, + pub generated_id: EntityId, } #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] pub struct GeneratedEntity { - pub entity_id: EntityId, - pub generated_id: ActivityId, + pub entity_id: EntityId, + pub generated_id: ActivityId, } #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)] #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] pub struct Attribution { - pub namespace_id: NamespaceId, - pub id: AttributionId, - pub agent_id: AgentId, - pub entity_id: EntityId, - pub role: Option, + pub namespace_id: NamespaceId, + pub id: AttributionId, + pub agent_id: AgentId, + pub entity_id: EntityId, + pub role: Option, } impl Attribution { - pub fn new( - namespace_id: &NamespaceId, - agent_id: &AgentId, - entity_id: &EntityId, - role: Option, - ) -> Self { - Self { - namespace_id: namespace_id.clone(), - id: AttributionId::from_component_ids(agent_id, entity_id, role.as_ref()), - agent_id: agent_id.clone(), - entity_id: entity_id.clone(), - role, - } - } + pub fn new( + namespace_id: &NamespaceId, + agent_id: &AgentId, + entity_id: &EntityId, + role: Option, + ) -> Self { + Self { + namespace_id: namespace_id.clone(), + id: AttributionId::from_component_ids(agent_id, entity_id, role.as_ref()), + agent_id: agent_id.clone(), + entity_id: entity_id.clone(), + role, + } + } } type NamespacedId = (NamespaceId, T); @@ -561,721 +561,747 @@ type NamespacedAgent = NamespacedId; type NamespacedEntity = NamespacedId; type NamespacedActivity = NamespacedId; -#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)] + +#[derive(Debug, Default, Clone, Copy)] pub struct ProvSummary { - pub total_agents: usize, - pub total_entities: usize, - pub total_activities: usize, - pub total_attributions: usize, - pub total_derivations: usize, - pub total_generations: usize, - pub total_usages: usize, - pub total_associations: usize, - pub total_delegations: usize, + pub total_agents: usize, + pub total_entities: usize, + pub total_activities: usize, + pub total_attributions: usize, + pub total_derivations: usize, + pub total_generations: usize, + pub total_usages: usize, + pub total_associations: usize, + pub total_delegations: usize, } +use std::fmt; + +impl fmt::Display for ProvSummary { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{{ total_agents: {}, total_entities: {}, total_activities: {}, total_attributions: {}, total_derivations: {}, total_generations: {}, total_usages: {}, total_associations: {}, total_delegations: {} }}", + self.total_agents, + self.total_entities, + self.total_activities, + self.total_attributions, + self.total_derivations, + self.total_generations, + self.total_usages, + self.total_associations, + self.total_delegations + ) + } +} + + #[cfg_attr( - feature = "parity-encoding", - derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) + feature = "parity-encoding", + derive(scale_info::TypeInfo, parity_scale_codec::Encode, parity_scale_codec::Decode) )] #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct ProvModel { - pub namespaces: BTreeMap>, - pub agents: BTreeMap>, - pub acted_on_behalf_of: BTreeMap>>, - pub delegation: BTreeMap>>, - pub entities: BTreeMap>, - pub derivation: BTreeMap>>, - pub generation: BTreeMap>>, - pub attribution: BTreeMap>>, - pub activities: BTreeMap>, - pub was_informed_by: BTreeMap>>, - pub generated: BTreeMap>>, - pub association: BTreeMap>>, - pub usage: BTreeMap>>, + pub namespaces: BTreeMap>, + pub agents: BTreeMap>, + pub acted_on_behalf_of: BTreeMap>>, + pub delegation: BTreeMap>>, + pub entities: BTreeMap>, + pub derivation: BTreeMap>>, + pub generation: BTreeMap>>, + pub attribution: BTreeMap>>, + pub activities: BTreeMap>, + pub was_informed_by: BTreeMap>>, + pub generated: BTreeMap>>, + pub association: BTreeMap>>, + pub usage: BTreeMap>>, } #[cfg(feature = "parity-encoding")] pub mod provmodel_protocol { - use super::*; - #[derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - Debug, - Default, - Clone, - Serialize, - Deserialize, - PartialEq, - Eq, - )] - pub struct ProvModelV1 { - pub namespaces: BTreeMap>, /* We need NamespaceIdV1 / - * NamespaceV1 etc, recursively - * until there are only primitive - * types */ - pub agents: BTreeMap>, - pub acted_on_behalf_of: BTreeMap>>, - pub delegation: BTreeMap>>, - pub entities: BTreeMap>, - pub derivation: BTreeMap>>, - pub generation: BTreeMap>>, - pub attribution: BTreeMap>>, - pub activities: BTreeMap>, - pub was_informed_by: BTreeMap>>, - pub generated: BTreeMap>>, - pub association: BTreeMap>>, - pub usage: BTreeMap>>, - } - - impl From for ProvModel { - fn from(value: ProvModelV1) -> Self { - ProvModel { - namespaces: value.namespaces, - agents: value.agents, - acted_on_behalf_of: value.acted_on_behalf_of, - delegation: value.delegation, - entities: value.entities, - derivation: value.derivation, - generation: value.generation, - attribution: value.attribution, - activities: value.activities, - was_informed_by: value.was_informed_by, - generated: value.generated, - association: value.association, - usage: value.usage, - } - } - } + use super::*; + + #[derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + Debug, + Default, + Clone, + Serialize, + Deserialize, + PartialEq, + Eq, + )] + pub struct ProvModelV1 { + pub namespaces: BTreeMap>, + /* We need NamespaceIdV1 / + * NamespaceV1 etc, recursively + * until there are only primitive + * types */ + pub agents: BTreeMap>, + pub acted_on_behalf_of: BTreeMap>>, + pub delegation: BTreeMap>>, + pub entities: BTreeMap>, + pub derivation: BTreeMap>>, + pub generation: BTreeMap>>, + pub attribution: BTreeMap>>, + pub activities: BTreeMap>, + pub was_informed_by: BTreeMap>>, + pub generated: BTreeMap>>, + pub association: BTreeMap>>, + pub usage: BTreeMap>>, + } + + impl From for ProvModel { + fn from(value: ProvModelV1) -> Self { + ProvModel { + namespaces: value.namespaces, + agents: value.agents, + acted_on_behalf_of: value.acted_on_behalf_of, + delegation: value.delegation, + entities: value.entities, + derivation: value.derivation, + generation: value.generation, + attribution: value.attribution, + activities: value.activities, + was_informed_by: value.was_informed_by, + generated: value.generated, + association: value.association, + usage: value.usage, + } + } + } } #[cfg(feature = "parity-encoding")] // TODO: We can make these structures reasonably bounded (and copy ids with interning) - though JSON // attributes may need some handwaving impl parity_scale_codec::MaxEncodedLen for ProvModel { - fn max_encoded_len() -> usize { - 64 * 1024usize - } + fn max_encoded_len() -> usize { + 64 * 1024usize + } } impl ProvModel { - pub fn summarize(&self) -> ProvSummary { - ProvSummary { - total_agents: self.agents.len(), - total_entities: self.entities.len(), - total_activities: self.activities.len(), - total_attributions: self - .attribution - .values() - .map(|attributions| attributions.len()) - .sum(), - total_derivations: self.derivation.values().map(|derivations| derivations.len()).sum(), - total_generations: self.generation.values().map(|generations| generations.len()).sum(), - total_usages: self.usage.values().map(|usages| usages.len()).sum(), - total_associations: self - .association - .values() - .map(|associations| associations.len()) - .sum(), - total_delegations: self.delegation.values().map(|delegations| delegations.len()).sum(), - } - } - - /// Merge the supplied ProvModel into this one - pub fn combine(&mut self, other: &ProvModel) { - self.namespaces.extend(other.namespaces.clone()); - self.agents.extend(other.agents.clone()); - self.acted_on_behalf_of.extend(other.acted_on_behalf_of.clone()); - self.delegation.extend(other.delegation.clone()); - self.entities.extend(other.entities.clone()); - self.derivation.extend(other.derivation.clone()); - self.generation.extend(other.generation.clone()); - self.attribution.extend(other.attribution.clone()); - self.activities.extend(other.activities.clone()); - self.was_informed_by.extend(other.was_informed_by.clone()); - self.generated.extend(other.generated.clone()); - self.association.extend(other.association.clone()); - self.usage.extend(other.usage.clone()); - } - - /// Apply a sequence of `ChronicleTransaction` to an empty model, then return it - pub fn from_tx<'a, I>(tx: I) -> Result - where - I: IntoIterator, - { - let mut model = Self::default(); - for tx in tx { - model.apply(tx)?; - } - - Ok(model) - } - - /// Append a derivation to the model - pub fn was_derived_from( - &mut self, - namespace_id: NamespaceId, - typ: DerivationType, - used_id: EntityId, - id: EntityId, - activity_id: Option, - ) { - let derivation_set = - Arc::make_mut(self.derivation.entry((namespace_id, id.clone())).or_default()); - - derivation_set.insert(Derivation { typ, generated_id: id, used_id, activity_id }); - } - - /// Append a delegation to the model - pub fn qualified_delegation( - &mut self, - namespace_id: &NamespaceId, - responsible_id: &AgentId, - delegate_id: &AgentId, - activity_id: Option, - role: Option, - ) { - let delegation = Delegation { - namespace_id: namespace_id.clone(), - id: DelegationId::from_component_ids( - delegate_id, - responsible_id, - activity_id.as_ref(), - role.as_ref(), - ), - responsible_id: responsible_id.clone(), - delegate_id: delegate_id.clone(), - activity_id, - role, - }; - - let delegation_set = Arc::make_mut( - self.delegation - .entry((namespace_id.clone(), responsible_id.clone())) - .or_default(), - ); - delegation_set.insert(delegation.clone()); - - let acted_on_behalf_of_set = Arc::make_mut( - self.acted_on_behalf_of - .entry((namespace_id.clone(), responsible_id.clone())) - .or_default(), - ); - - acted_on_behalf_of_set.insert(delegation); - } - - pub fn qualified_association( - &mut self, - namespace_id: &NamespaceId, - activity_id: &ActivityId, - agent_id: &AgentId, - role: Option, - ) { - let association_set = Arc::make_mut( - self.association.entry((namespace_id.clone(), activity_id.clone())).or_default(), - ); - - association_set.insert(Association { - namespace_id: namespace_id.clone(), - id: AssociationId::from_component_ids(agent_id, activity_id, role.as_ref()), - agent_id: agent_id.clone(), - activity_id: activity_id.clone(), - role, - }); - } - - pub fn was_generated_by( - &mut self, - namespace_id: NamespaceId, - generated_id: &EntityId, - activity_id: &ActivityId, - ) { - let generation_set = Arc::make_mut( - self.generation.entry((namespace_id.clone(), generated_id.clone())).or_default(), - ); - generation_set.insert(Generation { - activity_id: activity_id.clone(), - generated_id: generated_id.clone(), - }); - } - - pub fn generated( - &mut self, - namespace_id: NamespaceId, - generated_id: &ActivityId, - entity_id: &EntityId, - ) { - let generated_set = Arc::make_mut( - self.generated.entry((namespace_id.clone(), generated_id.clone())).or_default(), - ); - - generated_set.insert(GeneratedEntity { - entity_id: entity_id.clone(), - generated_id: generated_id.clone(), - }); - } - - pub fn used( - &mut self, - namespace_id: NamespaceId, - activity_id: &ActivityId, - entity_id: &EntityId, - ) { - let usage_set = Arc::make_mut( - self.usage.entry((namespace_id.clone(), activity_id.clone())).or_default(), - ); - - usage_set.insert(Usage { activity_id: activity_id.clone(), entity_id: entity_id.clone() }); - } - - pub fn was_informed_by( - &mut self, - namespace_id: NamespaceId, - activity_id: &ActivityId, - informing_activity_id: &ActivityId, - ) { - let was_informed_by_set = Arc::make_mut( - self.was_informed_by - .entry((namespace_id.clone(), activity_id.clone())) - .or_default(), - ); - - was_informed_by_set.insert((namespace_id, informing_activity_id.clone())); - } - - pub fn qualified_attribution( - &mut self, - namespace_id: &NamespaceId, - entity_id: &EntityId, - agent_id: &AgentId, - role: Option, - ) { - let attribution_set = Arc::make_mut( - self.attribution.entry((namespace_id.clone(), entity_id.clone())).or_default(), - ); - - attribution_set.insert(Attribution { - namespace_id: namespace_id.clone(), - id: AttributionId::from_component_ids(agent_id, entity_id, role.as_ref()), - agent_id: agent_id.clone(), - entity_id: entity_id.clone(), - role, - }); - } - - /// Ensure we have the referenced namespace in our model - pub fn namespace_context(&mut self, ns: &NamespaceId) { - let (namespace_name, uuid) = (ns.external_id_part(), ns.uuid_part()); - - self.namespaces.insert( - ns.clone(), - Namespace { - id: ns.clone(), - uuid: uuid.into_bytes(), - external_id: namespace_name.to_owned(), - } - .into(), - ); - } - - /// Ensure we have the referenced agent in our model, so that open world - /// assumptions can be made - pub fn agent_context(&mut self, ns: &NamespaceId, agent: &AgentId) { - self.agents - .entry((ns.clone(), agent.clone())) - .or_insert_with(|| Agent::exists(ns.clone(), agent.clone()).into()); - } - - pub fn get_agent(&mut self, ns: &NamespaceId, agent: &AgentId) -> Option<&Agent> { - self.agents.get(&(ns.clone(), agent.clone())).map(|arc| arc.as_ref()) - } - - pub fn modify_agent( - &mut self, - ns: &NamespaceId, - agent: &AgentId, - f: F, - ) { - if let Some(arc) = self.agents.get_mut(&(ns.clone(), agent.clone())) { - let agent: &mut Agent = Arc::make_mut(arc); - f(agent); - } - } - - /// Ensure we have the referenced entity in our model, so that open world - /// assumptions can be made - pub fn entity_context(&mut self, ns: &NamespaceId, entity: &EntityId) { - self.entities - .entry((ns.clone(), entity.clone())) - .or_insert_with(|| Entity::exists(ns.clone(), entity.clone()).into()); - } - - pub fn get_entity(&mut self, ns: &NamespaceId, entity: &EntityId) -> Option<&Entity> { - self.entities.get(&(ns.clone(), entity.clone())).map(|arc| arc.as_ref()) - } - - pub fn modify_entity( - &mut self, - ns: &NamespaceId, - entity: &EntityId, - f: F, - ) { - if let Some(arc) = self.entities.get_mut(&(ns.clone(), entity.clone())) { - let entity: &mut Entity = Arc::make_mut(arc); - f(entity); - } - } - - /// Ensure we have the referenced activity in our model, so that open world - /// assumptions can be made - pub fn activity_context(&mut self, ns: &NamespaceId, activity: &ActivityId) { - self.activities - .entry((ns.clone(), activity.clone())) - .or_insert_with(|| Activity::exists(ns.clone(), activity.clone()).into()); - } - - pub fn get_activity(&mut self, ns: &NamespaceId, activity: &ActivityId) -> Option<&Activity> { - self.activities.get(&(ns.clone(), activity.clone())).map(|arc| arc.as_ref()) - } - - pub fn modify_activity( - &mut self, - ns: &NamespaceId, - activity: &ActivityId, - f: F, - ) { - if let Some(arc) = self.activities.get_mut(&(ns.clone(), activity.clone())) { - let activity: &mut Activity = Arc::make_mut(arc); - f(activity); - } - } - - /// Transform a sequence of `ChronicleOperation` events into a provenance model, - /// If a statement requires a subject or object that does not currently exist in the model, then - /// we create it If an operation contradicts a previous statement, then we record the - /// contradiction, but attempt to apply as much of the operation as possible - #[instrument(skip(self,tx), level = "trace", name="apply_chronicle_operation", fields(op = ?tx, model= ?self), ret(Debug))] - pub fn apply(&mut self, tx: &ChronicleOperation) -> Result<(), Contradiction> { - let tx = tx.to_owned(); - match tx { - ChronicleOperation::CreateNamespace(CreateNamespace { id }) => { - self.namespace_context(&id); - Ok(()) - }, - ChronicleOperation::AgentExists(AgentExists { namespace, id, .. }) => { - self.agent_context(&namespace, &id); - - Ok(()) - }, - ChronicleOperation::AgentActsOnBehalfOf(ActsOnBehalfOf { - id: _, - namespace, - delegate_id, - activity_id, - role, - responsible_id, - }) => { - self.agent_context(&namespace, &delegate_id); - self.agent_context(&namespace, &responsible_id); - - if let Some(activity_id) = activity_id.clone() { - self.activity_context(&namespace, &activity_id); - } - - self.qualified_delegation( - &namespace, - &responsible_id, - &delegate_id, - activity_id, - role, - ); - - Ok(()) - }, - ChronicleOperation::ActivityExists(ActivityExists { namespace, id, .. }) => { - self.activity_context(&namespace, &id); - - Ok(()) - }, - ChronicleOperation::StartActivity(StartActivity { namespace, id, time }) => { - self.activity_context(&namespace, &id); - - let activity = self.get_activity(&namespace, &id); - - trace!(check_start_contradiction = ?time, existing_time=?activity.and_then(|activity| activity.started)); - match ( - activity.and_then(|activity| activity.started), - activity.and_then(|activity| activity.ended), - ) { - (Some(TimeWrapper(started)), _) if started != time.0 => - return Err(Contradiction::start_date_alteration( - id.into(), - namespace, - started, - time.0, - )), - (_, Some(TimeWrapper(ended))) if ended < time.0 => - return Err(Contradiction::invalid_range( - id.into(), - namespace, - time.0, - ended, - )), - _ => {}, - }; - - self.modify_activity(&namespace, &id, move |activity| { - activity.started = Some(time); - }); - - Ok(()) - }, - ChronicleOperation::EndActivity(EndActivity { namespace, id, time }) => { - self.activity_context(&namespace, &id); - - let activity = self.get_activity(&namespace, &id); - - trace!(check_end_contradiction = ?time, existing_time=?activity.and_then(|activity| activity.ended)); - match ( - activity.and_then(|activity| activity.started), - activity.and_then(|activity| activity.ended), - ) { - (_, Some(TimeWrapper(ended))) if ended != time.0 => - return Err(Contradiction::end_date_alteration( - id.into(), - namespace, - ended, - time.0, - )), - (Some(TimeWrapper(started)), _) if started > time.0 => - return Err(Contradiction::invalid_range( - id.into(), - namespace, - started, - time.0, - )), - _ => {}, - }; - - self.modify_activity(&namespace, &id, move |activity| { - activity.ended = Some(time); - }); - - Ok(()) - }, - ChronicleOperation::WasAssociatedWith(WasAssociatedWith { - id: _, - role, - namespace, - activity_id, - agent_id, - }) => { - self.agent_context(&namespace, &agent_id); - self.activity_context(&namespace, &activity_id); - self.qualified_association(&namespace, &activity_id, &agent_id, role); - - Ok(()) - }, - ChronicleOperation::WasAttributedTo(WasAttributedTo { - id: _, - role, - namespace, - entity_id, - agent_id, - }) => { - self.agent_context(&namespace, &agent_id); - self.entity_context(&namespace, &entity_id); - self.qualified_attribution(&namespace, &entity_id, &agent_id, role); - - Ok(()) - }, - ChronicleOperation::ActivityUses(ActivityUses { namespace, id, activity }) => { - self.activity_context(&namespace, &activity); - self.entity_context(&namespace, &id); - - self.used(namespace, &activity, &id); - - Ok(()) - }, - ChronicleOperation::EntityExists(EntityExists { namespace, id, .. }) => { - self.entity_context(&namespace, &id); - Ok(()) - }, - ChronicleOperation::WasGeneratedBy(WasGeneratedBy { namespace, id, activity }) => { - self.entity_context(&namespace, &id); - self.activity_context(&namespace, &activity); - - self.was_generated_by(namespace, &id, &activity); - - Ok(()) - }, - ChronicleOperation::WasInformedBy(WasInformedBy { - namespace, - activity, - informing_activity, - }) => { - self.activity_context(&namespace, &activity); - self.activity_context(&namespace, &informing_activity); - - self.was_informed_by(namespace, &activity, &informing_activity); - - Ok(()) - }, - ChronicleOperation::EntityDerive(EntityDerive { - namespace, - id, - typ, - used_id, - activity_id, - }) => { - self.entity_context(&namespace, &id); - self.entity_context(&namespace, &used_id); - - if let Some(activity_id) = &activity_id { - self.activity_context(&namespace, activity_id); - } - - self.was_derived_from(namespace, typ, used_id, id, activity_id); - - Ok(()) - }, - ChronicleOperation::SetAttributes(SetAttributes::Entity { - namespace, - id, - attributes, - }) => { - self.entity_context(&namespace, &id); - - if let Some(current) = self - .entities - .get(&(namespace.clone(), id.clone())) - .map(|entity| &entity.attributes) - { - Self::validate_attribute_changes( - &id.clone().into(), - &namespace, - current, - &attributes, - )?; - }; - - self.modify_entity(&namespace, &id, move |entity| { - entity.domaintypeid = attributes.get_typ().clone(); - entity.attributes = attributes.get_items().to_vec(); - }); - - Ok(()) - }, - ChronicleOperation::SetAttributes(SetAttributes::Activity { - namespace, - id, - attributes, - }) => { - self.activity_context(&namespace, &id); - - if let Some(current) = self - .activities - .get(&(namespace.clone(), id.clone())) - .map(|activity| &activity.attributes) - { - Self::validate_attribute_changes( - &id.clone().into(), - &namespace, - current, - &attributes, - )?; - }; - - self.modify_activity(&namespace, &id, move |activity| { - activity.domaintype_id = attributes.get_typ().clone(); - activity.attributes = attributes.get_items().to_vec(); - }); - - Ok(()) - }, - ChronicleOperation::SetAttributes(SetAttributes::Agent { - namespace, - id, - attributes, - }) => { - self.agent_context(&namespace, &id); - - if let Some(current) = - self.agents.get(&(namespace.clone(), id.clone())).map(|agent| &agent.attributes) - { - Self::validate_attribute_changes( - &id.clone().into(), - &namespace, - current, - &attributes, - )?; - }; - - self.modify_agent(&namespace, &id, move |agent| { - agent.domaintypeid = attributes.get_typ().clone(); - agent.attributes = attributes.get_items().to_vec(); - }); - - Ok(()) - }, - } - } - - /// Allow additional attributes, but changing an existing attribute is not allowed - #[instrument(level = "trace", ret(Debug))] - fn validate_attribute_changes( - id: &ChronicleIri, - namespace: &NamespaceId, - current: &Vec, - attempted: &Attributes, - ) -> Result<(), Contradiction> { - let current_map: BTreeMap = - current.iter().map(|attr| (attr.typ.clone(), attr)).collect(); - let contradictions = attempted - .get_items() - .iter() - .filter_map(|attempted_attr| { - current_map.get(&attempted_attr.typ).and_then(|¤t_attr| { - if attempted_attr != current_attr { - Some(( - attempted_attr.typ.clone(), - attempted_attr.clone(), - (*current_attr).clone(), - )) - } else { - None - } - }) - }) - .collect::>(); - - if contradictions.is_empty() { - Ok(()) - } else { - Err(Contradiction::attribute_value_change( - id.clone(), - namespace.clone(), - contradictions, - )) - } - } - - #[cfg(feature = "json-ld")] - pub(crate) fn add_agent(&mut self, agent: Agent) { - self.agents.insert((agent.namespaceid.clone(), agent.id.clone()), agent.into()); - } - - #[cfg(feature = "json-ld")] - pub(crate) fn add_activity(&mut self, activity: Activity) { - self.activities - .insert((activity.namespace_id.clone(), activity.id.clone()), activity.into()); - } - - #[cfg(feature = "json-ld")] - pub(crate) fn add_entity(&mut self, entity: Entity) { - self.entities - .insert((entity.namespace_id.clone(), entity.id.clone()), entity.into()); - } + pub fn summarize(&self) -> ProvSummary { + ProvSummary { + total_agents: self.agents.len(), + total_entities: self.entities.len(), + total_activities: self.activities.len(), + total_attributions: self + .attribution + .values() + .map(|attributions| attributions.len()) + .sum(), + total_derivations: self.derivation.values().map(|derivations| derivations.len()).sum(), + total_generations: self.generation.values().map(|generations| generations.len()).sum(), + total_usages: self.usage.values().map(|usages| usages.len()).sum(), + total_associations: self + .association + .values() + .map(|associations| associations.len()) + .sum(), + total_delegations: self.delegation.values().map(|delegations| delegations.len()).sum(), + } + } + + /// Merge the supplied ProvModel into this one + pub fn combine(&mut self, other: &ProvModel) { + self.namespaces.extend(other.namespaces.clone()); + self.agents.extend(other.agents.clone()); + self.acted_on_behalf_of.extend(other.acted_on_behalf_of.clone()); + self.delegation.extend(other.delegation.clone()); + self.entities.extend(other.entities.clone()); + self.derivation.extend(other.derivation.clone()); + self.generation.extend(other.generation.clone()); + self.attribution.extend(other.attribution.clone()); + self.activities.extend(other.activities.clone()); + self.was_informed_by.extend(other.was_informed_by.clone()); + self.generated.extend(other.generated.clone()); + self.association.extend(other.association.clone()); + self.usage.extend(other.usage.clone()); + } + + /// Apply a sequence of `ChronicleTransaction` to an empty model, then return it + pub fn from_tx<'a, I>(tx: I) -> Result + where + I: IntoIterator, + { + let mut model = Self::default(); + for tx in tx { + model.apply(tx)?; + } + + Ok(model) + } + + /// Append a derivation to the model + pub fn was_derived_from( + &mut self, + namespace_id: NamespaceId, + typ: DerivationType, + used_id: EntityId, + id: EntityId, + activity_id: Option, + ) { + let derivation_set = + Arc::make_mut(self.derivation.entry((namespace_id, id.clone())).or_default()); + + derivation_set.insert(Derivation { typ, generated_id: id, used_id, activity_id }); + } + + /// Append a delegation to the model + pub fn qualified_delegation( + &mut self, + namespace_id: &NamespaceId, + responsible_id: &AgentId, + delegate_id: &AgentId, + activity_id: Option, + role: Option, + ) { + let delegation = Delegation { + namespace_id: namespace_id.clone(), + id: DelegationId::from_component_ids( + delegate_id, + responsible_id, + activity_id.as_ref(), + role.as_ref(), + ), + responsible_id: responsible_id.clone(), + delegate_id: delegate_id.clone(), + activity_id, + role, + }; + + let delegation_set = Arc::make_mut( + self.delegation + .entry((namespace_id.clone(), responsible_id.clone())) + .or_default(), + ); + delegation_set.insert(delegation.clone()); + + let acted_on_behalf_of_set = Arc::make_mut( + self.acted_on_behalf_of + .entry((namespace_id.clone(), responsible_id.clone())) + .or_default(), + ); + + acted_on_behalf_of_set.insert(delegation); + } + + pub fn qualified_association( + &mut self, + namespace_id: &NamespaceId, + activity_id: &ActivityId, + agent_id: &AgentId, + role: Option, + ) { + let association_set = Arc::make_mut( + self.association.entry((namespace_id.clone(), activity_id.clone())).or_default(), + ); + + association_set.insert(Association { + namespace_id: namespace_id.clone(), + id: AssociationId::from_component_ids(agent_id, activity_id, role.as_ref()), + agent_id: agent_id.clone(), + activity_id: activity_id.clone(), + role, + }); + } + + pub fn was_generated_by( + &mut self, + namespace_id: NamespaceId, + generated_id: &EntityId, + activity_id: &ActivityId, + ) { + let generation_set = Arc::make_mut( + self.generation.entry((namespace_id.clone(), generated_id.clone())).or_default(), + ); + generation_set.insert(Generation { + activity_id: activity_id.clone(), + generated_id: generated_id.clone(), + }); + } + + pub fn generated( + &mut self, + namespace_id: NamespaceId, + generated_id: &ActivityId, + entity_id: &EntityId, + ) { + let generated_set = Arc::make_mut( + self.generated.entry((namespace_id.clone(), generated_id.clone())).or_default(), + ); + + generated_set.insert(GeneratedEntity { + entity_id: entity_id.clone(), + generated_id: generated_id.clone(), + }); + } + + pub fn used( + &mut self, + namespace_id: NamespaceId, + activity_id: &ActivityId, + entity_id: &EntityId, + ) { + let usage_set = Arc::make_mut( + self.usage.entry((namespace_id.clone(), activity_id.clone())).or_default(), + ); + + usage_set.insert(Usage { activity_id: activity_id.clone(), entity_id: entity_id.clone() }); + } + + pub fn was_informed_by( + &mut self, + namespace_id: NamespaceId, + activity_id: &ActivityId, + informing_activity_id: &ActivityId, + ) { + let was_informed_by_set = Arc::make_mut( + self.was_informed_by + .entry((namespace_id.clone(), activity_id.clone())) + .or_default(), + ); + + was_informed_by_set.insert((namespace_id, informing_activity_id.clone())); + } + + pub fn qualified_attribution( + &mut self, + namespace_id: &NamespaceId, + entity_id: &EntityId, + agent_id: &AgentId, + role: Option, + ) { + let attribution_set = Arc::make_mut( + self.attribution.entry((namespace_id.clone(), entity_id.clone())).or_default(), + ); + + attribution_set.insert(Attribution { + namespace_id: namespace_id.clone(), + id: AttributionId::from_component_ids(agent_id, entity_id, role.as_ref()), + agent_id: agent_id.clone(), + entity_id: entity_id.clone(), + role, + }); + } + + /// Ensure we have the referenced namespace in our model + pub fn namespace_context(&mut self, ns: &NamespaceId) { + let (namespace_name, uuid) = (ns.external_id_part(), ns.uuid_part()); + + self.namespaces.insert( + ns.clone(), + Namespace { + id: ns.clone(), + uuid: uuid.into_bytes(), + external_id: namespace_name.to_owned(), + } + .into(), + ); + } + + /// Ensure we have the referenced agent in our model, so that open world + /// assumptions can be made + pub fn agent_context(&mut self, ns: &NamespaceId, agent: &AgentId) { + self.agents + .entry((ns.clone(), agent.clone())) + .or_insert_with(|| Agent::exists(ns.clone(), agent.clone()).into()); + } + + pub fn get_agent(&mut self, ns: &NamespaceId, agent: &AgentId) -> Option<&Agent> { + self.agents.get(&(ns.clone(), agent.clone())).map(|arc| arc.as_ref()) + } + + pub fn modify_agent( + &mut self, + ns: &NamespaceId, + agent: &AgentId, + f: F, + ) { + if let Some(arc) = self.agents.get_mut(&(ns.clone(), agent.clone())) { + let agent: &mut Agent = Arc::make_mut(arc); + f(agent); + } + } + + /// Ensure we have the referenced entity in our model, so that open world + /// assumptions can be made + pub fn entity_context(&mut self, ns: &NamespaceId, entity: &EntityId) { + self.entities + .entry((ns.clone(), entity.clone())) + .or_insert_with(|| Entity::exists(ns.clone(), entity.clone()).into()); + } + + pub fn get_entity(&mut self, ns: &NamespaceId, entity: &EntityId) -> Option<&Entity> { + self.entities.get(&(ns.clone(), entity.clone())).map(|arc| arc.as_ref()) + } + + pub fn modify_entity( + &mut self, + ns: &NamespaceId, + entity: &EntityId, + f: F, + ) { + if let Some(arc) = self.entities.get_mut(&(ns.clone(), entity.clone())) { + let entity: &mut Entity = Arc::make_mut(arc); + f(entity); + } + } + + /// Ensure we have the referenced activity in our model, so that open world + /// assumptions can be made + pub fn activity_context(&mut self, ns: &NamespaceId, activity: &ActivityId) { + self.activities + .entry((ns.clone(), activity.clone())) + .or_insert_with(|| Activity::exists(ns.clone(), activity.clone()).into()); + } + + pub fn get_activity(&mut self, ns: &NamespaceId, activity: &ActivityId) -> Option<&Activity> { + self.activities.get(&(ns.clone(), activity.clone())).map(|arc| arc.as_ref()) + } + + pub fn modify_activity( + &mut self, + ns: &NamespaceId, + activity: &ActivityId, + f: F, + ) { + if let Some(arc) = self.activities.get_mut(&(ns.clone(), activity.clone())) { + let activity: &mut Activity = Arc::make_mut(arc); + f(activity); + } + } + + /// Transform a sequence of `ChronicleOperation` events into a provenance model, + /// If a statement requires a subject or object that does not currently exist in the model, then + /// we create it If an operation contradicts a previous statement, then we record the + /// contradiction, but attempt to apply as much of the operation as possible + #[instrument(skip(self, tx), level = "trace", name = "apply_chronicle_operation", fields( + op = ? tx, model = ? self + ), ret(Debug))] + pub fn apply(&mut self, tx: &ChronicleOperation) -> Result<(), Contradiction> { + let tx = tx.to_owned(); + match tx { + ChronicleOperation::CreateNamespace(CreateNamespace { id }) => { + self.namespace_context(&id); + Ok(()) + } + ChronicleOperation::AgentExists(AgentExists { namespace, id, .. }) => { + self.agent_context(&namespace, &id); + + Ok(()) + } + ChronicleOperation::AgentActsOnBehalfOf(ActsOnBehalfOf { + id: _, + namespace, + delegate_id, + activity_id, + role, + responsible_id, + }) => { + self.agent_context(&namespace, &delegate_id); + self.agent_context(&namespace, &responsible_id); + + if let Some(activity_id) = activity_id.clone() { + self.activity_context(&namespace, &activity_id); + } + + self.qualified_delegation( + &namespace, + &responsible_id, + &delegate_id, + activity_id, + role, + ); + + Ok(()) + } + ChronicleOperation::ActivityExists(ActivityExists { namespace, id, .. }) => { + self.activity_context(&namespace, &id); + + Ok(()) + } + ChronicleOperation::StartActivity(StartActivity { namespace, id, time }) => { + self.activity_context(&namespace, &id); + + let activity = self.get_activity(&namespace, &id); + + trace!(check_start_contradiction = ?time, existing_time=?activity.and_then(|activity| activity.started)); + match ( + activity.and_then(|activity| activity.started), + activity.and_then(|activity| activity.ended), + ) { + (Some(TimeWrapper(started)), _) if started != time.0 => + return Err(Contradiction::start_date_alteration( + id.into(), + namespace, + started, + time.0, + )), + (_, Some(TimeWrapper(ended))) if ended < time.0 => + return Err(Contradiction::invalid_range( + id.into(), + namespace, + time.0, + ended, + )), + _ => {} + }; + + self.modify_activity(&namespace, &id, move |activity| { + activity.started = Some(time); + }); + + Ok(()) + } + ChronicleOperation::EndActivity(EndActivity { namespace, id, time }) => { + self.activity_context(&namespace, &id); + + let activity = self.get_activity(&namespace, &id); + + trace!(check_end_contradiction = ?time, existing_time=?activity.and_then(|activity| activity.ended)); + match ( + activity.and_then(|activity| activity.started), + activity.and_then(|activity| activity.ended), + ) { + (_, Some(TimeWrapper(ended))) if ended != time.0 => + return Err(Contradiction::end_date_alteration( + id.into(), + namespace, + ended, + time.0, + )), + (Some(TimeWrapper(started)), _) if started > time.0 => + return Err(Contradiction::invalid_range( + id.into(), + namespace, + started, + time.0, + )), + _ => {} + }; + + self.modify_activity(&namespace, &id, move |activity| { + activity.ended = Some(time); + }); + + Ok(()) + } + ChronicleOperation::WasAssociatedWith(WasAssociatedWith { + id: _, + role, + namespace, + activity_id, + agent_id, + }) => { + self.agent_context(&namespace, &agent_id); + self.activity_context(&namespace, &activity_id); + self.qualified_association(&namespace, &activity_id, &agent_id, role); + + Ok(()) + } + ChronicleOperation::WasAttributedTo(WasAttributedTo { + id: _, + role, + namespace, + entity_id, + agent_id, + }) => { + self.agent_context(&namespace, &agent_id); + self.entity_context(&namespace, &entity_id); + self.qualified_attribution(&namespace, &entity_id, &agent_id, role); + + Ok(()) + } + ChronicleOperation::ActivityUses(ActivityUses { namespace, id, activity }) => { + self.activity_context(&namespace, &activity); + self.entity_context(&namespace, &id); + + self.used(namespace, &activity, &id); + + Ok(()) + } + ChronicleOperation::EntityExists(EntityExists { namespace, id, .. }) => { + self.entity_context(&namespace, &id); + Ok(()) + } + ChronicleOperation::WasGeneratedBy(WasGeneratedBy { namespace, id, activity }) => { + self.entity_context(&namespace, &id); + self.activity_context(&namespace, &activity); + + self.was_generated_by(namespace, &id, &activity); + + Ok(()) + } + ChronicleOperation::WasInformedBy(WasInformedBy { + namespace, + activity, + informing_activity, + }) => { + self.activity_context(&namespace, &activity); + self.activity_context(&namespace, &informing_activity); + + self.was_informed_by(namespace, &activity, &informing_activity); + + Ok(()) + } + ChronicleOperation::EntityDerive(EntityDerive { + namespace, + id, + typ, + used_id, + activity_id, + }) => { + self.entity_context(&namespace, &id); + self.entity_context(&namespace, &used_id); + + if let Some(activity_id) = &activity_id { + self.activity_context(&namespace, activity_id); + } + + self.was_derived_from(namespace, typ, used_id, id, activity_id); + + Ok(()) + } + ChronicleOperation::SetAttributes(SetAttributes::Entity { + namespace, + id, + attributes, + }) => { + self.entity_context(&namespace, &id); + + if let Some(current) = self + .entities + .get(&(namespace.clone(), id.clone())) + .map(|entity| &entity.attributes) + { + Self::validate_attribute_changes( + &id.clone().into(), + &namespace, + current, + &attributes, + )?; + }; + + self.modify_entity(&namespace, &id, move |entity| { + entity.domaintypeid = attributes.get_typ().clone(); + entity.attributes = attributes.get_items().to_vec(); + }); + + Ok(()) + } + ChronicleOperation::SetAttributes(SetAttributes::Activity { + namespace, + id, + attributes, + }) => { + self.activity_context(&namespace, &id); + + if let Some(current) = self + .activities + .get(&(namespace.clone(), id.clone())) + .map(|activity| &activity.attributes) + { + Self::validate_attribute_changes( + &id.clone().into(), + &namespace, + current, + &attributes, + )?; + }; + + self.modify_activity(&namespace, &id, move |activity| { + activity.domaintype_id = attributes.get_typ().clone(); + activity.attributes = attributes.get_items().to_vec(); + }); + + Ok(()) + } + ChronicleOperation::SetAttributes(SetAttributes::Agent { + namespace, + id, + attributes, + }) => { + self.agent_context(&namespace, &id); + + if let Some(current) = + self.agents.get(&(namespace.clone(), id.clone())).map(|agent| &agent.attributes) + { + Self::validate_attribute_changes( + &id.clone().into(), + &namespace, + current, + &attributes, + )?; + }; + + self.modify_agent(&namespace, &id, move |agent| { + agent.domaintypeid = attributes.get_typ().clone(); + agent.attributes = attributes.get_items().to_vec(); + }); + + Ok(()) + } + } + } + + /// Allow additional attributes, but changing an existing attribute is not allowed + #[instrument(level = "trace", ret(Debug))] + fn validate_attribute_changes( + id: &ChronicleIri, + namespace: &NamespaceId, + current: &Vec, + attempted: &Attributes, + ) -> Result<(), Contradiction> { + let current_map: BTreeMap = + current.iter().map(|attr| (attr.typ.clone(), attr)).collect(); + let contradictions = attempted + .get_items() + .iter() + .filter_map(|attempted_attr| { + current_map.get(&attempted_attr.typ).and_then(|¤t_attr| { + if attempted_attr != current_attr { + Some(( + attempted_attr.typ.clone(), + attempted_attr.clone(), + (*current_attr).clone(), + )) + } else { + None + } + }) + }) + .collect::>(); + + if contradictions.is_empty() { + Ok(()) + } else { + Err(Contradiction::attribute_value_change( + id.clone(), + namespace.clone(), + contradictions, + )) + } + } + + #[cfg(feature = "json-ld")] + pub(crate) fn add_agent(&mut self, agent: Agent) { + self.agents.insert((agent.namespaceid.clone(), agent.id.clone()), agent.into()); + } + + #[cfg(feature = "json-ld")] + pub(crate) fn add_activity(&mut self, activity: Activity) { + self.activities + .insert((activity.namespace_id.clone(), activity.id.clone()), activity.into()); + } + + #[cfg(feature = "json-ld")] + pub(crate) fn add_entity(&mut self, entity: Entity) { + self.entities + .insert((entity.namespace_id.clone(), entity.id.clone()), entity.into()); + } } diff --git a/crates/common/src/prov/model/proptest.rs b/crates/common/src/prov/model/proptest.rs index 650107ca1..2a6553f99 100644 --- a/crates/common/src/prov/model/proptest.rs +++ b/crates/common/src/prov/model/proptest.rs @@ -1,15 +1,14 @@ use chrono::Utc; use proptest::{option, prelude::*}; - use uuid::Uuid; use crate::{ - attributes::{Attribute, Attributes}, - prov::{ - json_ld::ToJson, operations::*, ActivityId, AgentId, Association, AssociationId, - Attribution, Contradiction, Delegation, DelegationId, Derivation, DomaintypeId, EntityId, - ExternalId, ExternalIdPart, Generation, NamespaceId, ProvModel, Role, Usage, UuidPart, - }, + attributes::{Attribute, Attributes}, + prov::{ + ActivityId, AgentId, Association, AssociationId, Attribution, Contradiction, + Delegation, DelegationId, Derivation, DomaintypeId, EntityId, ExternalId, ExternalIdPart, + Generation, json_ld::ToJson, NamespaceId, operations::*, ProvModel, Role, Usage, UuidPart, + }, }; use super::{ActivityUses, ActsOnBehalfOf, EntityDerive, StartActivity}; @@ -290,8 +289,8 @@ prop_compose! { } } -fn transaction() -> impl Strategy { - prop_oneof![ +fn transaction() -> impl Strategy { + prop_oneof![ 1 => create_agent().prop_map(ChronicleOperation::AgentExists), 1 => create_activity().prop_map(ChronicleOperation::ActivityExists), 1 => start_activity().prop_map(ChronicleOperation::StartActivity), @@ -308,8 +307,8 @@ fn transaction() -> impl Strategy { ] } -fn operation_seq() -> impl Strategy> { - proptest::collection::vec(transaction(), 1..50) +fn operation_seq() -> impl Strategy> { + proptest::collection::vec(transaction(), 1..50) } proptest! { diff --git a/crates/common/src/prov/operations.rs b/crates/common/src/prov/operations.rs index 9e2826893..e2e90c779 100644 --- a/crates/common/src/prov/operations.rs +++ b/crates/common/src/prov/operations.rs @@ -2,834 +2,836 @@ use chrono::{DateTime, NaiveDateTime, TimeZone, Utc}; #[cfg(feature = "diesel-bindings")] use diesel::{ - self, - backend::Backend, - deserialize::FromSql, - serialize::{Output, ToSql}, - sql_types::Integer, - AsExpression, QueryId, SqlType, + self, + backend::Backend, + deserialize::FromSql, + serialize::{Output, ToSql}, + sql_types::Integer, + AsExpression, QueryId, SqlType, }; #[cfg(not(feature = "std"))] use parity_scale_codec::alloc::string::String; #[cfg(not(feature = "std"))] -use scale_info::prelude::{vec::Vec,vec}; +use scale_info::prelude::{vec::Vec, vec}; use crate::attributes::Attributes; use super::{ - ActivityId, AgentId, AssociationId, AttributionId, DelegationId, EntityId, NamespaceId, Role, + ActivityId, AgentId, AssociationId, AttributionId, DelegationId, EntityId, NamespaceId, Role, }; #[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash, Serialize, Deserialize)] #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[cfg_attr(feature = "diesel-bindings", derive(AsExpression, SqlType, QueryId))] #[cfg_attr(feature = "diesel-bindings", diesel(sql_type = Integer))] #[repr(i32)] pub enum DerivationType { - None, - Revision, - Quotation, - PrimarySource, + None, + Revision, + Quotation, + PrimarySource, } #[cfg(feature = "diesel-bindings")] mod bindings { - use super::*; - impl ToSql for DerivationType - where - DB: Backend, - i32: ToSql, - { - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result { - match self { - DerivationType::None => (-1).to_sql(out), - DerivationType::Revision => 1.to_sql(out), - DerivationType::Quotation => 2.to_sql(out), - DerivationType::PrimarySource => 3.to_sql(out), - } - } - } - - impl FromSql for DerivationType - where - DB: Backend, - i32: FromSql, - { - fn from_sql(bytes: ::RawValue<'_>) -> diesel::deserialize::Result { - match i32::from_sql(bytes)? { - -1 => Ok(DerivationType::None), - 1 => Ok(DerivationType::Revision), - 2 => Ok(DerivationType::Quotation), - 3 => Ok(DerivationType::PrimarySource), - _ => Err("Unrecognized enum variant".into()), - } - } - } + use super::*; + + impl ToSql for DerivationType + where + DB: Backend, + i32: ToSql, + { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result { + match self { + DerivationType::None => (-1).to_sql(out), + DerivationType::Revision => 1.to_sql(out), + DerivationType::Quotation => 2.to_sql(out), + DerivationType::PrimarySource => 3.to_sql(out), + } + } + } + + impl FromSql for DerivationType + where + DB: Backend, + i32: FromSql, + { + fn from_sql(bytes: ::RawValue<'_>) -> diesel::deserialize::Result { + match i32::from_sql(bytes)? { + -1 => Ok(DerivationType::None), + 1 => Ok(DerivationType::Revision), + 2 => Ok(DerivationType::Quotation), + 3 => Ok(DerivationType::PrimarySource), + _ => Err("Unrecognized enum variant".into()), + } + } + } } impl TryFrom for DerivationType { - type Error = &'static str; + type Error = &'static str; - fn try_from(value: i32) -> Result { - match value { - -1 => Ok(DerivationType::None), - 1 => Ok(DerivationType::Revision), - 2 => Ok(DerivationType::Quotation), - 3 => Ok(DerivationType::PrimarySource), - _ => Err("Unrecognized enum variant when converting from 'i32'"), - } - } + fn try_from(value: i32) -> Result { + match value { + -1 => Ok(DerivationType::None), + 1 => Ok(DerivationType::Revision), + 2 => Ok(DerivationType::Quotation), + 3 => Ok(DerivationType::PrimarySource), + _ => Err("Unrecognized enum variant when converting from 'i32'"), + } + } } impl DerivationType { - pub fn revision() -> Self { - Self::Revision - } + pub fn revision() -> Self { + Self::Revision + } - pub fn quotation() -> Self { - Self::Quotation - } + pub fn quotation() -> Self { + Self::Quotation + } - pub fn primary_source() -> Self { - Self::PrimarySource - } + pub fn primary_source() -> Self { + Self::PrimarySource + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct CreateNamespace { - pub id: NamespaceId, + pub id: NamespaceId, } impl CreateNamespace { - pub fn new(id: NamespaceId) -> Self { - Self { id } - } + pub fn new(id: NamespaceId) -> Self { + Self { id } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct AgentExists { - pub namespace: NamespaceId, - pub id: AgentId, + pub namespace: NamespaceId, + pub id: AgentId, } impl AgentExists { - pub fn new(namespace: NamespaceId, id: AgentId) -> Self { - Self { namespace, id } - } + pub fn new(namespace: NamespaceId, id: AgentId) -> Self { + Self { namespace, id } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct ActsOnBehalfOf { - pub id: DelegationId, - pub role: Option, - pub activity_id: Option, - pub responsible_id: AgentId, - pub delegate_id: AgentId, - pub namespace: NamespaceId, + pub id: DelegationId, + pub role: Option, + pub activity_id: Option, + pub responsible_id: AgentId, + pub delegate_id: AgentId, + pub namespace: NamespaceId, } impl ActsOnBehalfOf { - pub fn new( - namespace: NamespaceId, - responsible_id: AgentId, - delegate_id: AgentId, - activity_id: Option, - role: Option, - ) -> Self { - Self { - namespace, - id: DelegationId::from_component_ids( - &delegate_id, - &responsible_id, - activity_id.as_ref(), - role.as_ref(), - ), - role, - activity_id, - responsible_id, - delegate_id, - } - } + pub fn new( + namespace: NamespaceId, + responsible_id: AgentId, + delegate_id: AgentId, + activity_id: Option, + role: Option, + ) -> Self { + Self { + namespace, + id: DelegationId::from_component_ids( + &delegate_id, + &responsible_id, + activity_id.as_ref(), + role.as_ref(), + ), + role, + activity_id, + responsible_id, + delegate_id, + } + } } + #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct ActivityExists { - pub namespace: NamespaceId, - pub id: ActivityId, + pub namespace: NamespaceId, + pub id: ActivityId, } impl ActivityExists { - pub fn new(namespace: NamespaceId, id: ActivityId) -> Self { - Self { namespace, id } - } + pub fn new(namespace: NamespaceId, id: ActivityId) -> Self { + Self { namespace, id } + } } #[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug)] pub struct TimeWrapper(pub DateTime); impl TimeWrapper { - pub fn to_rfc3339(&self) -> String { - self.0.to_rfc3339() - } + pub fn to_rfc3339(&self) -> String { + self.0.to_rfc3339() + } - pub fn naive_utc(&self) -> NaiveDateTime { - self.0.naive_utc() - } + pub fn naive_utc(&self) -> NaiveDateTime { + self.0.naive_utc() + } } impl core::fmt::Display for TimeWrapper { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.0.to_rfc3339()) - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.0.to_rfc3339()) + } } impl From> for TimeWrapper { - fn from(dt: DateTime) -> Self { - TimeWrapper(dt) - } + fn from(dt: DateTime) -> Self { + TimeWrapper(dt) + } } #[cfg(feature = "parity-encoding")] impl scale_encode::EncodeAsType for TimeWrapper { - fn encode_as_type_to( - &self, - type_id: u32, - types: &scale_info::PortableRegistry, - out: &mut scale_encode::Vec, - ) -> Result<(), scale_encode::Error> { - let timestamp = self.0.timestamp(); - let subsec_nanos = self.0.timestamp_subsec_nanos(); - (timestamp, subsec_nanos).encode_as_type_to(type_id, types, out) - } + fn encode_as_type_to( + &self, + type_id: u32, + types: &scale_info::PortableRegistry, + out: &mut scale_encode::Vec, + ) -> Result<(), scale_encode::Error> { + let timestamp = self.0.timestamp(); + let subsec_nanos = self.0.timestamp_subsec_nanos(); + (timestamp, subsec_nanos).encode_as_type_to(type_id, types, out) + } } #[cfg(feature = "parity-encoding")] impl parity_scale_codec::Encode for TimeWrapper { - fn encode_to(&self, dest: &mut T) { - let timestamp = self.0.timestamp(); - let subsec_nanos = self.0.timestamp_subsec_nanos(); - (timestamp, subsec_nanos).encode_to(dest); - } + fn encode_to(&self, dest: &mut T) { + let timestamp = self.0.timestamp(); + let subsec_nanos = self.0.timestamp_subsec_nanos(); + (timestamp, subsec_nanos).encode_to(dest); + } } #[cfg(feature = "parity-encoding")] impl parity_scale_codec::Decode for TimeWrapper { - fn decode( - input: &mut I, - ) -> Result { - let (timestamp, subsec_nanos) = <(i64, u32)>::decode(input)?; + fn decode( + input: &mut I, + ) -> Result { + let (timestamp, subsec_nanos) = <(i64, u32)>::decode(input)?; - let datetime = - Utc.timestamp_opt(timestamp, subsec_nanos).single().ok_or("Invalid timestamp")?; + let datetime = + Utc.timestamp_opt(timestamp, subsec_nanos).single().ok_or("Invalid timestamp")?; - Ok(Self(datetime)) - } + Ok(Self(datetime)) + } } #[cfg(feature = "parity-encoding")] impl scale_info::TypeInfo for TimeWrapper { - type Identity = Self; + type Identity = Self; - fn type_info() -> scale_info::Type { - scale_info::Type::builder() - .path(scale_info::Path::new("TimeWrapper", module_path!())) - .composite( - scale_info::build::Fields::unnamed() - .field(|f| f.ty::().type_name("Timestamp")) - .field(|f| f.ty::().type_name("SubsecNanos")), - ) - } + fn type_info() -> scale_info::Type { + scale_info::Type::builder() + .path(scale_info::Path::new("TimeWrapper", module_path!())) + .composite( + scale_info::build::Fields::unnamed() + .field(|f| f.ty::().type_name("Timestamp")) + .field(|f| f.ty::().type_name("SubsecNanos")), + ) + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct StartActivity { - pub namespace: NamespaceId, - pub id: ActivityId, - pub time: TimeWrapper, + pub namespace: NamespaceId, + pub id: ActivityId, + pub time: TimeWrapper, } impl StartActivity { - pub fn new(namespace: NamespaceId, id: ActivityId, time: DateTime) -> Self { - Self { namespace, id, time: TimeWrapper(time) } - } + pub fn new(namespace: NamespaceId, id: ActivityId, time: DateTime) -> Self { + Self { namespace, id, time: TimeWrapper(time) } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct EndActivity { - pub namespace: NamespaceId, - pub id: ActivityId, - pub time: TimeWrapper, + pub namespace: NamespaceId, + pub id: ActivityId, + pub time: TimeWrapper, } impl EndActivity { - pub fn new(namespace: NamespaceId, id: ActivityId, time: DateTime) -> Self { - Self { namespace, id, time: TimeWrapper(time) } - } + pub fn new(namespace: NamespaceId, id: ActivityId, time: DateTime) -> Self { + Self { namespace, id, time: TimeWrapper(time) } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct ActivityUses { - pub namespace: NamespaceId, - pub id: EntityId, - pub activity: ActivityId, + pub namespace: NamespaceId, + pub id: EntityId, + pub activity: ActivityId, } impl ActivityUses { - /// Creates a new `ActivityUses` instance. - /// - /// # Arguments - /// - /// * `namespace` - The namespace identifier for the activity. - /// * `id` - The unique identifier for the entity being used. - /// * `activity` - The unique identifier for the activity using the entity. - pub fn new(namespace: NamespaceId, id: EntityId, activity: ActivityId) -> Self { - Self { namespace, id, activity } - } + /// Creates a new `ActivityUses` instance. + /// + /// # Arguments + /// + /// * `namespace` - The namespace identifier for the activity. + /// * `id` - The unique identifier for the entity being used. + /// * `activity` - The unique identifier for the activity using the entity. + pub fn new(namespace: NamespaceId, id: EntityId, activity: ActivityId) -> Self { + Self { namespace, id, activity } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct EntityExists { - pub namespace: NamespaceId, - pub id: EntityId, + pub namespace: NamespaceId, + pub id: EntityId, } impl EntityExists { - /// Creates a new `EntityExists` instance. - /// - /// # Arguments - /// - /// * `namespace` - The namespace identifier for the entity. - /// * `id` - The identifier for the entity. - #[tracing::instrument(skip(namespace, id), fields(namespace = %namespace, entity_id = %id))] - pub fn new(namespace: NamespaceId, id: EntityId) -> Self { - Self { namespace, id } - } + /// Creates a new `EntityExists` instance. + /// + /// # Arguments + /// + /// * `namespace` - The namespace identifier for the entity. + /// * `id` - The identifier for the entity. + #[tracing::instrument(skip(namespace, id), fields(namespace = % namespace, entity_id = % id))] + pub fn new(namespace: NamespaceId, id: EntityId) -> Self { + Self { namespace, id } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct WasGeneratedBy { - pub namespace: NamespaceId, - pub id: EntityId, - pub activity: ActivityId, + pub namespace: NamespaceId, + pub id: EntityId, + pub activity: ActivityId, } impl WasGeneratedBy { - /// Creates a new `WasGeneratedBy` instance. - /// - /// # Arguments - /// - /// * `namespace` - The namespace identifier for the entity. - /// * `id` - The unique identifier for the entity. - /// * `activity` - The identifier for the activity that generated the entity. - pub fn new(namespace: NamespaceId, id: EntityId, activity: ActivityId) -> Self { - Self { namespace, id, activity } - } + /// Creates a new `WasGeneratedBy` instance. + /// + /// # Arguments + /// + /// * `namespace` - The namespace identifier for the entity. + /// * `id` - The unique identifier for the entity. + /// * `activity` - The identifier for the activity that generated the entity. + pub fn new(namespace: NamespaceId, id: EntityId, activity: ActivityId) -> Self { + Self { namespace, id, activity } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct EntityDerive { - pub namespace: NamespaceId, - pub id: EntityId, - pub used_id: EntityId, - pub activity_id: Option, - pub typ: DerivationType, + pub namespace: NamespaceId, + pub id: EntityId, + pub used_id: EntityId, + pub activity_id: Option, + pub typ: DerivationType, } impl EntityDerive { - /// Creates a new `EntityDerive` instance. - /// - /// # Arguments - /// - /// * `namespace` - The namespace identifier for the entity. - /// * `id` - The unique identifier for the entity. - /// * `used_id` - The identifier for the entity that was used. - /// * `activity_id` - The identifier for the activity that derived the entity, if any. - /// * `typ` - The type of derivation. - pub fn new( - namespace: NamespaceId, - id: EntityId, - used_id: EntityId, - activity_id: Option, - typ: DerivationType, - ) -> Self { - Self { namespace, id, used_id, activity_id, typ } - } + /// Creates a new `EntityDerive` instance. + /// + /// # Arguments + /// + /// * `namespace` - The namespace identifier for the entity. + /// * `id` - The unique identifier for the entity. + /// * `used_id` - The identifier for the entity that was used. + /// * `activity_id` - The identifier for the activity that derived the entity, if any. + /// * `typ` - The type of derivation. + pub fn new( + namespace: NamespaceId, + id: EntityId, + used_id: EntityId, + activity_id: Option, + typ: DerivationType, + ) -> Self { + Self { namespace, id, used_id, activity_id, typ } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct WasAssociatedWith { - pub id: AssociationId, - pub role: Option, - pub namespace: NamespaceId, - pub activity_id: ActivityId, - pub agent_id: AgentId, + pub id: AssociationId, + pub role: Option, + pub namespace: NamespaceId, + pub activity_id: ActivityId, + pub agent_id: AgentId, } impl WasAssociatedWith { - pub fn new( - namespace: NamespaceId, - activity_id: ActivityId, - agent_id: AgentId, - role: Option, - ) -> Self { - Self { - id: AssociationId::from_component_ids(&agent_id, &activity_id, role.as_ref()), - role, - namespace, - activity_id, - agent_id, - } - } + pub fn new( + namespace: NamespaceId, + activity_id: ActivityId, + agent_id: AgentId, + role: Option, + ) -> Self { + Self { + id: AssociationId::from_component_ids(&agent_id, &activity_id, role.as_ref()), + role, + namespace, + activity_id, + agent_id, + } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct WasAttributedTo { - pub id: AttributionId, - pub role: Option, - pub namespace: NamespaceId, - pub entity_id: EntityId, - pub agent_id: AgentId, + pub id: AttributionId, + pub role: Option, + pub namespace: NamespaceId, + pub entity_id: EntityId, + pub agent_id: AgentId, } impl WasAttributedTo { - #[tracing::instrument(skip(namespace, role))] - pub fn new( - namespace: NamespaceId, - entity_id: EntityId, - agent_id: AgentId, - role: Option, - ) -> Self { - Self { - id: AttributionId::from_component_ids(&agent_id, &entity_id, role.as_ref()), - role, - namespace, - entity_id, - agent_id, - } - } + #[tracing::instrument(skip(namespace, role))] + pub fn new( + namespace: NamespaceId, + entity_id: EntityId, + agent_id: AgentId, + role: Option, + ) -> Self { + Self { + id: AttributionId::from_component_ids(&agent_id, &entity_id, role.as_ref()), + role, + namespace, + entity_id, + agent_id, + } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub struct WasInformedBy { - pub namespace: NamespaceId, - pub activity: ActivityId, - pub informing_activity: ActivityId, + pub namespace: NamespaceId, + pub activity: ActivityId, + pub informing_activity: ActivityId, } impl WasInformedBy { - /// Creates a new `WasInformedBy` instance. - /// - /// # Arguments - /// - /// * `namespace` - The namespace identifier for the activity. - /// * `activity` - The ActivityId for the activity that was informed. - /// * `informing_activity` - The ActivityId for the informing activity. - pub fn new( - namespace: NamespaceId, - activity: ActivityId, - informing_activity: ActivityId, - ) -> Self { - Self { namespace, activity, informing_activity } - } + /// Creates a new `WasInformedBy` instance. + /// + /// # Arguments + /// + /// * `namespace` - The namespace identifier for the activity. + /// * `activity` - The ActivityId for the activity that was informed. + /// * `informing_activity` - The ActivityId for the informing activity. + pub fn new( + namespace: NamespaceId, + activity: ActivityId, + informing_activity: ActivityId, + ) -> Self { + Self { namespace, activity, informing_activity } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub enum SetAttributes { - Entity { namespace: NamespaceId, id: EntityId, attributes: Attributes }, - Agent { namespace: NamespaceId, id: AgentId, attributes: Attributes }, - Activity { namespace: NamespaceId, id: ActivityId, attributes: Attributes }, + Entity { namespace: NamespaceId, id: EntityId, attributes: Attributes }, + Agent { namespace: NamespaceId, id: AgentId, attributes: Attributes }, + Activity { namespace: NamespaceId, id: ActivityId, attributes: Attributes }, } impl SetAttributes { - pub fn agent(namespace: NamespaceId, id: AgentId, attributes: Attributes) -> Self { - SetAttributes::Agent { namespace, id, attributes } - } + pub fn agent(namespace: NamespaceId, id: AgentId, attributes: Attributes) -> Self { + SetAttributes::Agent { namespace, id, attributes } + } - pub fn entity(namespace: NamespaceId, id: EntityId, attributes: Attributes) -> Self { - SetAttributes::Entity { namespace, id, attributes } - } + pub fn entity(namespace: NamespaceId, id: EntityId, attributes: Attributes) -> Self { + SetAttributes::Entity { namespace, id, attributes } + } - pub fn activity(namespace: NamespaceId, id: ActivityId, attributes: Attributes) -> Self { - SetAttributes::Activity { namespace, id, attributes } - } + pub fn activity(namespace: NamespaceId, id: ActivityId, attributes: Attributes) -> Self { + SetAttributes::Activity { namespace, id, attributes } + } } #[cfg_attr( - feature = "parity-encoding", - derive( - scale_info::TypeInfo, - parity_scale_codec::Encode, - parity_scale_codec::Decode, - scale_encode::EncodeAsType - ) + feature = "parity-encoding", + derive( + scale_info::TypeInfo, + parity_scale_codec::Encode, + parity_scale_codec::Decode, + scale_encode::EncodeAsType + ) )] #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] pub enum ChronicleOperation { - CreateNamespace(CreateNamespace), - AgentExists(AgentExists), - AgentActsOnBehalfOf(ActsOnBehalfOf), - ActivityExists(ActivityExists), - StartActivity(StartActivity), - EndActivity(EndActivity), - ActivityUses(ActivityUses), - EntityExists(EntityExists), - WasGeneratedBy(WasGeneratedBy), - EntityDerive(EntityDerive), - SetAttributes(SetAttributes), - WasAssociatedWith(WasAssociatedWith), - WasAttributedTo(WasAttributedTo), - WasInformedBy(WasInformedBy), + CreateNamespace(CreateNamespace), + AgentExists(AgentExists), + AgentActsOnBehalfOf(ActsOnBehalfOf), + ActivityExists(ActivityExists), + StartActivity(StartActivity), + EndActivity(EndActivity), + ActivityUses(ActivityUses), + EntityExists(EntityExists), + WasGeneratedBy(WasGeneratedBy), + EntityDerive(EntityDerive), + SetAttributes(SetAttributes), + WasAssociatedWith(WasAssociatedWith), + WasAttributedTo(WasAttributedTo), + WasInformedBy(WasInformedBy), } impl ChronicleOperation { - #[tracing::instrument] - #[tracing::instrument] - pub fn create_namespace(id: NamespaceId) -> Self { - ChronicleOperation::CreateNamespace(CreateNamespace::new(id)) - } - - #[tracing::instrument] - pub fn agent_exists(namespace: NamespaceId, id: AgentId) -> Self { - ChronicleOperation::AgentExists(AgentExists::new(namespace, id)) - } - - #[tracing::instrument] - pub fn agent_acts_on_behalf_of( - namespace: NamespaceId, - responsible_id: AgentId, - delegate_id: AgentId, - activity_id: Option, - role: Option, - ) -> Self { - ChronicleOperation::AgentActsOnBehalfOf(ActsOnBehalfOf::new( - namespace, - responsible_id, - delegate_id, - activity_id, - role, - )) - } - - #[tracing::instrument] - pub fn activity_exists(namespace: NamespaceId, id: ActivityId) -> Self { - ChronicleOperation::ActivityExists(ActivityExists::new(namespace, id)) - } - - #[tracing::instrument] - pub fn start_activity( - namespace: NamespaceId, - id: ActivityId, - start_time: DateTime, - ) -> Self { - ChronicleOperation::StartActivity(StartActivity::new(namespace, id, start_time)) - } - - #[tracing::instrument] - pub fn end_activity(namespace: NamespaceId, id: ActivityId, end_time: DateTime) -> Self { - ChronicleOperation::EndActivity(EndActivity::new(namespace, id, end_time)) - } - - #[tracing::instrument] - pub fn activity_used( - namespace: NamespaceId, - activity_id: ActivityId, - entity_id: EntityId, - ) -> Self { - ChronicleOperation::ActivityUses(ActivityUses::new(namespace, entity_id, activity_id)) - } - - #[tracing::instrument] - pub fn entity_exists(namespace: NamespaceId, id: EntityId) -> Self { - ChronicleOperation::EntityExists(EntityExists::new(namespace, id)) - } - - #[tracing::instrument] - pub fn was_generated_by( - namespace: NamespaceId, - entity_id: EntityId, - activity_id: ActivityId, - ) -> Self { - ChronicleOperation::WasGeneratedBy(WasGeneratedBy::new(namespace, entity_id, activity_id)) - } - - pub fn entity_derive( - namespace: NamespaceId, - source_id: EntityId, - target_id: EntityId, - activity_id: Option, - derivation_type: DerivationType, - ) -> Self { - ChronicleOperation::EntityDerive(EntityDerive::new( - namespace, - source_id, - target_id, - activity_id, - derivation_type, - )) - } - - pub fn set_attributes(set_attributes: SetAttributes) -> Self { - ChronicleOperation::SetAttributes(set_attributes) - } - - #[tracing::instrument] - pub fn was_associated_with( - namespace: NamespaceId, - activity_id: ActivityId, - agent_id: AgentId, - role: Option, - ) -> Self { - ChronicleOperation::WasAssociatedWith(WasAssociatedWith::new( - namespace, - activity_id, - agent_id, - role, - )) - } - - pub fn was_attributed_to( - namespace: NamespaceId, - entity_id: EntityId, - agent_id: AgentId, - role: Option, - ) -> Self { - ChronicleOperation::WasAttributedTo(WasAttributedTo::new( - namespace, entity_id, agent_id, role, - )) - } - - #[tracing::instrument] - pub fn was_informed_by( - namespace: NamespaceId, - informed: ActivityId, - informant: ActivityId, - ) -> Self { - ChronicleOperation::WasInformedBy(WasInformedBy::new(namespace, informed, informant)) - } - - /// Returns a reference to the `NamespaceId` of the `ChronicleOperation` - pub fn namespace(&self) -> &NamespaceId { - match self { - ChronicleOperation::ActivityExists(o) => &o.namespace, - ChronicleOperation::AgentExists(o) => &o.namespace, - ChronicleOperation::AgentActsOnBehalfOf(o) => &o.namespace, - ChronicleOperation::CreateNamespace(o) => &o.id, - ChronicleOperation::StartActivity(o) => &o.namespace, - ChronicleOperation::EndActivity(o) => &o.namespace, - ChronicleOperation::ActivityUses(o) => &o.namespace, - ChronicleOperation::EntityExists(o) => &o.namespace, - ChronicleOperation::WasGeneratedBy(o) => &o.namespace, - ChronicleOperation::EntityDerive(o) => &o.namespace, - ChronicleOperation::SetAttributes(o) => match o { - SetAttributes::Activity { namespace, .. } => namespace, - SetAttributes::Agent { namespace, .. } => namespace, - SetAttributes::Entity { namespace, .. } => namespace, - }, - ChronicleOperation::WasAssociatedWith(o) => &o.namespace, - ChronicleOperation::WasAttributedTo(o) => &o.namespace, - ChronicleOperation::WasInformedBy(o) => &o.namespace, - } - } - - // Chronicle is open world, so the use of an id implies that it exists. Match an operation and - // return the implied existential operations. - pub fn implied_by(&self) -> Vec { - match self { - ChronicleOperation::AgentActsOnBehalfOf(o) => vec![ - ChronicleOperation::agent_exists(o.namespace.clone(), o.delegate_id.clone()), - ChronicleOperation::agent_exists(o.namespace.clone(), o.responsible_id.clone()), - ], - ChronicleOperation::StartActivity(o) => { - vec![ChronicleOperation::activity_exists(o.namespace.clone(), o.id.clone())] - }, - ChronicleOperation::EndActivity(o) => { - vec![ChronicleOperation::activity_exists(o.namespace.clone(), o.id.clone())] - }, - ChronicleOperation::ActivityUses(o) => vec![ - ChronicleOperation::activity_exists(o.namespace.clone(), o.activity.clone()), - ChronicleOperation::entity_exists(o.namespace.clone(), o.id.clone()), - ], - ChronicleOperation::EntityExists(o) => { - vec![ChronicleOperation::entity_exists(o.namespace.clone(), o.id.clone())] - }, - ChronicleOperation::WasGeneratedBy(o) => vec![ - ChronicleOperation::entity_exists(o.namespace.clone(), o.id.clone()), - ChronicleOperation::activity_exists(o.namespace.clone(), o.activity.clone()), - ], - ChronicleOperation::EntityDerive(o) => { - let mut ops = vec![ - ChronicleOperation::entity_exists(o.namespace.clone(), o.id.clone()), - ChronicleOperation::entity_exists(o.namespace.clone(), o.used_id.clone()), - ]; - if let Some(activity_id) = &o.activity_id { - ops.push(ChronicleOperation::activity_exists( - o.namespace.clone(), - activity_id.clone(), - )); - } - ops - }, - ChronicleOperation::SetAttributes(o) => match o { - SetAttributes::Activity { namespace, id, .. } => { - vec![ChronicleOperation::activity_exists(namespace.clone(), id.clone())] - }, - SetAttributes::Agent { namespace, id, .. } => { - vec![ChronicleOperation::agent_exists(namespace.clone(), id.clone())] - }, - SetAttributes::Entity { namespace, id, .. } => { - vec![ChronicleOperation::entity_exists(namespace.clone(), id.clone())] - }, - }, - ChronicleOperation::WasAssociatedWith(o) => vec![ - ChronicleOperation::activity_exists(o.namespace.clone(), o.activity_id.clone()), - ChronicleOperation::agent_exists(o.namespace.clone(), o.agent_id.clone()), - ], - ChronicleOperation::WasAttributedTo(o) => vec![ - ChronicleOperation::entity_exists(o.namespace.clone(), o.entity_id.clone()), - ChronicleOperation::agent_exists(o.namespace.clone(), o.agent_id.clone()), - ], - ChronicleOperation::WasInformedBy(o) => vec![ - ChronicleOperation::activity_exists(o.namespace.clone(), o.activity.clone()), - ChronicleOperation::activity_exists( - o.namespace.clone(), - o.informing_activity.clone(), - ), - ], - _ => vec![], - } - } + #[tracing::instrument] + #[tracing::instrument] + pub fn create_namespace(id: NamespaceId) -> Self { + ChronicleOperation::CreateNamespace(CreateNamespace::new(id)) + } + + #[tracing::instrument] + pub fn agent_exists(namespace: NamespaceId, id: AgentId) -> Self { + ChronicleOperation::AgentExists(AgentExists::new(namespace, id)) + } + + #[tracing::instrument] + pub fn agent_acts_on_behalf_of( + namespace: NamespaceId, + responsible_id: AgentId, + delegate_id: AgentId, + activity_id: Option, + role: Option, + ) -> Self { + ChronicleOperation::AgentActsOnBehalfOf(ActsOnBehalfOf::new( + namespace, + responsible_id, + delegate_id, + activity_id, + role, + )) + } + + #[tracing::instrument] + pub fn activity_exists(namespace: NamespaceId, id: ActivityId) -> Self { + ChronicleOperation::ActivityExists(ActivityExists::new(namespace, id)) + } + + #[tracing::instrument] + pub fn start_activity( + namespace: NamespaceId, + id: ActivityId, + start_time: DateTime, + ) -> Self { + ChronicleOperation::StartActivity(StartActivity::new(namespace, id, start_time)) + } + + #[tracing::instrument] + pub fn end_activity(namespace: NamespaceId, id: ActivityId, end_time: DateTime) -> Self { + ChronicleOperation::EndActivity(EndActivity::new(namespace, id, end_time)) + } + + #[tracing::instrument] + pub fn activity_used( + namespace: NamespaceId, + activity_id: ActivityId, + entity_id: EntityId, + ) -> Self { + ChronicleOperation::ActivityUses(ActivityUses::new(namespace, entity_id, activity_id)) + } + + #[tracing::instrument] + pub fn entity_exists(namespace: NamespaceId, id: EntityId) -> Self { + ChronicleOperation::EntityExists(EntityExists::new(namespace, id)) + } + + #[tracing::instrument] + pub fn was_generated_by( + namespace: NamespaceId, + entity_id: EntityId, + activity_id: ActivityId, + ) -> Self { + ChronicleOperation::WasGeneratedBy(WasGeneratedBy::new(namespace, entity_id, activity_id)) + } + + pub fn entity_derive( + namespace: NamespaceId, + source_id: EntityId, + target_id: EntityId, + activity_id: Option, + derivation_type: DerivationType, + ) -> Self { + ChronicleOperation::EntityDerive(EntityDerive::new( + namespace, + source_id, + target_id, + activity_id, + derivation_type, + )) + } + + pub fn set_attributes(set_attributes: SetAttributes) -> Self { + ChronicleOperation::SetAttributes(set_attributes) + } + + #[tracing::instrument] + pub fn was_associated_with( + namespace: NamespaceId, + activity_id: ActivityId, + agent_id: AgentId, + role: Option, + ) -> Self { + ChronicleOperation::WasAssociatedWith(WasAssociatedWith::new( + namespace, + activity_id, + agent_id, + role, + )) + } + + pub fn was_attributed_to( + namespace: NamespaceId, + entity_id: EntityId, + agent_id: AgentId, + role: Option, + ) -> Self { + ChronicleOperation::WasAttributedTo(WasAttributedTo::new( + namespace, entity_id, agent_id, role, + )) + } + + #[tracing::instrument] + pub fn was_informed_by( + namespace: NamespaceId, + informed: ActivityId, + informant: ActivityId, + ) -> Self { + ChronicleOperation::WasInformedBy(WasInformedBy::new(namespace, informed, informant)) + } + + /// Returns a reference to the `NamespaceId` of the `ChronicleOperation` + pub fn namespace(&self) -> &NamespaceId { + match self { + ChronicleOperation::ActivityExists(o) => &o.namespace, + ChronicleOperation::AgentExists(o) => &o.namespace, + ChronicleOperation::AgentActsOnBehalfOf(o) => &o.namespace, + ChronicleOperation::CreateNamespace(o) => &o.id, + ChronicleOperation::StartActivity(o) => &o.namespace, + ChronicleOperation::EndActivity(o) => &o.namespace, + ChronicleOperation::ActivityUses(o) => &o.namespace, + ChronicleOperation::EntityExists(o) => &o.namespace, + ChronicleOperation::WasGeneratedBy(o) => &o.namespace, + ChronicleOperation::EntityDerive(o) => &o.namespace, + ChronicleOperation::SetAttributes(o) => match o { + SetAttributes::Activity { namespace, .. } => namespace, + SetAttributes::Agent { namespace, .. } => namespace, + SetAttributes::Entity { namespace, .. } => namespace, + }, + ChronicleOperation::WasAssociatedWith(o) => &o.namespace, + ChronicleOperation::WasAttributedTo(o) => &o.namespace, + ChronicleOperation::WasInformedBy(o) => &o.namespace, + } + } + + // Chronicle is open world, so the use of an id implies that it exists. Match an operation and + // return the implied existential operations. + pub fn implied_by(&self) -> Vec { + match self { + ChronicleOperation::AgentActsOnBehalfOf(o) => vec![ + ChronicleOperation::agent_exists(o.namespace.clone(), o.delegate_id.clone()), + ChronicleOperation::agent_exists(o.namespace.clone(), o.responsible_id.clone()), + ], + ChronicleOperation::StartActivity(o) => { + vec![ChronicleOperation::activity_exists(o.namespace.clone(), o.id.clone())] + } + ChronicleOperation::EndActivity(o) => { + vec![ChronicleOperation::activity_exists(o.namespace.clone(), o.id.clone())] + } + ChronicleOperation::ActivityUses(o) => vec![ + ChronicleOperation::activity_exists(o.namespace.clone(), o.activity.clone()), + ChronicleOperation::entity_exists(o.namespace.clone(), o.id.clone()), + ], + ChronicleOperation::EntityExists(o) => { + vec![ChronicleOperation::entity_exists(o.namespace.clone(), o.id.clone())] + } + ChronicleOperation::WasGeneratedBy(o) => vec![ + ChronicleOperation::entity_exists(o.namespace.clone(), o.id.clone()), + ChronicleOperation::activity_exists(o.namespace.clone(), o.activity.clone()), + ], + ChronicleOperation::EntityDerive(o) => { + let mut ops = vec![ + ChronicleOperation::entity_exists(o.namespace.clone(), o.id.clone()), + ChronicleOperation::entity_exists(o.namespace.clone(), o.used_id.clone()), + ]; + if let Some(activity_id) = &o.activity_id { + ops.push(ChronicleOperation::activity_exists( + o.namespace.clone(), + activity_id.clone(), + )); + } + ops + } + ChronicleOperation::SetAttributes(o) => match o { + SetAttributes::Activity { namespace, id, .. } => { + vec![ChronicleOperation::activity_exists(namespace.clone(), id.clone())] + } + SetAttributes::Agent { namespace, id, .. } => { + vec![ChronicleOperation::agent_exists(namespace.clone(), id.clone())] + } + SetAttributes::Entity { namespace, id, .. } => { + vec![ChronicleOperation::entity_exists(namespace.clone(), id.clone())] + } + }, + ChronicleOperation::WasAssociatedWith(o) => vec![ + ChronicleOperation::activity_exists(o.namespace.clone(), o.activity_id.clone()), + ChronicleOperation::agent_exists(o.namespace.clone(), o.agent_id.clone()), + ], + ChronicleOperation::WasAttributedTo(o) => vec![ + ChronicleOperation::entity_exists(o.namespace.clone(), o.entity_id.clone()), + ChronicleOperation::agent_exists(o.namespace.clone(), o.agent_id.clone()), + ], + ChronicleOperation::WasInformedBy(o) => vec![ + ChronicleOperation::activity_exists(o.namespace.clone(), o.activity.clone()), + ChronicleOperation::activity_exists( + o.namespace.clone(), + o.informing_activity.clone(), + ), + ], + _ => vec![], + } + } } diff --git a/crates/common/src/prov/vocab.rs b/crates/common/src/prov/vocab.rs index 8bd8a4b53..bd0e982f8 100644 --- a/crates/common/src/prov/vocab.rs +++ b/crates/common/src/prov/vocab.rs @@ -1,315 +1,312 @@ -mod chronicle_operations { - - #[derive(Clone, Copy, PartialEq, Eq, Hash)] - pub enum ChronicleOperation { - CreateNamespace, - NamespaceName, - NamespaceUuid, - AgentExists, - AgentName, - AgentUuid, - AgentActsOnBehalfOf, - DelegateId, - ResponsibleId, - ActivityExists, - ActivityName, - StartActivity, - StartActivityTime, - EndActivity, - EndActivityTime, - WasAssociatedWith, - WasAttributedTo, - ActivityUses, - EntityName, - Locator, - Role, - EntityExists, - WasGeneratedBy, - EntityDerive, - DerivationType, - UsedEntityName, - SetAttributes, - Attributes, - Attribute, - DomaintypeId, - WasInformedBy, - InformingActivityName, - Generated, - } - - const ACTIVITY_EXISTS: &str = "http://chronicle.works/chronicleoperations/ns#ActivityExists"; - const ACTIVITY_NAME: &str = "http://chronicle.works/chronicleoperations/ns#ActivityName"; - const START_ACTIVITY: &str = "http://chronicle.works/chronicleoperations/ns#StartActivity"; - const START_ACTIVITY_TIME: &str = - "http://chronicle.works/chronicleoperations/ns#StartActivityTime"; - const END_ACTIVITY: &str = "http://chronicle.works/chronicleoperations/ns#EndActivity"; - const END_ACTIVITY_TIME: &str = "http://chronicle.works/chronicleoperations/ns#EndActivityTime"; - const WAS_ASSOCIATED_WITH: &str = - "http://chronicle.works/chronicleoperations/ns#WasAssociatedWith"; - const WAS_ATTRIBUTED_TO: &str = "http://chronicle.works/chronicleoperations/ns#WasAttributedTo"; - const ACTIVITY_USES: &str = "http://chronicle.works/chronicleoperations/ns#ActivityUses"; - const ENTITY_NAME: &str = "http://chronicle.works/chronicleoperations/ns#EntityName"; - const LOCATOR: &str = "http://chronicle.works/chronicleoperations/ns#Locator"; - const ROLE: &str = "http://chronicle.works/chronicleoperations/ns#Role"; - const ENTITY_EXISTS: &str = "http://chronicle.works/chronicleoperations/ns#EntityExists"; - const WAS_GENERATED_BY: &str = "http://chronicle.works/chronicleoperations/ns#WasGeneratedBy"; - const ENTITY_DERIVE: &str = "http://chronicle.works/chronicleoperations/ns#EntityDerive"; - const DERIVATION_TYPE: &str = "http://chronicle.works/chronicleoperations/ns#DerivationType"; - const USED_ENTITY_NAME: &str = "http://chronicle.works/chronicleoperations/ns#UsedEntityName"; - const SET_ATTRIBUTES: &str = "http://chronicle.works/chronicleoperations/ns#SetAttributes"; - const ATTRIBUTES: &str = "http://chronicle.works/chronicleoperations/ns#Attributes"; - const ATTRIBUTE: &str = "http://chronicle.works/chronicleoperations/ns#Attribute"; - const DOMAINTYPE_ID: &str = "http://chronicle.works/chronicleoperations/ns#DomaintypeId"; - const WAS_INFORMED_BY: &str = "http://chronicle.works/chronicleoperations/ns#WasInformedBy"; - const INFORMING_ACTIVITY_NAME: &str = - "http://chronicle.works/chronicleoperations/ns#InformingActivityName"; - const GENERATED: &str = "http://chronicle.works/chronicleoperations/ns#Generated"; - const CREATE_NAMESPACE: &str = "http://chronicle.works/chronicleoperations/ns#CreateNamespace"; - const NAMESPACE_NAME: &str = "http://chronicle.works/chronicleoperations/ns#namespaceName"; - const NAMESPACE_UUID: &str = "http://chronicle.works/chronicleoperations/ns#namespaceUuid"; - const AGENT_EXISTS: &str = "http://chronicle.works/chronicleoperations/ns#AgentExists"; - const AGENT_NAME: &str = "http://chronicle.works/chronicleoperations/ns#agentName"; - const AGENT_UUID: &str = "http://chronicle.works/chronicleoperations/ns#agentUuid"; - const AGENT_ACTS_ON_BEHALF_OF: &str = - "http://chronicle.works/chronicleoperations/ns#AgentActsOnBehalfOf"; - const DELEGATE_ID: &str = "http://chronicle.works/chronicleoperations/ns#delegateId"; - const RESPONSIBLE_ID: &str = "http://chronicle.works/chronicleoperations/ns#responsibleId"; - - impl AsRef for ChronicleOperation { - fn as_ref(&self) -> &'static str { - match self { - ChronicleOperation::ActivityExists => ACTIVITY_EXISTS, - ChronicleOperation::ActivityName => ACTIVITY_NAME, - ChronicleOperation::StartActivity => START_ACTIVITY, - ChronicleOperation::StartActivityTime => START_ACTIVITY_TIME, - ChronicleOperation::EndActivity => END_ACTIVITY, - ChronicleOperation::EndActivityTime => END_ACTIVITY_TIME, - ChronicleOperation::WasAssociatedWith => WAS_ASSOCIATED_WITH, - ChronicleOperation::WasAttributedTo => WAS_ATTRIBUTED_TO, - ChronicleOperation::ActivityUses => ACTIVITY_USES, - ChronicleOperation::EntityName => ENTITY_NAME, - ChronicleOperation::Locator => LOCATOR, - ChronicleOperation::Role => ROLE, - ChronicleOperation::EntityExists => ENTITY_EXISTS, - ChronicleOperation::WasGeneratedBy => WAS_GENERATED_BY, - ChronicleOperation::EntityDerive => ENTITY_DERIVE, - ChronicleOperation::DerivationType => DERIVATION_TYPE, - ChronicleOperation::UsedEntityName => USED_ENTITY_NAME, - ChronicleOperation::SetAttributes => SET_ATTRIBUTES, - ChronicleOperation::Attributes => ATTRIBUTES, - ChronicleOperation::Attribute => ATTRIBUTE, - ChronicleOperation::DomaintypeId => DOMAINTYPE_ID, - ChronicleOperation::WasInformedBy => WAS_INFORMED_BY, - ChronicleOperation::InformingActivityName => INFORMING_ACTIVITY_NAME, - ChronicleOperation::Generated => GENERATED, - ChronicleOperation::CreateNamespace => CREATE_NAMESPACE, - ChronicleOperation::NamespaceName => NAMESPACE_NAME, - ChronicleOperation::NamespaceUuid => NAMESPACE_UUID, - ChronicleOperation::AgentExists => AGENT_EXISTS, - ChronicleOperation::AgentName => AGENT_NAME, - ChronicleOperation::AgentUuid => AGENT_UUID, - ChronicleOperation::AgentActsOnBehalfOf => AGENT_ACTS_ON_BEHALF_OF, - ChronicleOperation::DelegateId => DELEGATE_ID, - ChronicleOperation::ResponsibleId => RESPONSIBLE_ID, - } - } - } - - #[cfg(feature = "json-ld")] - impl From for iri_string::types::IriString { - fn from(val: ChronicleOperation) -> Self { - use iri_string::types::UriString; - UriString::try_from(val.as_str().to_string()).unwrap().into() - } - } - - impl ChronicleOperation { - pub fn as_str(&self) -> &str { - self.as_ref() - } - } +pub use chronicle::*; +pub use chronicle_operations::ChronicleOperation; +pub use prov::Prov; - impl core::fmt::Display for ChronicleOperation { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } - } +mod chronicle_operations { + #[derive(Clone, Copy, PartialEq, Eq, Hash)] + pub enum ChronicleOperation { + CreateNamespace, + NamespaceName, + NamespaceUuid, + AgentExists, + AgentName, + AgentUuid, + AgentActsOnBehalfOf, + DelegateId, + ResponsibleId, + ActivityExists, + ActivityName, + StartActivity, + StartActivityTime, + EndActivity, + EndActivityTime, + WasAssociatedWith, + WasAttributedTo, + ActivityUses, + EntityName, + Locator, + Role, + EntityExists, + WasGeneratedBy, + EntityDerive, + DerivationType, + UsedEntityName, + SetAttributes, + Attributes, + Attribute, + DomaintypeId, + WasInformedBy, + InformingActivityName, + Generated, + } + + const ACTIVITY_EXISTS: &str = "http://chronicle.works/chronicleoperations/ns#ActivityExists"; + const ACTIVITY_NAME: &str = "http://chronicle.works/chronicleoperations/ns#ActivityName"; + const START_ACTIVITY: &str = "http://chronicle.works/chronicleoperations/ns#StartActivity"; + const START_ACTIVITY_TIME: &str = + "http://chronicle.works/chronicleoperations/ns#StartActivityTime"; + const END_ACTIVITY: &str = "http://chronicle.works/chronicleoperations/ns#EndActivity"; + const END_ACTIVITY_TIME: &str = "http://chronicle.works/chronicleoperations/ns#EndActivityTime"; + const WAS_ASSOCIATED_WITH: &str = + "http://chronicle.works/chronicleoperations/ns#WasAssociatedWith"; + const WAS_ATTRIBUTED_TO: &str = "http://chronicle.works/chronicleoperations/ns#WasAttributedTo"; + const ACTIVITY_USES: &str = "http://chronicle.works/chronicleoperations/ns#ActivityUses"; + const ENTITY_NAME: &str = "http://chronicle.works/chronicleoperations/ns#EntityName"; + const LOCATOR: &str = "http://chronicle.works/chronicleoperations/ns#Locator"; + const ROLE: &str = "http://chronicle.works/chronicleoperations/ns#Role"; + const ENTITY_EXISTS: &str = "http://chronicle.works/chronicleoperations/ns#EntityExists"; + const WAS_GENERATED_BY: &str = "http://chronicle.works/chronicleoperations/ns#WasGeneratedBy"; + const ENTITY_DERIVE: &str = "http://chronicle.works/chronicleoperations/ns#EntityDerive"; + const DERIVATION_TYPE: &str = "http://chronicle.works/chronicleoperations/ns#DerivationType"; + const USED_ENTITY_NAME: &str = "http://chronicle.works/chronicleoperations/ns#UsedEntityName"; + const SET_ATTRIBUTES: &str = "http://chronicle.works/chronicleoperations/ns#SetAttributes"; + const ATTRIBUTES: &str = "http://chronicle.works/chronicleoperations/ns#Attributes"; + const ATTRIBUTE: &str = "http://chronicle.works/chronicleoperations/ns#Attribute"; + const DOMAINTYPE_ID: &str = "http://chronicle.works/chronicleoperations/ns#DomaintypeId"; + const WAS_INFORMED_BY: &str = "http://chronicle.works/chronicleoperations/ns#WasInformedBy"; + const INFORMING_ACTIVITY_NAME: &str = + "http://chronicle.works/chronicleoperations/ns#InformingActivityName"; + const GENERATED: &str = "http://chronicle.works/chronicleoperations/ns#Generated"; + const CREATE_NAMESPACE: &str = "http://chronicle.works/chronicleoperations/ns#CreateNamespace"; + const NAMESPACE_NAME: &str = "http://chronicle.works/chronicleoperations/ns#namespaceName"; + const NAMESPACE_UUID: &str = "http://chronicle.works/chronicleoperations/ns#namespaceUuid"; + const AGENT_EXISTS: &str = "http://chronicle.works/chronicleoperations/ns#AgentExists"; + const AGENT_NAME: &str = "http://chronicle.works/chronicleoperations/ns#agentName"; + const AGENT_UUID: &str = "http://chronicle.works/chronicleoperations/ns#agentUuid"; + const AGENT_ACTS_ON_BEHALF_OF: &str = + "http://chronicle.works/chronicleoperations/ns#AgentActsOnBehalfOf"; + const DELEGATE_ID: &str = "http://chronicle.works/chronicleoperations/ns#delegateId"; + const RESPONSIBLE_ID: &str = "http://chronicle.works/chronicleoperations/ns#responsibleId"; + + impl AsRef for ChronicleOperation { + fn as_ref(&self) -> &'static str { + match self { + ChronicleOperation::ActivityExists => ACTIVITY_EXISTS, + ChronicleOperation::ActivityName => ACTIVITY_NAME, + ChronicleOperation::StartActivity => START_ACTIVITY, + ChronicleOperation::StartActivityTime => START_ACTIVITY_TIME, + ChronicleOperation::EndActivity => END_ACTIVITY, + ChronicleOperation::EndActivityTime => END_ACTIVITY_TIME, + ChronicleOperation::WasAssociatedWith => WAS_ASSOCIATED_WITH, + ChronicleOperation::WasAttributedTo => WAS_ATTRIBUTED_TO, + ChronicleOperation::ActivityUses => ACTIVITY_USES, + ChronicleOperation::EntityName => ENTITY_NAME, + ChronicleOperation::Locator => LOCATOR, + ChronicleOperation::Role => ROLE, + ChronicleOperation::EntityExists => ENTITY_EXISTS, + ChronicleOperation::WasGeneratedBy => WAS_GENERATED_BY, + ChronicleOperation::EntityDerive => ENTITY_DERIVE, + ChronicleOperation::DerivationType => DERIVATION_TYPE, + ChronicleOperation::UsedEntityName => USED_ENTITY_NAME, + ChronicleOperation::SetAttributes => SET_ATTRIBUTES, + ChronicleOperation::Attributes => ATTRIBUTES, + ChronicleOperation::Attribute => ATTRIBUTE, + ChronicleOperation::DomaintypeId => DOMAINTYPE_ID, + ChronicleOperation::WasInformedBy => WAS_INFORMED_BY, + ChronicleOperation::InformingActivityName => INFORMING_ACTIVITY_NAME, + ChronicleOperation::Generated => GENERATED, + ChronicleOperation::CreateNamespace => CREATE_NAMESPACE, + ChronicleOperation::NamespaceName => NAMESPACE_NAME, + ChronicleOperation::NamespaceUuid => NAMESPACE_UUID, + ChronicleOperation::AgentExists => AGENT_EXISTS, + ChronicleOperation::AgentName => AGENT_NAME, + ChronicleOperation::AgentUuid => AGENT_UUID, + ChronicleOperation::AgentActsOnBehalfOf => AGENT_ACTS_ON_BEHALF_OF, + ChronicleOperation::DelegateId => DELEGATE_ID, + ChronicleOperation::ResponsibleId => RESPONSIBLE_ID, + } + } + } + + #[cfg(feature = "json-ld")] + impl From for iri_string::types::IriString { + fn from(val: ChronicleOperation) -> Self { + use iri_string::types::UriString; + UriString::try_from(val.as_str().to_string()).unwrap().into() + } + } + + impl ChronicleOperation { + pub fn as_str(&self) -> &str { + self.as_ref() + } + } + + impl core::fmt::Display for ChronicleOperation { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } + } } -pub use chronicle_operations::ChronicleOperation; - mod prov { - - #[derive(Clone, Copy, PartialEq, Eq, Hash)] - pub enum Prov { - Agent, - Entity, - Activity, - WasAssociatedWith, - QualifiedAssociation, - QualifiedAttribution, - Association, - Attribution, - Responsible, - WasGeneratedBy, - Used, - WasAttributedTo, - StartedAtTime, - EndedAtTime, - WasDerivedFrom, - HadPrimarySource, - WasQuotedFrom, - WasRevisionOf, - ActedOnBehalfOf, - QualifiedDelegation, - Delegation, - Delegate, - HadRole, - HadActivity, - HadEntity, - WasInformedBy, - Generated, - } - - const AGENT: &str = "http://www.w3.org/ns/prov#Agent"; - const ENTITY: &str = "http://www.w3.org/ns/prov#Entity"; - const ACTIVITY: &str = "http://www.w3.org/ns/prov#Activity"; - const WAS_ASSOCIATED_WITH: &str = "http://www.w3.org/ns/prov#wasAssociatedWith"; - const QUALIFIED_ASSOCIATION: &str = "http://www.w3.org/ns/prov#qualifiedAssociation"; - const QUALIFIED_ATTRIBUTION: &str = "http://www.w3.org/ns/prov#qualifiedAttribution"; - const ASSOCIATION: &str = "http://www.w3.org/ns/prov#Association"; - const ATTRIBUTION: &str = "http://www.w3.org/ns/prov#Attribution"; - const RESPONSIBLE: &str = "http://www.w3.org/ns/prov#agent"; - const WAS_GENERATED_BY: &str = "http://www.w3.org/ns/prov#wasGeneratedBy"; - const USED: &str = "http://www.w3.org/ns/prov#used"; - const WAS_ATTRIBUTED_TO: &str = "http://www.w3.org/ns/prov#wasAttributedTo"; - const STARTED_AT_TIME: &str = "http://www.w3.org/ns/prov#startedAtTime"; - const ENDED_AT_TIME: &str = "http://www.w3.org/ns/prov#endedAtTime"; - const WAS_DERIVED_FROM: &str = "http://www.w3.org/ns/prov#wasDerivedFrom"; - const HAD_PRIMARY_SOURCE: &str = "http://www.w3.org/ns/prov#hadPrimarySource"; - const WAS_QUOTED_FROM: &str = "http://www.w3.org/ns/prov#wasQuotedFrom"; - const WAS_REVISION_OF: &str = "http://www.w3.org/ns/prov#wasRevisionOf"; - const ACTED_ON_BEHALF_OF: &str = "http://www.w3.org/ns/prov#actedOnBehalfOf"; - const QUALIFIED_DELEGATION: &str = "http://www.w3.org/ns/prov#qualifiedDelegation"; - const DELEGATION: &str = "http://www.w3.org/ns/prov#Delegation"; - const DELEGATE: &str = "http://www.w3.org/ns/prov#agent"; - const HAD_ROLE: &str = "http://www.w3.org/ns/prov#hadRole"; - const HAD_ACTIVITY: &str = "http://www.w3.org/ns/prov#hadActivity"; - const HAD_ENTITY: &str = "http://www.w3.org/ns/prov#hadEntity"; - const WAS_INFORMED_BY: &str = "http://www.w3.org/ns/prov#wasInformedBy"; - const GENERATED: &str = "http://www.w3.org/ns/prov#generated"; - - impl AsRef for Prov { - fn as_ref(&self) -> &'static str { - match self { - Prov::Agent => AGENT, - Prov::Entity => ENTITY, - Prov::Activity => ACTIVITY, - Prov::WasAssociatedWith => WAS_ASSOCIATED_WITH, - Prov::QualifiedAssociation => QUALIFIED_ASSOCIATION, - Prov::QualifiedAttribution => QUALIFIED_ATTRIBUTION, - Prov::Association => ASSOCIATION, - Prov::Attribution => ATTRIBUTION, - Prov::Responsible => RESPONSIBLE, - Prov::WasGeneratedBy => WAS_GENERATED_BY, - Prov::Used => USED, - Prov::WasAttributedTo => WAS_ATTRIBUTED_TO, - Prov::StartedAtTime => STARTED_AT_TIME, - Prov::EndedAtTime => ENDED_AT_TIME, - Prov::WasDerivedFrom => WAS_DERIVED_FROM, - Prov::HadPrimarySource => HAD_PRIMARY_SOURCE, - Prov::WasQuotedFrom => WAS_QUOTED_FROM, - Prov::WasRevisionOf => WAS_REVISION_OF, - Prov::ActedOnBehalfOf => ACTED_ON_BEHALF_OF, - Prov::QualifiedDelegation => QUALIFIED_DELEGATION, - Prov::Delegation => DELEGATION, - Prov::Delegate => DELEGATE, - Prov::HadRole => HAD_ROLE, - Prov::HadActivity => HAD_ACTIVITY, - Prov::HadEntity => HAD_ENTITY, - Prov::WasInformedBy => WAS_INFORMED_BY, - Prov::Generated => GENERATED, - } - } - } - - #[cfg(feature = "json-ld")] - impl From for iri_string::types::IriString { - fn from(val: Prov) -> Self { - use iri_string::types::UriString; - UriString::try_from(val.as_str().to_string()).unwrap().into() - } - } - - impl Prov { - pub fn as_str(&self) -> &str { - self.as_ref() - } - } - - impl core::fmt::Display for Prov { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } - } + #[derive(Clone, Copy, PartialEq, Eq, Hash)] + pub enum Prov { + Agent, + Entity, + Activity, + WasAssociatedWith, + QualifiedAssociation, + QualifiedAttribution, + Association, + Attribution, + Responsible, + WasGeneratedBy, + Used, + WasAttributedTo, + StartedAtTime, + EndedAtTime, + WasDerivedFrom, + HadPrimarySource, + WasQuotedFrom, + WasRevisionOf, + ActedOnBehalfOf, + QualifiedDelegation, + Delegation, + Delegate, + HadRole, + HadActivity, + HadEntity, + WasInformedBy, + Generated, + } + + const AGENT: &str = "http://www.w3.org/ns/prov#Agent"; + const ENTITY: &str = "http://www.w3.org/ns/prov#Entity"; + const ACTIVITY: &str = "http://www.w3.org/ns/prov#Activity"; + const WAS_ASSOCIATED_WITH: &str = "http://www.w3.org/ns/prov#wasAssociatedWith"; + const QUALIFIED_ASSOCIATION: &str = "http://www.w3.org/ns/prov#qualifiedAssociation"; + const QUALIFIED_ATTRIBUTION: &str = "http://www.w3.org/ns/prov#qualifiedAttribution"; + const ASSOCIATION: &str = "http://www.w3.org/ns/prov#Association"; + const ATTRIBUTION: &str = "http://www.w3.org/ns/prov#Attribution"; + const RESPONSIBLE: &str = "http://www.w3.org/ns/prov#agent"; + const WAS_GENERATED_BY: &str = "http://www.w3.org/ns/prov#wasGeneratedBy"; + const USED: &str = "http://www.w3.org/ns/prov#used"; + const WAS_ATTRIBUTED_TO: &str = "http://www.w3.org/ns/prov#wasAttributedTo"; + const STARTED_AT_TIME: &str = "http://www.w3.org/ns/prov#startedAtTime"; + const ENDED_AT_TIME: &str = "http://www.w3.org/ns/prov#endedAtTime"; + const WAS_DERIVED_FROM: &str = "http://www.w3.org/ns/prov#wasDerivedFrom"; + const HAD_PRIMARY_SOURCE: &str = "http://www.w3.org/ns/prov#hadPrimarySource"; + const WAS_QUOTED_FROM: &str = "http://www.w3.org/ns/prov#wasQuotedFrom"; + const WAS_REVISION_OF: &str = "http://www.w3.org/ns/prov#wasRevisionOf"; + const ACTED_ON_BEHALF_OF: &str = "http://www.w3.org/ns/prov#actedOnBehalfOf"; + const QUALIFIED_DELEGATION: &str = "http://www.w3.org/ns/prov#qualifiedDelegation"; + const DELEGATION: &str = "http://www.w3.org/ns/prov#Delegation"; + const DELEGATE: &str = "http://www.w3.org/ns/prov#agent"; + const HAD_ROLE: &str = "http://www.w3.org/ns/prov#hadRole"; + const HAD_ACTIVITY: &str = "http://www.w3.org/ns/prov#hadActivity"; + const HAD_ENTITY: &str = "http://www.w3.org/ns/prov#hadEntity"; + const WAS_INFORMED_BY: &str = "http://www.w3.org/ns/prov#wasInformedBy"; + const GENERATED: &str = "http://www.w3.org/ns/prov#generated"; + + impl AsRef for Prov { + fn as_ref(&self) -> &'static str { + match self { + Prov::Agent => AGENT, + Prov::Entity => ENTITY, + Prov::Activity => ACTIVITY, + Prov::WasAssociatedWith => WAS_ASSOCIATED_WITH, + Prov::QualifiedAssociation => QUALIFIED_ASSOCIATION, + Prov::QualifiedAttribution => QUALIFIED_ATTRIBUTION, + Prov::Association => ASSOCIATION, + Prov::Attribution => ATTRIBUTION, + Prov::Responsible => RESPONSIBLE, + Prov::WasGeneratedBy => WAS_GENERATED_BY, + Prov::Used => USED, + Prov::WasAttributedTo => WAS_ATTRIBUTED_TO, + Prov::StartedAtTime => STARTED_AT_TIME, + Prov::EndedAtTime => ENDED_AT_TIME, + Prov::WasDerivedFrom => WAS_DERIVED_FROM, + Prov::HadPrimarySource => HAD_PRIMARY_SOURCE, + Prov::WasQuotedFrom => WAS_QUOTED_FROM, + Prov::WasRevisionOf => WAS_REVISION_OF, + Prov::ActedOnBehalfOf => ACTED_ON_BEHALF_OF, + Prov::QualifiedDelegation => QUALIFIED_DELEGATION, + Prov::Delegation => DELEGATION, + Prov::Delegate => DELEGATE, + Prov::HadRole => HAD_ROLE, + Prov::HadActivity => HAD_ACTIVITY, + Prov::HadEntity => HAD_ENTITY, + Prov::WasInformedBy => WAS_INFORMED_BY, + Prov::Generated => GENERATED, + } + } + } + + #[cfg(feature = "json-ld")] + impl From for iri_string::types::IriString { + fn from(val: Prov) -> Self { + use iri_string::types::UriString; + UriString::try_from(val.as_str().to_string()).unwrap().into() + } + } + + impl Prov { + pub fn as_str(&self) -> &str { + self.as_ref() + } + } + + impl core::fmt::Display for Prov { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } + } } -pub use prov::Prov; - mod chronicle { - use core::str::FromStr; - - use iri_string::types::UriString; - #[cfg(not(feature = "std"))] - use parity_scale_codec::alloc::string::String; - - #[cfg(not(feature = "std"))] - use scale_info::prelude::{borrow::ToOwned, string::ToString, *}; - use uuid::Uuid; - - use crate::prov::{ActivityId, AgentId, EntityId, ExternalId, ExternalIdPart, Role}; - - #[derive(Clone, Copy, PartialEq, Eq, Hash)] - pub enum Chronicle { - Namespace, - HasNamespace, - Value, - } - - const NAMESPACE: &str = "http://chronicle.works/chronicle/ns#Namespace"; - const HAS_NAMESPACE: &str = "http://chronicle.works/chronicle/ns#hasNamespace"; - const VALUE: &str = "http://chronicle.works/chronicle/ns#Value"; - - impl AsRef for Chronicle { - fn as_ref(&self) -> &'static str { - match self { - Chronicle::Namespace => NAMESPACE, - Chronicle::HasNamespace => HAS_NAMESPACE, - Chronicle::Value => VALUE, - } - } - } - - #[cfg(feature = "json-ld")] - impl From for iri_string::types::IriString { - fn from(val: Chronicle) -> Self { - UriString::try_from(val.as_str().to_string()).unwrap().into() - } - } - - impl Chronicle { - pub fn as_str(&self) -> &str { - self.as_ref() - } - } - - impl core::fmt::Display for Chronicle { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.as_str()) - } - } - - lazy_static::lazy_static! { + use core::str::FromStr; + + use iri_string::types::UriString; + #[cfg(not(feature = "std"))] + use parity_scale_codec::alloc::string::String; + #[cfg(not(feature = "std"))] + use scale_info::prelude::{*, borrow::ToOwned, string::ToString}; + use uuid::Uuid; + + use crate::prov::{ActivityId, AgentId, EntityId, ExternalId, ExternalIdPart, Role}; + + #[derive(Clone, Copy, PartialEq, Eq, Hash)] + pub enum Chronicle { + Namespace, + HasNamespace, + Value, + } + + const NAMESPACE: &str = "http://chronicle.works/chronicle/ns#Namespace"; + const HAS_NAMESPACE: &str = "http://chronicle.works/chronicle/ns#hasNamespace"; + const VALUE: &str = "http://chronicle.works/chronicle/ns#Value"; + + impl AsRef for Chronicle { + fn as_ref(&self) -> &'static str { + match self { + Chronicle::Namespace => NAMESPACE, + Chronicle::HasNamespace => HAS_NAMESPACE, + Chronicle::Value => VALUE, + } + } + } + + #[cfg(feature = "json-ld")] + impl From for iri_string::types::IriString { + fn from(val: Chronicle) -> Self { + UriString::try_from(val.as_str().to_string()).unwrap().into() + } + } + + impl Chronicle { + pub fn as_str(&self) -> &str { + self.as_ref() + } + } + + impl core::fmt::Display for Chronicle { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } + } + + lazy_static::lazy_static! { static ref ENCODE_SET: percent_encoding::AsciiSet = percent_encoding::NON_ALPHANUMERIC .remove(b'_') @@ -317,158 +314,157 @@ mod chronicle { .remove(b'.'); } - /// Operations to format specific Iri kinds, using percentage encoding to ensure they are - /// infallible. This module provides functionality to create various types of IRIs with - /// percent encoding applied to external IDs where necessary. - impl Chronicle { - pub const LEGACY_PREFIXES: &'static [&'static str] = - &["http://btp.works/chronicle/ns#", "http://blockchaintp.com/chronicle/ns#"]; - pub const LONG_PREFIX: &'static str = "http://chronicle.works/chronicle/ns#"; - pub const PREFIX: &'static str = "chronicle"; - - /// Encodes the given external ID using percent-encoding to ensure it is a valid Chronicle - /// CURIE - fn encode_external_id(external_id: &ExternalId) -> String { - percent_encoding::utf8_percent_encode(external_id.as_str(), &ENCODE_SET).to_string() - } - - /// Constructs a namespace IRI using a given external ID and UUID. - pub fn namespace( - external_id: &ExternalId, - id: &Uuid, - ) -> Result { - let encoded_external_id = Self::encode_external_id(external_id); - UriString::from_str(&format!("{}:ns:{}:{}", Self::PREFIX, encoded_external_id, id)) - } - - /// Constructs an agent IRI using a given external ID. - pub fn agent( - external_id: &ExternalId, - ) -> Result> { - let encoded_external_id = Self::encode_external_id(external_id); - format!("{}:agent:{}", Self::PREFIX, encoded_external_id).try_into() - } - - /// Constructs an activity IRI using a given external ID. - pub fn activity( - external_id: &ExternalId, - ) -> Result> { - let encoded_external_id = Self::encode_external_id(external_id); - format!("{}:activity:{}", Self::PREFIX, encoded_external_id).try_into() - } - - /// Constructs an entity IRI using a given external ID. - pub fn entity( - external_id: &ExternalId, - ) -> Result> { - let encoded_external_id = Self::encode_external_id(external_id); - format!("{}:entity:{}", Self::PREFIX, encoded_external_id).try_into() - } - - /// Constructs a domaintype IRI using a given external ID. - pub fn domaintype( - external_id: &ExternalId, - ) -> Result> { - let encoded_external_id = Self::encode_external_id(external_id); - format!("{}:domaintype:{}", Self::PREFIX, encoded_external_id).try_into() - } - - /// Constructs an association IRI using given agent and activity IDs, and an optional role. - pub fn association( - agent: &AgentId, - activity: &ActivityId, - role: &Option, - ) -> Result> { - let encoded_agent_id = Self::encode_external_id(agent.external_id_part()); - let encoded_activity_id = Self::encode_external_id(activity.external_id_part()); - let encoded_role = role - .as_ref() - .map(|r| Self::encode_external_id(&ExternalId::from(r.as_str()))) - .unwrap_or_else(|| "".to_owned()); - format!( - "{}:association:{}:{}:role={}", - Self::PREFIX, - encoded_agent_id, - encoded_activity_id, - encoded_role, - ) - .try_into() - } - - /// Constructs a delegation IRI using given delegate and responsible agent IDs, and optional - /// activity and role. - #[tracing::instrument( - name = "delegation_iri_creation", - skip(delegate, responsible, activity, role) - )] - pub fn delegation( - delegate: &AgentId, - responsible: &AgentId, - activity: &Option, - role: &Option, - ) -> Result> { - let encoded_delegate_id = Self::encode_external_id(delegate.external_id_part()); - let encoded_responsible_id = Self::encode_external_id(responsible.external_id_part()); - let encoded_activity_id = activity - .as_ref() - .map(|a| Self::encode_external_id(a.external_id_part())) - .unwrap_or_default(); - let encoded_role = role - .as_ref() - .map(|r| Self::encode_external_id(&ExternalId::from(r.as_str()))) - .unwrap_or_else(|| "".to_owned()); - format!( - "{}:delegation:{}:{}:role={}:activity={}", - Self::PREFIX, - encoded_delegate_id, - encoded_responsible_id, - encoded_role, - encoded_activity_id, - ) - .try_into() - } - - /// Constructs an attribution IRI using given agent and entity IDs, and an optional role. - #[tracing::instrument(name = "attribution_iri_creation", skip(agent, entity, role))] - pub fn attribution( - agent: &AgentId, - entity: &EntityId, - role: &Option, - ) -> Result> { - let encoded_agent_id = Self::encode_external_id(agent.external_id_part()); - let encoded_entity_id = Self::encode_external_id(entity.external_id_part()); - let encoded_role = role - .as_ref() - .map(|r| Self::encode_external_id(&ExternalId::from(r.as_str()))) - .unwrap_or_else(|| "".to_owned()); - format!( - "{}:attribution:{}:{}:role={}", - Self::PREFIX, - encoded_agent_id, - encoded_entity_id, - encoded_role, - ) - .try_into() - } - } + /// Operations to format specific Iri kinds, using percentage encoding to ensure they are + /// infallible. This module provides functionality to create various types of IRIs with + /// percent encoding applied to external IDs where necessary. + impl Chronicle { + pub const LEGACY_PREFIXES: &'static [&'static str] = + &["http://btp.works/chronicle/ns#", "http://blockchaintp.com/chronicle/ns#"]; + pub const LONG_PREFIX: &'static str = "http://chronicle.works/chronicle/ns#"; + pub const PREFIX: &'static str = "chronicle"; + + /// Encodes the given external ID using percent-encoding to ensure it is a valid Chronicle + /// CURIE + fn encode_external_id(external_id: &ExternalId) -> String { + percent_encoding::utf8_percent_encode(external_id.as_str(), &ENCODE_SET).to_string() + } + + /// Constructs a namespace IRI using a given external ID and UUID. + pub fn namespace( + external_id: &ExternalId, + id: &Uuid, + ) -> Result { + let encoded_external_id = Self::encode_external_id(external_id); + UriString::from_str(&format!("{}:ns:{}:{}", Self::PREFIX, encoded_external_id, id)) + } + + /// Constructs an agent IRI using a given external ID. + pub fn agent( + external_id: &ExternalId, + ) -> Result> { + let encoded_external_id = Self::encode_external_id(external_id); + format!("{}:agent:{}", Self::PREFIX, encoded_external_id).try_into() + } + + /// Constructs an activity IRI using a given external ID. + pub fn activity( + external_id: &ExternalId, + ) -> Result> { + let encoded_external_id = Self::encode_external_id(external_id); + format!("{}:activity:{}", Self::PREFIX, encoded_external_id).try_into() + } + + /// Constructs an entity IRI using a given external ID. + pub fn entity( + external_id: &ExternalId, + ) -> Result> { + let encoded_external_id = Self::encode_external_id(external_id); + format!("{}:entity:{}", Self::PREFIX, encoded_external_id).try_into() + } + + /// Constructs a domaintype IRI using a given external ID. + pub fn domaintype( + external_id: &ExternalId, + ) -> Result> { + let encoded_external_id = Self::encode_external_id(external_id); + format!("{}:domaintype:{}", Self::PREFIX, encoded_external_id).try_into() + } + + /// Constructs an association IRI using given agent and activity IDs, and an optional role. + pub fn association( + agent: &AgentId, + activity: &ActivityId, + role: &Option, + ) -> Result> { + let encoded_agent_id = Self::encode_external_id(agent.external_id_part()); + let encoded_activity_id = Self::encode_external_id(activity.external_id_part()); + let encoded_role = role + .as_ref() + .map(|r| Self::encode_external_id(&ExternalId::from(r.as_str()))) + .unwrap_or_else(|| "".to_owned()); + format!( + "{}:association:{}:{}:role={}", + Self::PREFIX, + encoded_agent_id, + encoded_activity_id, + encoded_role, + ) + .try_into() + } + + /// Constructs a delegation IRI using given delegate and responsible agent IDs, and optional + /// activity and role. + #[tracing::instrument( + name = "delegation_iri_creation", + skip(delegate, responsible, activity, role) + )] + pub fn delegation( + delegate: &AgentId, + responsible: &AgentId, + activity: &Option, + role: &Option, + ) -> Result> { + let encoded_delegate_id = Self::encode_external_id(delegate.external_id_part()); + let encoded_responsible_id = Self::encode_external_id(responsible.external_id_part()); + let encoded_activity_id = activity + .as_ref() + .map(|a| Self::encode_external_id(a.external_id_part())) + .unwrap_or_default(); + let encoded_role = role + .as_ref() + .map(|r| Self::encode_external_id(&ExternalId::from(r.as_str()))) + .unwrap_or_else(|| "".to_owned()); + format!( + "{}:delegation:{}:{}:role={}:activity={}", + Self::PREFIX, + encoded_delegate_id, + encoded_responsible_id, + encoded_role, + encoded_activity_id, + ) + .try_into() + } + + /// Constructs an attribution IRI using given agent and entity IDs, and an optional role. + #[tracing::instrument(name = "attribution_iri_creation", skip(agent, entity, role))] + pub fn attribution( + agent: &AgentId, + entity: &EntityId, + role: &Option, + ) -> Result> { + let encoded_agent_id = Self::encode_external_id(agent.external_id_part()); + let encoded_entity_id = Self::encode_external_id(entity.external_id_part()); + let encoded_role = role + .as_ref() + .map(|r| Self::encode_external_id(&ExternalId::from(r.as_str()))) + .unwrap_or_else(|| "".to_owned()); + format!( + "{}:attribution:{}:{}:role={}", + Self::PREFIX, + encoded_agent_id, + encoded_entity_id, + encoded_role, + ) + .try_into() + } + } } -pub use chronicle::*; - /// As these operations are meant to be infallible, prop test them to ensure #[cfg(test)] #[allow(clippy::useless_conversion)] mod test { - use crate::prov::{ - ActivityId, AgentId, AssociationId, AttributionId, DelegationId, DomaintypeId, EntityId, - ExternalId, ExternalIdPart, NamespaceId, Role, - }; + use proptest::prelude::*; + use uuid::Uuid; + + use crate::prov::{ + ActivityId, AgentId, AssociationId, AttributionId, DelegationId, DomaintypeId, EntityId, + ExternalId, ExternalIdPart, NamespaceId, Role, + }; - use super::Chronicle; - use proptest::prelude::*; - use uuid::Uuid; + use super::Chronicle; - proptest! { + proptest! { #![proptest_config(ProptestConfig { max_shrink_iters: std::u32::MAX, verbose: 0, .. ProptestConfig::default() })] diff --git a/crates/embedded-substrate/Cargo.toml b/crates/embedded-substrate/Cargo.toml index 2cfaa1ca5..c54743b62 100644 --- a/crates/embedded-substrate/Cargo.toml +++ b/crates/embedded-substrate/Cargo.toml @@ -1,28 +1,28 @@ [package] edition = "2021" -name = "embedded-substrate" +name = "embedded-substrate" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = { workspace = true } -lazy_static = { workspace = true } -node-chronicle = { path = "../../node/node-chronicle" } -portpicker = { workspace = true } -protocol-abstract = { path = "../protocol-abstract" } -protocol-substrate = { path = "../protocol-substrate" } +anyhow = { workspace = true } +lazy_static = { workspace = true } +node-chronicle = { path = "../../node/node-chronicle" } +portpicker = { workspace = true } +protocol-abstract = { path = "../protocol-abstract" } +protocol-substrate = { path = "../protocol-substrate" } protocol-substrate-chronicle = { path = "../protocol-substrate-chronicle" } -sc-cli = { version = "0.33.0" } -sp-io = { version = "27.0.0" } -sp-runtime = { version = "28.0.0" } -subxt = { version = "0.34", features = ["substrate-compat"] } -tempfile = { version = "3" } -thiserror = { workspace = true } -tokio = { workspace = true } -tracing = { workspace = true } +sc-cli = { version = "0.33.0" } +sp-io = { version = "27.0.0" } +sp-runtime = { version = "28.0.0" } +subxt = { version = "0.34", features = ["substrate-compat"] } +tempfile = { version = "3" } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } [dev-dependencies] chronicle-signing = { workspace = true } -uuid = { workspace = true } +uuid = { workspace = true } diff --git a/crates/embedded-substrate/meta.rs b/crates/embedded-substrate/meta.rs index 9a0f59d51..8aa3e21a8 100644 --- a/crates/embedded-substrate/meta.rs +++ b/crates/embedded-substrate/meta.rs @@ -2,7224 +2,7888 @@ #[allow(clippy::all)] #[allow(rustdoc::broken_intra_doc_links)] pub mod api { - #[allow(unused_imports)] - mod root_mod { - pub use super::*; - } - pub static PALLETS: [&str; 7usize] = - ["System", "Timestamp", "Aura", "Grandpa", "Sudo", "Chronicle", "Opa"]; - pub static RUNTIME_APIS: [&str; 10usize] = [ - "ChronicleApi", - "Core", - "Metadata", - "BlockBuilder", - "TaggedTransactionQueue", - "OffchainWorkerApi", - "AuraApi", - "SessionKeys", - "GrandpaApi", - "AccountNonceApi", - ]; - #[doc = r" The error type returned when there is a runtime issue."] - pub type DispatchError = runtime_types::sp_runtime::DispatchError; - #[doc = r" The outer event enum."] - pub type Event = runtime_types::runtime_chronicle::RuntimeEvent; - #[doc = r" The outer extrinsic enum."] - pub type Call = runtime_types::runtime_chronicle::RuntimeCall; - #[doc = r" The outer error enum representing the DispatchError's Module variant."] - pub type Error = runtime_types::runtime_chronicle::RuntimeError; - pub fn constants() -> ConstantsApi { - ConstantsApi - } - pub fn storage() -> StorageApi { - StorageApi - } - pub fn tx() -> TransactionApi { - TransactionApi - } - pub fn apis() -> runtime_apis::RuntimeApi { - runtime_apis::RuntimeApi - } - pub mod runtime_apis { - use super::{root_mod, runtime_types}; - use subxt::ext::codec::Encode; - pub struct RuntimeApi; - impl RuntimeApi { - pub fn chronicle_api(&self) -> chronicle_api::ChronicleApi { - chronicle_api::ChronicleApi - } - - pub fn core(&self) -> core::Core { - core::Core - } - - pub fn metadata(&self) -> metadata::Metadata { - metadata::Metadata - } - - pub fn block_builder(&self) -> block_builder::BlockBuilder { - block_builder::BlockBuilder - } - - pub fn tagged_transaction_queue( - &self, - ) -> tagged_transaction_queue::TaggedTransactionQueue { - tagged_transaction_queue::TaggedTransactionQueue - } - - pub fn offchain_worker_api(&self) -> offchain_worker_api::OffchainWorkerApi { - offchain_worker_api::OffchainWorkerApi - } - - pub fn aura_api(&self) -> aura_api::AuraApi { - aura_api::AuraApi - } - - pub fn session_keys(&self) -> session_keys::SessionKeys { - session_keys::SessionKeys - } - - pub fn grandpa_api(&self) -> grandpa_api::GrandpaApi { - grandpa_api::GrandpaApi - } - - pub fn account_nonce_api(&self) -> account_nonce_api::AccountNonceApi { - account_nonce_api::AccountNonceApi - } - } - pub mod chronicle_api { - use super::{root_mod, runtime_types}; - pub struct ChronicleApi; - impl ChronicleApi { - pub fn placeholder( - &self, - ) -> ::subxt::runtime_api::Payload< - types::Placeholder, - types::placeholder::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "ChronicleApi", - "placeholder", - types::Placeholder {}, - [ - 69u8, 86u8, 182u8, 109u8, 157u8, 7u8, 62u8, 57u8, 188u8, 29u8, 49u8, - 204u8, 192u8, 72u8, 129u8, 172u8, 6u8, 99u8, 90u8, 91u8, 65u8, 63u8, - 182u8, 117u8, 15u8, 156u8, 227u8, 205u8, 229u8, 70u8, 212u8, 119u8, - ], - ) - } - } - pub mod types { - use super::runtime_types; - pub mod placeholder { - use super::runtime_types; - pub mod output { - use super::runtime_types; - pub type Output = ::core::primitive::u32; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Placeholder {} - } - } - pub mod core { - use super::{root_mod, runtime_types}; - #[doc = " The `Core` runtime api that every Substrate runtime needs to implement."] - pub struct Core; - impl Core { - #[doc = " Returns the version of the runtime."] - pub fn version( - &self, - ) -> ::subxt::runtime_api::Payload { - ::subxt::runtime_api::Payload::new_static( - "Core", - "version", - types::Version {}, - [ - 76u8, 202u8, 17u8, 117u8, 189u8, 237u8, 239u8, 237u8, 151u8, 17u8, - 125u8, 159u8, 218u8, 92u8, 57u8, 238u8, 64u8, 147u8, 40u8, 72u8, 157u8, - 116u8, 37u8, 195u8, 156u8, 27u8, 123u8, 173u8, 178u8, 102u8, 136u8, - 6u8, - ], - ) - } - - #[doc = " Execute the given block."] - pub fn execute_block( - &self, - block: types::execute_block::Block, - ) -> ::subxt::runtime_api::Payload< - types::ExecuteBlock, - types::execute_block::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "Core", - "execute_block", - types::ExecuteBlock { block }, - [ - 133u8, 135u8, 228u8, 65u8, 106u8, 27u8, 85u8, 158u8, 112u8, 254u8, - 93u8, 26u8, 102u8, 201u8, 118u8, 216u8, 249u8, 247u8, 91u8, 74u8, 56u8, - 208u8, 231u8, 115u8, 131u8, 29u8, 209u8, 6u8, 65u8, 57u8, 214u8, 125u8, - ], - ) - } - - #[doc = " Initialize a block with the given header."] - pub fn initialize_block( - &self, - header: types::initialize_block::Header, - ) -> ::subxt::runtime_api::Payload< - types::InitializeBlock, - types::initialize_block::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "Core", - "initialize_block", - types::InitializeBlock { header }, - [ - 146u8, 138u8, 72u8, 240u8, 63u8, 96u8, 110u8, 189u8, 77u8, 92u8, 96u8, - 232u8, 41u8, 217u8, 105u8, 148u8, 83u8, 190u8, 152u8, 219u8, 19u8, - 87u8, 163u8, 1u8, 232u8, 25u8, 221u8, 74u8, 224u8, 67u8, 223u8, 34u8, - ], - ) - } - } - pub mod types { - use super::runtime_types; - pub mod version { - use super::runtime_types; - pub mod output { - use super::runtime_types; - pub type Output = runtime_types::sp_version::RuntimeVersion; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Version {} - pub mod execute_block { - use super::runtime_types; - pub type Block = runtime_types :: sp_runtime :: generic :: block :: Block < runtime_types :: sp_runtime :: generic :: header :: Header < :: core :: primitive :: u32 > , :: subxt :: utils :: UncheckedExtrinsic < :: subxt :: utils :: MultiAddress < :: subxt :: utils :: AccountId32 , () > , runtime_types :: runtime_chronicle :: RuntimeCall , runtime_types :: sp_runtime :: MultiSignature , (runtime_types :: frame_system :: extensions :: check_non_zero_sender :: CheckNonZeroSender , runtime_types :: frame_system :: extensions :: check_spec_version :: CheckSpecVersion , runtime_types :: frame_system :: extensions :: check_tx_version :: CheckTxVersion , runtime_types :: frame_system :: extensions :: check_genesis :: CheckGenesis , runtime_types :: frame_system :: extensions :: check_mortality :: CheckMortality , runtime_types :: runtime_chronicle :: no_nonce_fees :: CheckNonce , runtime_types :: frame_system :: extensions :: check_weight :: CheckWeight ,) > > ; - pub mod output { - use super::runtime_types; - pub type Output = (); - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ExecuteBlock { - pub block: execute_block::Block, - } - pub mod initialize_block { - use super::runtime_types; - pub type Header = - runtime_types::sp_runtime::generic::header::Header<::core::primitive::u32>; - pub mod output { - use super::runtime_types; - pub type Output = (); - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct InitializeBlock { - pub header: initialize_block::Header, - } - } - } - pub mod metadata { - use super::{root_mod, runtime_types}; - #[doc = " The `Metadata` api trait that returns metadata for the runtime."] - pub struct Metadata; - impl Metadata { - #[doc = " Returns the metadata of a runtime."] - pub fn metadata( - &self, - ) -> ::subxt::runtime_api::Payload - { - ::subxt::runtime_api::Payload::new_static( - "Metadata", - "metadata", - types::Metadata {}, - [ - 231u8, 24u8, 67u8, 152u8, 23u8, 26u8, 188u8, 82u8, 229u8, 6u8, 185u8, - 27u8, 175u8, 68u8, 83u8, 122u8, 69u8, 89u8, 185u8, 74u8, 248u8, 87u8, - 217u8, 124u8, 193u8, 252u8, 199u8, 186u8, 196u8, 179u8, 179u8, 96u8, - ], - ) - } - - #[doc = " Returns the metadata at a given version."] - #[doc = ""] - #[doc = " If the given `version` isn't supported, this will return `None`."] - #[doc = " Use [`Self::metadata_versions`] to find out about supported metadata version of the runtime."] - pub fn metadata_at_version( - &self, - version: types::metadata_at_version::Version, - ) -> ::subxt::runtime_api::Payload< - types::MetadataAtVersion, - types::metadata_at_version::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "Metadata", - "metadata_at_version", - types::MetadataAtVersion { version }, - [ - 131u8, 53u8, 212u8, 234u8, 16u8, 25u8, 120u8, 252u8, 153u8, 153u8, - 216u8, 28u8, 54u8, 113u8, 52u8, 236u8, 146u8, 68u8, 142u8, 8u8, 10u8, - 169u8, 131u8, 142u8, 204u8, 38u8, 48u8, 108u8, 134u8, 86u8, 226u8, - 61u8, - ], - ) - } - - #[doc = " Returns the supported metadata versions."] - #[doc = ""] - #[doc = " This can be used to call `metadata_at_version`."] - pub fn metadata_versions( - &self, - ) -> ::subxt::runtime_api::Payload< - types::MetadataVersions, - types::metadata_versions::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "Metadata", - "metadata_versions", - types::MetadataVersions {}, - [ - 23u8, 144u8, 137u8, 91u8, 188u8, 39u8, 231u8, 208u8, 252u8, 218u8, - 224u8, 176u8, 77u8, 32u8, 130u8, 212u8, 223u8, 76u8, 100u8, 190u8, - 82u8, 94u8, 190u8, 8u8, 82u8, 244u8, 225u8, 179u8, 85u8, 176u8, 56u8, - 16u8, - ], - ) - } - } - pub mod types { - use super::runtime_types; - pub mod metadata { - use super::runtime_types; - pub mod output { - use super::runtime_types; - pub type Output = runtime_types::sp_core::OpaqueMetadata; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Metadata {} - pub mod metadata_at_version { - use super::runtime_types; - pub type Version = ::core::primitive::u32; - pub mod output { - use super::runtime_types; - pub type Output = - ::core::option::Option; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct MetadataAtVersion { - pub version: metadata_at_version::Version, - } - pub mod metadata_versions { - use super::runtime_types; - pub mod output { - use super::runtime_types; - pub type Output = ::std::vec::Vec<::core::primitive::u32>; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct MetadataVersions {} - } - } - pub mod block_builder { - use super::{root_mod, runtime_types}; - #[doc = " The `BlockBuilder` api trait that provides the required functionality for building a block."] - pub struct BlockBuilder; - impl BlockBuilder { - #[doc = " Apply the given extrinsic."] - #[doc = ""] - #[doc = " Returns an inclusion outcome which specifies if this extrinsic is included in"] - #[doc = " this block or not."] - pub fn apply_extrinsic( - &self, - extrinsic: types::apply_extrinsic::Extrinsic, - ) -> ::subxt::runtime_api::Payload< - types::ApplyExtrinsic, - types::apply_extrinsic::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "BlockBuilder", - "apply_extrinsic", - types::ApplyExtrinsic { extrinsic }, - [ - 72u8, 54u8, 139u8, 3u8, 118u8, 136u8, 65u8, 47u8, 6u8, 105u8, 125u8, - 223u8, 160u8, 29u8, 103u8, 74u8, 79u8, 149u8, 48u8, 90u8, 237u8, 2u8, - 97u8, 201u8, 123u8, 34u8, 167u8, 37u8, 187u8, 35u8, 176u8, 97u8, - ], - ) - } - - #[doc = " Finish the current block."] - pub fn finalize_block( - &self, - ) -> ::subxt::runtime_api::Payload< - types::FinalizeBlock, - types::finalize_block::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "BlockBuilder", - "finalize_block", - types::FinalizeBlock {}, - [ - 244u8, 207u8, 24u8, 33u8, 13u8, 69u8, 9u8, 249u8, 145u8, 143u8, 122u8, - 96u8, 197u8, 55u8, 64u8, 111u8, 238u8, 224u8, 34u8, 201u8, 27u8, 146u8, - 232u8, 99u8, 191u8, 30u8, 114u8, 16u8, 32u8, 220u8, 58u8, 62u8, - ], - ) - } - - #[doc = " Generate inherent extrinsics. The inherent data will vary from chain to chain."] - pub fn inherent_extrinsics( - &self, - inherent: types::inherent_extrinsics::Inherent, - ) -> ::subxt::runtime_api::Payload< - types::InherentExtrinsics, - types::inherent_extrinsics::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "BlockBuilder", - "inherent_extrinsics", - types::InherentExtrinsics { inherent }, - [ - 254u8, 110u8, 245u8, 201u8, 250u8, 192u8, 27u8, 228u8, 151u8, 213u8, - 166u8, 89u8, 94u8, 81u8, 189u8, 234u8, 64u8, 18u8, 245u8, 80u8, 29u8, - 18u8, 140u8, 129u8, 113u8, 236u8, 135u8, 55u8, 79u8, 159u8, 175u8, - 183u8, - ], - ) - } - - #[doc = " Check that the inherents are valid. The inherent data will vary from chain to chain."] - pub fn check_inherents( - &self, - block: types::check_inherents::Block, - data: types::check_inherents::Data, - ) -> ::subxt::runtime_api::Payload< - types::CheckInherents, - types::check_inherents::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "BlockBuilder", - "check_inherents", - types::CheckInherents { block, data }, - [ - 153u8, 134u8, 1u8, 215u8, 139u8, 11u8, 53u8, 51u8, 210u8, 175u8, 197u8, - 28u8, 38u8, 209u8, 175u8, 247u8, 142u8, 157u8, 50u8, 151u8, 164u8, - 191u8, 181u8, 118u8, 80u8, 97u8, 160u8, 248u8, 110u8, 217u8, 181u8, - 234u8, - ], - ) - } - } - pub mod types { - use super::runtime_types; - pub mod apply_extrinsic { - use super::runtime_types; - pub type Extrinsic = :: subxt :: utils :: UncheckedExtrinsic < :: subxt :: utils :: MultiAddress < :: subxt :: utils :: AccountId32 , () > , runtime_types :: runtime_chronicle :: RuntimeCall , runtime_types :: sp_runtime :: MultiSignature , (runtime_types :: frame_system :: extensions :: check_non_zero_sender :: CheckNonZeroSender , runtime_types :: frame_system :: extensions :: check_spec_version :: CheckSpecVersion , runtime_types :: frame_system :: extensions :: check_tx_version :: CheckTxVersion , runtime_types :: frame_system :: extensions :: check_genesis :: CheckGenesis , runtime_types :: frame_system :: extensions :: check_mortality :: CheckMortality , runtime_types :: runtime_chronicle :: no_nonce_fees :: CheckNonce , runtime_types :: frame_system :: extensions :: check_weight :: CheckWeight ,) > ; - pub mod output { - use super::runtime_types; - pub type Output = :: core :: result :: Result < :: core :: result :: Result < () , runtime_types :: sp_runtime :: DispatchError > , runtime_types :: sp_runtime :: transaction_validity :: TransactionValidityError > ; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ApplyExtrinsic { - pub extrinsic: apply_extrinsic::Extrinsic, - } - pub mod finalize_block { - use super::runtime_types; - pub mod output { - use super::runtime_types; - pub type Output = runtime_types::sp_runtime::generic::header::Header< - ::core::primitive::u32, - >; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct FinalizeBlock {} - pub mod inherent_extrinsics { - use super::runtime_types; - pub type Inherent = runtime_types::sp_inherents::InherentData; - pub mod output { - use super::runtime_types; - pub type Output = :: std :: vec :: Vec < :: subxt :: utils :: UncheckedExtrinsic < :: subxt :: utils :: MultiAddress < :: subxt :: utils :: AccountId32 , () > , runtime_types :: runtime_chronicle :: RuntimeCall , runtime_types :: sp_runtime :: MultiSignature , (runtime_types :: frame_system :: extensions :: check_non_zero_sender :: CheckNonZeroSender , runtime_types :: frame_system :: extensions :: check_spec_version :: CheckSpecVersion , runtime_types :: frame_system :: extensions :: check_tx_version :: CheckTxVersion , runtime_types :: frame_system :: extensions :: check_genesis :: CheckGenesis , runtime_types :: frame_system :: extensions :: check_mortality :: CheckMortality , runtime_types :: runtime_chronicle :: no_nonce_fees :: CheckNonce , runtime_types :: frame_system :: extensions :: check_weight :: CheckWeight ,) > > ; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct InherentExtrinsics { - pub inherent: inherent_extrinsics::Inherent, - } - pub mod check_inherents { - use super::runtime_types; - pub type Block = runtime_types :: sp_runtime :: generic :: block :: Block < runtime_types :: sp_runtime :: generic :: header :: Header < :: core :: primitive :: u32 > , :: subxt :: utils :: UncheckedExtrinsic < :: subxt :: utils :: MultiAddress < :: subxt :: utils :: AccountId32 , () > , runtime_types :: runtime_chronicle :: RuntimeCall , runtime_types :: sp_runtime :: MultiSignature , (runtime_types :: frame_system :: extensions :: check_non_zero_sender :: CheckNonZeroSender , runtime_types :: frame_system :: extensions :: check_spec_version :: CheckSpecVersion , runtime_types :: frame_system :: extensions :: check_tx_version :: CheckTxVersion , runtime_types :: frame_system :: extensions :: check_genesis :: CheckGenesis , runtime_types :: frame_system :: extensions :: check_mortality :: CheckMortality , runtime_types :: runtime_chronicle :: no_nonce_fees :: CheckNonce , runtime_types :: frame_system :: extensions :: check_weight :: CheckWeight ,) > > ; - pub type Data = runtime_types::sp_inherents::InherentData; - pub mod output { - use super::runtime_types; - pub type Output = runtime_types::sp_inherents::CheckInherentsResult; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct CheckInherents { - pub block: check_inherents::Block, - pub data: check_inherents::Data, - } - } - } - pub mod tagged_transaction_queue { - use super::{root_mod, runtime_types}; - #[doc = " The `TaggedTransactionQueue` api trait for interfering with the transaction queue."] - pub struct TaggedTransactionQueue; - impl TaggedTransactionQueue { - #[doc = " Validate the transaction."] - #[doc = ""] - #[doc = " This method is invoked by the transaction pool to learn details about given transaction."] - #[doc = " The implementation should make sure to verify the correctness of the transaction"] - #[doc = " against current state. The given `block_hash` corresponds to the hash of the block"] - #[doc = " that is used as current state."] - #[doc = ""] - #[doc = " Note that this call may be performed by the pool multiple times and transactions"] - #[doc = " might be verified in any possible order."] - pub fn validate_transaction( - &self, - source: types::validate_transaction::Source, - tx: types::validate_transaction::Tx, - block_hash: types::validate_transaction::BlockHash, - ) -> ::subxt::runtime_api::Payload< - types::ValidateTransaction, - types::validate_transaction::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "TaggedTransactionQueue", - "validate_transaction", - types::ValidateTransaction { source, tx, block_hash }, - [ - 196u8, 50u8, 90u8, 49u8, 109u8, 251u8, 200u8, 35u8, 23u8, 150u8, 140u8, - 143u8, 232u8, 164u8, 133u8, 89u8, 32u8, 240u8, 115u8, 39u8, 95u8, 70u8, - 162u8, 76u8, 122u8, 73u8, 151u8, 144u8, 234u8, 120u8, 100u8, 29u8, - ], - ) - } - } - pub mod types { - use super::runtime_types; - pub mod validate_transaction { - use super::runtime_types; - pub type Source = - runtime_types::sp_runtime::transaction_validity::TransactionSource; - pub type Tx = :: subxt :: utils :: UncheckedExtrinsic < :: subxt :: utils :: MultiAddress < :: subxt :: utils :: AccountId32 , () > , runtime_types :: runtime_chronicle :: RuntimeCall , runtime_types :: sp_runtime :: MultiSignature , (runtime_types :: frame_system :: extensions :: check_non_zero_sender :: CheckNonZeroSender , runtime_types :: frame_system :: extensions :: check_spec_version :: CheckSpecVersion , runtime_types :: frame_system :: extensions :: check_tx_version :: CheckTxVersion , runtime_types :: frame_system :: extensions :: check_genesis :: CheckGenesis , runtime_types :: frame_system :: extensions :: check_mortality :: CheckMortality , runtime_types :: runtime_chronicle :: no_nonce_fees :: CheckNonce , runtime_types :: frame_system :: extensions :: check_weight :: CheckWeight ,) > ; - pub type BlockHash = ::subxt::utils::H256; - pub mod output { - use super::runtime_types; - pub type Output = :: core :: result :: Result < runtime_types :: sp_runtime :: transaction_validity :: ValidTransaction , runtime_types :: sp_runtime :: transaction_validity :: TransactionValidityError > ; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ValidateTransaction { - pub source: validate_transaction::Source, - pub tx: validate_transaction::Tx, - pub block_hash: validate_transaction::BlockHash, - } - } - } - pub mod offchain_worker_api { - use super::{root_mod, runtime_types}; - #[doc = " The offchain worker api."] - pub struct OffchainWorkerApi; - impl OffchainWorkerApi { - #[doc = " Starts the off-chain task for given block header."] - pub fn offchain_worker( - &self, - header: types::offchain_worker::Header, - ) -> ::subxt::runtime_api::Payload< - types::OffchainWorker, - types::offchain_worker::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "OffchainWorkerApi", - "offchain_worker", - types::OffchainWorker { header }, - [ - 10u8, 135u8, 19u8, 153u8, 33u8, 216u8, 18u8, 242u8, 33u8, 140u8, 4u8, - 223u8, 200u8, 130u8, 103u8, 118u8, 137u8, 24u8, 19u8, 127u8, 161u8, - 29u8, 184u8, 111u8, 222u8, 111u8, 253u8, 73u8, 45u8, 31u8, 79u8, 60u8, - ], - ) - } - } - pub mod types { - use super::runtime_types; - pub mod offchain_worker { - use super::runtime_types; - pub type Header = - runtime_types::sp_runtime::generic::header::Header<::core::primitive::u32>; - pub mod output { - use super::runtime_types; - pub type Output = (); - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct OffchainWorker { - pub header: offchain_worker::Header, - } - } - } - pub mod aura_api { - use super::{root_mod, runtime_types}; - #[doc = " API necessary for block authorship with aura."] - pub struct AuraApi; - impl AuraApi { - #[doc = " Returns the slot duration for Aura."] - #[doc = ""] - #[doc = " Currently, only the value provided by this type at genesis will be used."] - pub fn slot_duration( - &self, - ) -> ::subxt::runtime_api::Payload< - types::SlotDuration, - types::slot_duration::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "AuraApi", - "slot_duration", - types::SlotDuration {}, - [ - 233u8, 210u8, 132u8, 172u8, 100u8, 125u8, 239u8, 92u8, 114u8, 82u8, - 7u8, 110u8, 179u8, 196u8, 10u8, 19u8, 211u8, 15u8, 174u8, 2u8, 91u8, - 73u8, 133u8, 100u8, 205u8, 201u8, 191u8, 60u8, 163u8, 122u8, 215u8, - 10u8, - ], - ) - } - - #[doc = " Return the current set of authorities."] - pub fn authorities( - &self, - ) -> ::subxt::runtime_api::Payload< - types::Authorities, - types::authorities::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "AuraApi", - "authorities", - types::Authorities {}, - [ - 96u8, 136u8, 226u8, 244u8, 105u8, 189u8, 8u8, 250u8, 71u8, 230u8, 37u8, - 123u8, 218u8, 47u8, 179u8, 16u8, 170u8, 181u8, 165u8, 77u8, 102u8, - 51u8, 43u8, 51u8, 186u8, 84u8, 49u8, 15u8, 208u8, 226u8, 129u8, 230u8, - ], - ) - } - } - pub mod types { - use super::runtime_types; - pub mod slot_duration { - use super::runtime_types; - pub mod output { - use super::runtime_types; - pub type Output = runtime_types::sp_consensus_slots::SlotDuration; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct SlotDuration {} - pub mod authorities { - use super::runtime_types; - pub mod output { - use super::runtime_types; - pub type Output = ::std::vec::Vec< - runtime_types::sp_consensus_aura::sr25519::app_sr25519::Public, - >; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Authorities {} - } - } - pub mod session_keys { - use super::{root_mod, runtime_types}; - #[doc = " Session keys runtime api."] - pub struct SessionKeys; - impl SessionKeys { - #[doc = " Generate a set of session keys with optionally using the given seed."] - #[doc = " The keys should be stored within the keystore exposed via runtime"] - #[doc = " externalities."] - #[doc = ""] - #[doc = " The seed needs to be a valid `utf8` string."] - #[doc = ""] - #[doc = " Returns the concatenated SCALE encoded public keys."] - pub fn generate_session_keys( - &self, - seed: types::generate_session_keys::Seed, - ) -> ::subxt::runtime_api::Payload< - types::GenerateSessionKeys, - types::generate_session_keys::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "SessionKeys", - "generate_session_keys", - types::GenerateSessionKeys { seed }, - [ - 96u8, 171u8, 164u8, 166u8, 175u8, 102u8, 101u8, 47u8, 133u8, 95u8, - 102u8, 202u8, 83u8, 26u8, 238u8, 47u8, 126u8, 132u8, 22u8, 11u8, 33u8, - 190u8, 175u8, 94u8, 58u8, 245u8, 46u8, 80u8, 195u8, 184u8, 107u8, 65u8, - ], - ) - } - - #[doc = " Decode the given public session keys."] - #[doc = ""] - #[doc = " Returns the list of public raw public keys + key type."] - pub fn decode_session_keys( - &self, - encoded: types::decode_session_keys::Encoded, - ) -> ::subxt::runtime_api::Payload< - types::DecodeSessionKeys, - types::decode_session_keys::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "SessionKeys", - "decode_session_keys", - types::DecodeSessionKeys { encoded }, - [ - 57u8, 242u8, 18u8, 51u8, 132u8, 110u8, 238u8, 255u8, 39u8, 194u8, 8u8, - 54u8, 198u8, 178u8, 75u8, 151u8, 148u8, 176u8, 144u8, 197u8, 87u8, - 29u8, 179u8, 235u8, 176u8, 78u8, 252u8, 103u8, 72u8, 203u8, 151u8, - 248u8, - ], - ) - } - } - pub mod types { - use super::runtime_types; - pub mod generate_session_keys { - use super::runtime_types; - pub type Seed = ::core::option::Option<::std::vec::Vec<::core::primitive::u8>>; - pub mod output { - use super::runtime_types; - pub type Output = ::std::vec::Vec<::core::primitive::u8>; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct GenerateSessionKeys { - pub seed: generate_session_keys::Seed, - } - pub mod decode_session_keys { - use super::runtime_types; - pub type Encoded = ::std::vec::Vec<::core::primitive::u8>; - pub mod output { - use super::runtime_types; - pub type Output = ::core::option::Option< - ::std::vec::Vec<( - ::std::vec::Vec<::core::primitive::u8>, - runtime_types::sp_core::crypto::KeyTypeId, - )>, - >; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct DecodeSessionKeys { - pub encoded: decode_session_keys::Encoded, - } - } - } - pub mod grandpa_api { - use super::{root_mod, runtime_types}; - #[doc = " APIs for integrating the GRANDPA finality gadget into runtimes."] - #[doc = " This should be implemented on the runtime side."] - #[doc = ""] - #[doc = " This is primarily used for negotiating authority-set changes for the"] - #[doc = " gadget. GRANDPA uses a signaling model of changing authority sets:"] - #[doc = " changes should be signaled with a delay of N blocks, and then automatically"] - #[doc = " applied in the runtime after those N blocks have passed."] - #[doc = ""] - #[doc = " The consensus protocol will coordinate the handoff externally."] - pub struct GrandpaApi; - impl GrandpaApi { - #[doc = " Get the current GRANDPA authorities and weights. This should not change except"] - #[doc = " for when changes are scheduled and the corresponding delay has passed."] - #[doc = ""] - #[doc = " When called at block B, it will return the set of authorities that should be"] - #[doc = " used to finalize descendants of this block (B+1, B+2, ...). The block B itself"] - #[doc = " is finalized by the authorities from block B-1."] - pub fn grandpa_authorities( - &self, - ) -> ::subxt::runtime_api::Payload< - types::GrandpaAuthorities, - types::grandpa_authorities::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "GrandpaApi", - "grandpa_authorities", - types::GrandpaAuthorities {}, - [ - 166u8, 76u8, 160u8, 101u8, 242u8, 145u8, 213u8, 10u8, 16u8, 130u8, - 230u8, 196u8, 125u8, 152u8, 92u8, 143u8, 119u8, 223u8, 140u8, 189u8, - 203u8, 95u8, 52u8, 105u8, 147u8, 107u8, 135u8, 228u8, 62u8, 178u8, - 128u8, 33u8, - ], - ) - } - - #[doc = " Submits an unsigned extrinsic to report an equivocation. The caller"] - #[doc = " must provide the equivocation proof and a key ownership proof"] - #[doc = " (should be obtained using `generate_key_ownership_proof`). The"] - #[doc = " extrinsic will be unsigned and should only be accepted for local"] - #[doc = " authorship (not to be broadcast to the network). This method returns"] - #[doc = " `None` when creation of the extrinsic fails, e.g. if equivocation"] - #[doc = " reporting is disabled for the given runtime (i.e. this method is"] - #[doc = " hardcoded to return `None`). Only useful in an offchain context."] - pub fn submit_report_equivocation_unsigned_extrinsic( - &self, - equivocation_proof : types :: submit_report_equivocation_unsigned_extrinsic :: EquivocationProof, - key_owner_proof : types :: submit_report_equivocation_unsigned_extrinsic :: KeyOwnerProof, - ) -> ::subxt::runtime_api::Payload< - types::SubmitReportEquivocationUnsignedExtrinsic, - types::submit_report_equivocation_unsigned_extrinsic::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "GrandpaApi", - "submit_report_equivocation_unsigned_extrinsic", - types::SubmitReportEquivocationUnsignedExtrinsic { - equivocation_proof, - key_owner_proof, - }, - [ - 112u8, 94u8, 150u8, 250u8, 132u8, 127u8, 185u8, 24u8, 113u8, 62u8, - 28u8, 171u8, 83u8, 9u8, 41u8, 228u8, 92u8, 137u8, 29u8, 190u8, 214u8, - 232u8, 100u8, 66u8, 100u8, 168u8, 149u8, 122u8, 93u8, 17u8, 236u8, - 104u8, - ], - ) - } - - #[doc = " Generates a proof of key ownership for the given authority in the"] - #[doc = " given set. An example usage of this module is coupled with the"] - #[doc = " session historical module to prove that a given authority key is"] - #[doc = " tied to a given staking identity during a specific session. Proofs"] - #[doc = " of key ownership are necessary for submitting equivocation reports."] - #[doc = " NOTE: even though the API takes a `set_id` as parameter the current"] - #[doc = " implementations ignore this parameter and instead rely on this"] - #[doc = " method being called at the correct block height, i.e. any point at"] - #[doc = " which the given set id is live on-chain. Future implementations will"] - #[doc = " instead use indexed data through an offchain worker, not requiring"] - #[doc = " older states to be available."] - pub fn generate_key_ownership_proof( - &self, - set_id: types::generate_key_ownership_proof::SetId, - authority_id: types::generate_key_ownership_proof::AuthorityId, - ) -> ::subxt::runtime_api::Payload< - types::GenerateKeyOwnershipProof, - types::generate_key_ownership_proof::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "GrandpaApi", - "generate_key_ownership_proof", - types::GenerateKeyOwnershipProof { set_id, authority_id }, - [ - 40u8, 126u8, 113u8, 27u8, 245u8, 45u8, 123u8, 138u8, 12u8, 3u8, 125u8, - 186u8, 151u8, 53u8, 186u8, 93u8, 13u8, 150u8, 163u8, 176u8, 206u8, - 89u8, 244u8, 127u8, 182u8, 85u8, 203u8, 41u8, 101u8, 183u8, 209u8, - 179u8, - ], - ) - } - - #[doc = " Get current GRANDPA authority set id."] - pub fn current_set_id( - &self, - ) -> ::subxt::runtime_api::Payload< - types::CurrentSetId, - types::current_set_id::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "GrandpaApi", - "current_set_id", - types::CurrentSetId {}, - [ - 42u8, 230u8, 120u8, 211u8, 156u8, 245u8, 109u8, 86u8, 100u8, 146u8, - 234u8, 205u8, 41u8, 183u8, 109u8, 42u8, 17u8, 33u8, 156u8, 25u8, 139u8, - 84u8, 101u8, 75u8, 232u8, 198u8, 87u8, 136u8, 218u8, 233u8, 103u8, - 156u8, - ], - ) - } - } - pub mod types { - use super::runtime_types; - pub mod grandpa_authorities { - use super::runtime_types; - pub mod output { - use super::runtime_types; - pub type Output = ::std::vec::Vec<( - runtime_types::sp_consensus_grandpa::app::Public, - ::core::primitive::u64, - )>; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct GrandpaAuthorities {} - pub mod submit_report_equivocation_unsigned_extrinsic { - use super::runtime_types; - pub type EquivocationProof = - runtime_types::sp_consensus_grandpa::EquivocationProof< - ::subxt::utils::H256, - ::core::primitive::u32, - >; - pub type KeyOwnerProof = - runtime_types::sp_consensus_grandpa::OpaqueKeyOwnershipProof; - pub mod output { - use super::runtime_types; - pub type Output = ::core::option::Option<()>; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct SubmitReportEquivocationUnsignedExtrinsic { - pub equivocation_proof: - submit_report_equivocation_unsigned_extrinsic::EquivocationProof, - pub key_owner_proof: - submit_report_equivocation_unsigned_extrinsic::KeyOwnerProof, - } - pub mod generate_key_ownership_proof { - use super::runtime_types; - pub type SetId = ::core::primitive::u64; - pub type AuthorityId = runtime_types::sp_consensus_grandpa::app::Public; - pub mod output { - use super::runtime_types; - pub type Output = ::core::option::Option< - runtime_types::sp_consensus_grandpa::OpaqueKeyOwnershipProof, - >; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct GenerateKeyOwnershipProof { - pub set_id: generate_key_ownership_proof::SetId, - pub authority_id: generate_key_ownership_proof::AuthorityId, - } - pub mod current_set_id { - use super::runtime_types; - pub mod output { - use super::runtime_types; - pub type Output = ::core::primitive::u64; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct CurrentSetId {} - } - } - pub mod account_nonce_api { - use super::{root_mod, runtime_types}; - #[doc = " The API to query account nonce."] - pub struct AccountNonceApi; - impl AccountNonceApi { - #[doc = " Get current account nonce of given `AccountId`."] - pub fn account_nonce( - &self, - account: types::account_nonce::Account, - ) -> ::subxt::runtime_api::Payload< - types::AccountNonce, - types::account_nonce::output::Output, - > { - ::subxt::runtime_api::Payload::new_static( - "AccountNonceApi", - "account_nonce", - types::AccountNonce { account }, - [ - 231u8, 82u8, 7u8, 227u8, 131u8, 2u8, 215u8, 252u8, 173u8, 82u8, 11u8, - 103u8, 200u8, 25u8, 114u8, 116u8, 79u8, 229u8, 152u8, 150u8, 236u8, - 37u8, 101u8, 26u8, 220u8, 146u8, 182u8, 101u8, 73u8, 55u8, 191u8, - 171u8, - ], - ) - } - } - pub mod types { - use super::runtime_types; - pub mod account_nonce { - use super::runtime_types; - pub type Account = ::subxt::utils::AccountId32; - pub mod output { - use super::runtime_types; - pub type Output = ::core::primitive::u32; - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct AccountNonce { - pub account: account_nonce::Account, - } - } - } - } - pub fn custom() -> CustomValuesApi { - CustomValuesApi - } - pub struct CustomValuesApi; - impl CustomValuesApi {} - pub struct ConstantsApi; - impl ConstantsApi { - pub fn system(&self) -> system::constants::ConstantsApi { - system::constants::ConstantsApi - } - - pub fn timestamp(&self) -> timestamp::constants::ConstantsApi { - timestamp::constants::ConstantsApi - } - - pub fn grandpa(&self) -> grandpa::constants::ConstantsApi { - grandpa::constants::ConstantsApi - } - } - pub struct StorageApi; - impl StorageApi { - pub fn system(&self) -> system::storage::StorageApi { - system::storage::StorageApi - } - - pub fn timestamp(&self) -> timestamp::storage::StorageApi { - timestamp::storage::StorageApi - } - - pub fn aura(&self) -> aura::storage::StorageApi { - aura::storage::StorageApi - } - - pub fn grandpa(&self) -> grandpa::storage::StorageApi { - grandpa::storage::StorageApi - } - - pub fn sudo(&self) -> sudo::storage::StorageApi { - sudo::storage::StorageApi - } - - pub fn chronicle(&self) -> chronicle::storage::StorageApi { - chronicle::storage::StorageApi - } - - pub fn opa(&self) -> opa::storage::StorageApi { - opa::storage::StorageApi - } - } - pub struct TransactionApi; - impl TransactionApi { - pub fn system(&self) -> system::calls::TransactionApi { - system::calls::TransactionApi - } - - pub fn timestamp(&self) -> timestamp::calls::TransactionApi { - timestamp::calls::TransactionApi - } - - pub fn grandpa(&self) -> grandpa::calls::TransactionApi { - grandpa::calls::TransactionApi - } - - pub fn sudo(&self) -> sudo::calls::TransactionApi { - sudo::calls::TransactionApi - } - - pub fn chronicle(&self) -> chronicle::calls::TransactionApi { - chronicle::calls::TransactionApi - } - - pub fn opa(&self) -> opa::calls::TransactionApi { - opa::calls::TransactionApi - } - } - #[doc = r" check whether the metadata provided is aligned with this statically generated code."] - pub fn is_codegen_valid_for(metadata: &::subxt::Metadata) -> bool { - let runtime_metadata_hash = metadata - .hasher() - .only_these_pallets(&PALLETS) - .only_these_runtime_apis(&RUNTIME_APIS) - .hash(); - runtime_metadata_hash - == [ - 132u8, 151u8, 134u8, 46u8, 233u8, 247u8, 71u8, 77u8, 208u8, 250u8, 224u8, 194u8, - 87u8, 250u8, 180u8, 8u8, 171u8, 141u8, 155u8, 124u8, 69u8, 131u8, 176u8, 140u8, - 166u8, 22u8, 252u8, 16u8, 219u8, 185u8, 158u8, 56u8, - ] - } - pub mod system { - use super::{root_mod, runtime_types}; - #[doc = "Error for the System pallet"] - pub type Error = runtime_types::frame_system::pallet::Error; - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::frame_system::pallet::Call; - pub mod calls { - use super::{root_mod, runtime_types}; - type DispatchError = runtime_types::sp_runtime::DispatchError; - pub mod types { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::remark`]."] - pub struct Remark { - pub remark: remark::Remark, - } - pub mod remark { - use super::runtime_types; - pub type Remark = ::std::vec::Vec<::core::primitive::u8>; - } - impl ::subxt::blocks::StaticExtrinsic for Remark { - const CALL: &'static str = "remark"; - const PALLET: &'static str = "System"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::set_heap_pages`]."] - pub struct SetHeapPages { - pub pages: set_heap_pages::Pages, - } - pub mod set_heap_pages { - use super::runtime_types; - pub type Pages = ::core::primitive::u64; - } - impl ::subxt::blocks::StaticExtrinsic for SetHeapPages { - const CALL: &'static str = "set_heap_pages"; - const PALLET: &'static str = "System"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::set_code`]."] - pub struct SetCode { - pub code: set_code::Code, - } - pub mod set_code { - use super::runtime_types; - pub type Code = ::std::vec::Vec<::core::primitive::u8>; - } - impl ::subxt::blocks::StaticExtrinsic for SetCode { - const CALL: &'static str = "set_code"; - const PALLET: &'static str = "System"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::set_code_without_checks`]."] - pub struct SetCodeWithoutChecks { - pub code: set_code_without_checks::Code, - } - pub mod set_code_without_checks { - use super::runtime_types; - pub type Code = ::std::vec::Vec<::core::primitive::u8>; - } - impl ::subxt::blocks::StaticExtrinsic for SetCodeWithoutChecks { - const CALL: &'static str = "set_code_without_checks"; - const PALLET: &'static str = "System"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::set_storage`]."] - pub struct SetStorage { - pub items: set_storage::Items, - } - pub mod set_storage { - use super::runtime_types; - pub type Items = ::std::vec::Vec<( - ::std::vec::Vec<::core::primitive::u8>, - ::std::vec::Vec<::core::primitive::u8>, - )>; - } - impl ::subxt::blocks::StaticExtrinsic for SetStorage { - const CALL: &'static str = "set_storage"; - const PALLET: &'static str = "System"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::kill_storage`]."] - pub struct KillStorage { - pub keys: kill_storage::Keys, - } - pub mod kill_storage { - use super::runtime_types; - pub type Keys = ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>>; - } - impl ::subxt::blocks::StaticExtrinsic for KillStorage { - const CALL: &'static str = "kill_storage"; - const PALLET: &'static str = "System"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::kill_prefix`]."] - pub struct KillPrefix { - pub prefix: kill_prefix::Prefix, - pub subkeys: kill_prefix::Subkeys, - } - pub mod kill_prefix { - use super::runtime_types; - pub type Prefix = ::std::vec::Vec<::core::primitive::u8>; - pub type Subkeys = ::core::primitive::u32; - } - impl ::subxt::blocks::StaticExtrinsic for KillPrefix { - const CALL: &'static str = "kill_prefix"; - const PALLET: &'static str = "System"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::remark_with_event`]."] - pub struct RemarkWithEvent { - pub remark: remark_with_event::Remark, - } - pub mod remark_with_event { - use super::runtime_types; - pub type Remark = ::std::vec::Vec<::core::primitive::u8>; - } - impl ::subxt::blocks::StaticExtrinsic for RemarkWithEvent { - const CALL: &'static str = "remark_with_event"; - const PALLET: &'static str = "System"; - } - } - pub struct TransactionApi; - impl TransactionApi { - #[doc = "See [`Pallet::remark`]."] - pub fn remark( - &self, - remark: types::remark::Remark, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "System", - "remark", - types::Remark { remark }, - [ - 43u8, 126u8, 180u8, 174u8, 141u8, 48u8, 52u8, 125u8, 166u8, 212u8, - 216u8, 98u8, 100u8, 24u8, 132u8, 71u8, 101u8, 64u8, 246u8, 169u8, 33u8, - 250u8, 147u8, 208u8, 2u8, 40u8, 129u8, 209u8, 232u8, 207u8, 207u8, - 13u8, - ], - ) - } - - #[doc = "See [`Pallet::set_heap_pages`]."] - pub fn set_heap_pages( - &self, - pages: types::set_heap_pages::Pages, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "System", - "set_heap_pages", - types::SetHeapPages { pages }, - [ - 188u8, 191u8, 99u8, 216u8, 219u8, 109u8, 141u8, 50u8, 78u8, 235u8, - 215u8, 242u8, 195u8, 24u8, 111u8, 76u8, 229u8, 64u8, 99u8, 225u8, - 134u8, 121u8, 81u8, 209u8, 127u8, 223u8, 98u8, 215u8, 150u8, 70u8, - 57u8, 147u8, - ], - ) - } - - #[doc = "See [`Pallet::set_code`]."] - pub fn set_code( - &self, - code: types::set_code::Code, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "System", - "set_code", - types::SetCode { code }, - [ - 233u8, 248u8, 88u8, 245u8, 28u8, 65u8, 25u8, 169u8, 35u8, 237u8, 19u8, - 203u8, 136u8, 160u8, 18u8, 3u8, 20u8, 197u8, 81u8, 169u8, 244u8, 188u8, - 27u8, 147u8, 147u8, 236u8, 65u8, 25u8, 3u8, 143u8, 182u8, 22u8, - ], - ) - } - - #[doc = "See [`Pallet::set_code_without_checks`]."] - pub fn set_code_without_checks( - &self, - code: types::set_code_without_checks::Code, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "System", - "set_code_without_checks", - types::SetCodeWithoutChecks { code }, - [ - 82u8, 212u8, 157u8, 44u8, 70u8, 0u8, 143u8, 15u8, 109u8, 109u8, 107u8, - 157u8, 141u8, 42u8, 169u8, 11u8, 15u8, 186u8, 252u8, 138u8, 10u8, - 147u8, 15u8, 178u8, 247u8, 229u8, 213u8, 98u8, 207u8, 231u8, 119u8, - 115u8, - ], - ) - } - - #[doc = "See [`Pallet::set_storage`]."] - pub fn set_storage( - &self, - items: types::set_storage::Items, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "System", - "set_storage", - types::SetStorage { items }, - [ - 141u8, 216u8, 52u8, 222u8, 223u8, 136u8, 123u8, 181u8, 19u8, 75u8, - 163u8, 102u8, 229u8, 189u8, 158u8, 142u8, 95u8, 235u8, 240u8, 49u8, - 150u8, 76u8, 78u8, 137u8, 126u8, 88u8, 183u8, 88u8, 231u8, 146u8, - 234u8, 43u8, - ], - ) - } - - #[doc = "See [`Pallet::kill_storage`]."] - pub fn kill_storage( - &self, - keys: types::kill_storage::Keys, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "System", - "kill_storage", - types::KillStorage { keys }, - [ - 73u8, 63u8, 196u8, 36u8, 144u8, 114u8, 34u8, 213u8, 108u8, 93u8, 209u8, - 234u8, 153u8, 185u8, 33u8, 91u8, 187u8, 195u8, 223u8, 130u8, 58u8, - 156u8, 63u8, 47u8, 228u8, 249u8, 216u8, 139u8, 143u8, 177u8, 41u8, - 35u8, - ], - ) - } - - #[doc = "See [`Pallet::kill_prefix`]."] - pub fn kill_prefix( - &self, - prefix: types::kill_prefix::Prefix, - subkeys: types::kill_prefix::Subkeys, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "System", - "kill_prefix", - types::KillPrefix { prefix, subkeys }, - [ - 184u8, 57u8, 139u8, 24u8, 208u8, 87u8, 108u8, 215u8, 198u8, 189u8, - 175u8, 242u8, 167u8, 215u8, 97u8, 63u8, 110u8, 166u8, 238u8, 98u8, - 67u8, 236u8, 111u8, 110u8, 234u8, 81u8, 102u8, 5u8, 182u8, 5u8, 214u8, - 85u8, - ], - ) - } - - #[doc = "See [`Pallet::remark_with_event`]."] - pub fn remark_with_event( - &self, - remark: types::remark_with_event::Remark, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "System", - "remark_with_event", - types::RemarkWithEvent { remark }, - [ - 120u8, 120u8, 153u8, 92u8, 184u8, 85u8, 34u8, 2u8, 174u8, 206u8, 105u8, - 228u8, 233u8, 130u8, 80u8, 246u8, 228u8, 59u8, 234u8, 240u8, 4u8, 49u8, - 147u8, 170u8, 115u8, 91u8, 149u8, 200u8, 228u8, 181u8, 8u8, 154u8, - ], - ) - } - } - } - #[doc = "Event for the System pallet."] - pub type Event = runtime_types::frame_system::pallet::Event; - pub mod events { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "An extrinsic completed successfully."] - pub struct ExtrinsicSuccess { - pub dispatch_info: extrinsic_success::DispatchInfo, - } - pub mod extrinsic_success { - use super::runtime_types; - pub type DispatchInfo = runtime_types::frame_support::dispatch::DispatchInfo; - } - impl ::subxt::events::StaticEvent for ExtrinsicSuccess { - const EVENT: &'static str = "ExtrinsicSuccess"; - const PALLET: &'static str = "System"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "An extrinsic failed."] - pub struct ExtrinsicFailed { - pub dispatch_error: extrinsic_failed::DispatchError, - pub dispatch_info: extrinsic_failed::DispatchInfo, - } - pub mod extrinsic_failed { - use super::runtime_types; - pub type DispatchError = runtime_types::sp_runtime::DispatchError; - pub type DispatchInfo = runtime_types::frame_support::dispatch::DispatchInfo; - } - impl ::subxt::events::StaticEvent for ExtrinsicFailed { - const EVENT: &'static str = "ExtrinsicFailed"; - const PALLET: &'static str = "System"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "`:code` was updated."] - pub struct CodeUpdated; - impl ::subxt::events::StaticEvent for CodeUpdated { - const EVENT: &'static str = "CodeUpdated"; - const PALLET: &'static str = "System"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "A new account was created."] - pub struct NewAccount { - pub account: new_account::Account, - } - pub mod new_account { - use super::runtime_types; - pub type Account = ::subxt::utils::AccountId32; - } - impl ::subxt::events::StaticEvent for NewAccount { - const EVENT: &'static str = "NewAccount"; - const PALLET: &'static str = "System"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "An account was reaped."] - pub struct KilledAccount { - pub account: killed_account::Account, - } - pub mod killed_account { - use super::runtime_types; - pub type Account = ::subxt::utils::AccountId32; - } - impl ::subxt::events::StaticEvent for KilledAccount { - const EVENT: &'static str = "KilledAccount"; - const PALLET: &'static str = "System"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "On on-chain remark happened."] - pub struct Remarked { - pub sender: remarked::Sender, - pub hash: remarked::Hash, - } - pub mod remarked { - use super::runtime_types; - pub type Sender = ::subxt::utils::AccountId32; - pub type Hash = ::subxt::utils::H256; - } - impl ::subxt::events::StaticEvent for Remarked { - const EVENT: &'static str = "Remarked"; - const PALLET: &'static str = "System"; - } - } - pub mod storage { - use super::runtime_types; - pub mod types { - use super::runtime_types; - pub mod account { - use super::runtime_types; - pub type Account = - runtime_types::frame_system::AccountInfo<::core::primitive::u32, ()>; - pub type Param0 = ::subxt::utils::AccountId32; - } - pub mod extrinsic_count { - use super::runtime_types; - pub type ExtrinsicCount = ::core::primitive::u32; - } - pub mod block_weight { - use super::runtime_types; - pub type BlockWeight = runtime_types::frame_support::dispatch::PerDispatchClass< - runtime_types::sp_weights::weight_v2::Weight, - >; - } - pub mod all_extrinsics_len { - use super::runtime_types; - pub type AllExtrinsicsLen = ::core::primitive::u32; - } - pub mod block_hash { - use super::runtime_types; - pub type BlockHash = ::subxt::utils::H256; - pub type Param0 = ::core::primitive::u32; - } - pub mod extrinsic_data { - use super::runtime_types; - pub type ExtrinsicData = ::std::vec::Vec<::core::primitive::u8>; - pub type Param0 = ::core::primitive::u32; - } - pub mod number { - use super::runtime_types; - pub type Number = ::core::primitive::u32; - } - pub mod parent_hash { - use super::runtime_types; - pub type ParentHash = ::subxt::utils::H256; - } - pub mod digest { - use super::runtime_types; - pub type Digest = runtime_types::sp_runtime::generic::digest::Digest; - } - pub mod events { - use super::runtime_types; - pub type Events = ::std::vec::Vec< - runtime_types::frame_system::EventRecord< - runtime_types::runtime_chronicle::RuntimeEvent, - ::subxt::utils::H256, - >, - >; - } - pub mod event_count { - use super::runtime_types; - pub type EventCount = ::core::primitive::u32; - } - pub mod event_topics { - use super::runtime_types; - pub type EventTopics = - ::std::vec::Vec<(::core::primitive::u32, ::core::primitive::u32)>; - pub type Param0 = ::subxt::utils::H256; - } - pub mod last_runtime_upgrade { - use super::runtime_types; - pub type LastRuntimeUpgrade = - runtime_types::frame_system::LastRuntimeUpgradeInfo; - } - pub mod upgraded_to_u32_ref_count { - use super::runtime_types; - pub type UpgradedToU32RefCount = ::core::primitive::bool; - } - pub mod upgraded_to_triple_ref_count { - use super::runtime_types; - pub type UpgradedToTripleRefCount = ::core::primitive::bool; - } - pub mod execution_phase { - use super::runtime_types; - pub type ExecutionPhase = runtime_types::frame_system::Phase; - } - } - pub struct StorageApi; - impl StorageApi { - #[doc = " The full account information for a particular account ID."] - pub fn account_iter( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::account::Account, - (), - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - > { - ::subxt::storage::address::Address::new_static( - "System", - "Account", - vec![], - [ - 207u8, 128u8, 217u8, 6u8, 244u8, 231u8, 113u8, 230u8, 246u8, 220u8, - 226u8, 62u8, 206u8, 203u8, 104u8, 119u8, 181u8, 97u8, 211u8, 3u8, - 157u8, 102u8, 196u8, 131u8, 51u8, 221u8, 41u8, 183u8, 108u8, 28u8, - 247u8, 73u8, - ], - ) - } - - #[doc = " The full account information for a particular account ID."] - pub fn account( - &self, - _0: impl ::std::borrow::Borrow, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::account::Account, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "Account", - vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], - [ - 207u8, 128u8, 217u8, 6u8, 244u8, 231u8, 113u8, 230u8, 246u8, 220u8, - 226u8, 62u8, 206u8, 203u8, 104u8, 119u8, 181u8, 97u8, 211u8, 3u8, - 157u8, 102u8, 196u8, 131u8, 51u8, 221u8, 41u8, 183u8, 108u8, 28u8, - 247u8, 73u8, - ], - ) - } - - #[doc = " Total extrinsics count for the current block."] - pub fn extrinsic_count( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::extrinsic_count::ExtrinsicCount, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "ExtrinsicCount", - vec![], - [ - 102u8, 76u8, 236u8, 42u8, 40u8, 231u8, 33u8, 222u8, 123u8, 147u8, - 153u8, 148u8, 234u8, 203u8, 181u8, 119u8, 6u8, 187u8, 177u8, 199u8, - 120u8, 47u8, 137u8, 254u8, 96u8, 100u8, 165u8, 182u8, 249u8, 230u8, - 159u8, 79u8, - ], - ) - } - - #[doc = " The current weight for the block."] - pub fn block_weight( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::block_weight::BlockWeight, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "BlockWeight", - vec![], - [ - 158u8, 46u8, 228u8, 89u8, 210u8, 214u8, 84u8, 154u8, 50u8, 68u8, 63u8, - 62u8, 43u8, 42u8, 99u8, 27u8, 54u8, 42u8, 146u8, 44u8, 241u8, 216u8, - 229u8, 30u8, 216u8, 255u8, 165u8, 238u8, 181u8, 130u8, 36u8, 102u8, - ], - ) - } - - #[doc = " Total length (in bytes) for all extrinsics put together, for the current block."] - pub fn all_extrinsics_len( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::all_extrinsics_len::AllExtrinsicsLen, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "AllExtrinsicsLen", - vec![], - [ - 117u8, 86u8, 61u8, 243u8, 41u8, 51u8, 102u8, 214u8, 137u8, 100u8, - 243u8, 185u8, 122u8, 174u8, 187u8, 117u8, 86u8, 189u8, 63u8, 135u8, - 101u8, 218u8, 203u8, 201u8, 237u8, 254u8, 128u8, 183u8, 169u8, 221u8, - 242u8, 65u8, - ], - ) - } - - #[doc = " Map of block numbers to block hashes."] - pub fn block_hash_iter( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::block_hash::BlockHash, - (), - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - > { - ::subxt::storage::address::Address::new_static( - "System", - "BlockHash", - vec![], - [ - 217u8, 32u8, 215u8, 253u8, 24u8, 182u8, 207u8, 178u8, 157u8, 24u8, - 103u8, 100u8, 195u8, 165u8, 69u8, 152u8, 112u8, 181u8, 56u8, 192u8, - 164u8, 16u8, 20u8, 222u8, 28u8, 214u8, 144u8, 142u8, 146u8, 69u8, - 202u8, 118u8, - ], - ) - } - - #[doc = " Map of block numbers to block hashes."] - pub fn block_hash( - &self, - _0: impl ::std::borrow::Borrow, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::block_hash::BlockHash, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "BlockHash", - vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], - [ - 217u8, 32u8, 215u8, 253u8, 24u8, 182u8, 207u8, 178u8, 157u8, 24u8, - 103u8, 100u8, 195u8, 165u8, 69u8, 152u8, 112u8, 181u8, 56u8, 192u8, - 164u8, 16u8, 20u8, 222u8, 28u8, 214u8, 144u8, 142u8, 146u8, 69u8, - 202u8, 118u8, - ], - ) - } - - #[doc = " Extrinsics data for the current block (maps an extrinsic's index to its data)."] - pub fn extrinsic_data_iter( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::extrinsic_data::ExtrinsicData, - (), - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - > { - ::subxt::storage::address::Address::new_static( - "System", - "ExtrinsicData", - vec![], - [ - 160u8, 180u8, 122u8, 18u8, 196u8, 26u8, 2u8, 37u8, 115u8, 232u8, 133u8, - 220u8, 106u8, 245u8, 4u8, 129u8, 42u8, 84u8, 241u8, 45u8, 199u8, 179u8, - 128u8, 61u8, 170u8, 137u8, 231u8, 156u8, 247u8, 57u8, 47u8, 38u8, - ], - ) - } - - #[doc = " Extrinsics data for the current block (maps an extrinsic's index to its data)."] - pub fn extrinsic_data( - &self, - _0: impl ::std::borrow::Borrow, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::extrinsic_data::ExtrinsicData, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "ExtrinsicData", - vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], - [ - 160u8, 180u8, 122u8, 18u8, 196u8, 26u8, 2u8, 37u8, 115u8, 232u8, 133u8, - 220u8, 106u8, 245u8, 4u8, 129u8, 42u8, 84u8, 241u8, 45u8, 199u8, 179u8, - 128u8, 61u8, 170u8, 137u8, 231u8, 156u8, 247u8, 57u8, 47u8, 38u8, - ], - ) - } - - #[doc = " The current block number being processed. Set by `execute_block`."] - pub fn number( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::number::Number, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "Number", - vec![], - [ - 30u8, 194u8, 177u8, 90u8, 194u8, 232u8, 46u8, 180u8, 85u8, 129u8, 14u8, - 9u8, 8u8, 8u8, 23u8, 95u8, 230u8, 5u8, 13u8, 105u8, 125u8, 2u8, 22u8, - 200u8, 78u8, 93u8, 115u8, 28u8, 150u8, 113u8, 48u8, 53u8, - ], - ) - } - - #[doc = " Hash of the previous block."] - pub fn parent_hash( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::parent_hash::ParentHash, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "ParentHash", - vec![], - [ - 26u8, 130u8, 11u8, 216u8, 155u8, 71u8, 128u8, 170u8, 30u8, 153u8, 21u8, - 192u8, 62u8, 93u8, 137u8, 80u8, 120u8, 81u8, 202u8, 94u8, 248u8, 125u8, - 71u8, 82u8, 141u8, 229u8, 32u8, 56u8, 73u8, 50u8, 101u8, 78u8, - ], - ) - } - - #[doc = " Digest of the current block, also part of the block header."] - pub fn digest( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::digest::Digest, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "Digest", - vec![], - [ - 61u8, 64u8, 237u8, 91u8, 145u8, 232u8, 17u8, 254u8, 181u8, 16u8, 234u8, - 91u8, 51u8, 140u8, 254u8, 131u8, 98u8, 135u8, 21u8, 37u8, 251u8, 20u8, - 58u8, 92u8, 123u8, 141u8, 14u8, 227u8, 146u8, 46u8, 222u8, 117u8, - ], - ) - } - - #[doc = " Events deposited for the current block."] - #[doc = ""] - #[doc = " NOTE: The item is unbound and should therefore never be read on chain."] - #[doc = " It could otherwise inflate the PoV size of a block."] - #[doc = ""] - #[doc = " Events have a large in-memory size. Box the events to not go out-of-memory"] - #[doc = " just in case someone still reads them from within the runtime."] - pub fn events( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::events::Events, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "Events", - vec![], - [ - 47u8, 5u8, 76u8, 40u8, 21u8, 207u8, 254u8, 42u8, 181u8, 203u8, 152u8, - 15u8, 76u8, 55u8, 70u8, 116u8, 60u8, 212u8, 81u8, 157u8, 220u8, 244u8, - 168u8, 174u8, 57u8, 37u8, 145u8, 109u8, 39u8, 83u8, 134u8, 248u8, - ], - ) - } - - #[doc = " The number of events in the `Events` list."] - pub fn event_count( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::event_count::EventCount, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "EventCount", - vec![], - [ - 175u8, 24u8, 252u8, 184u8, 210u8, 167u8, 146u8, 143u8, 164u8, 80u8, - 151u8, 205u8, 189u8, 189u8, 55u8, 220u8, 47u8, 101u8, 181u8, 33u8, - 254u8, 131u8, 13u8, 143u8, 3u8, 244u8, 245u8, 45u8, 2u8, 210u8, 79u8, - 133u8, - ], - ) - } - - #[doc = " Mapping between a topic (represented by T::Hash) and a vector of indexes"] - #[doc = " of events in the `>` list."] - #[doc = ""] - #[doc = " All topic vectors have deterministic storage locations depending on the topic. This"] - #[doc = " allows light-clients to leverage the changes trie storage tracking mechanism and"] - #[doc = " in case of changes fetch the list of events of interest."] - #[doc = ""] - #[doc = " The value has the type `(BlockNumberFor, EventIndex)` because if we used only just"] - #[doc = " the `EventIndex` then in case if the topic has the same contents on the next block"] - #[doc = " no notification will be triggered thus the event might be lost."] - pub fn event_topics_iter( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::event_topics::EventTopics, - (), - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - > { - ::subxt::storage::address::Address::new_static( - "System", - "EventTopics", - vec![], - [ - 40u8, 225u8, 14u8, 75u8, 44u8, 176u8, 76u8, 34u8, 143u8, 107u8, 69u8, - 133u8, 114u8, 13u8, 172u8, 250u8, 141u8, 73u8, 12u8, 65u8, 217u8, 63u8, - 120u8, 241u8, 48u8, 106u8, 143u8, 161u8, 128u8, 100u8, 166u8, 59u8, - ], - ) - } - - #[doc = " Mapping between a topic (represented by T::Hash) and a vector of indexes"] - #[doc = " of events in the `>` list."] - #[doc = ""] - #[doc = " All topic vectors have deterministic storage locations depending on the topic. This"] - #[doc = " allows light-clients to leverage the changes trie storage tracking mechanism and"] - #[doc = " in case of changes fetch the list of events of interest."] - #[doc = ""] - #[doc = " The value has the type `(BlockNumberFor, EventIndex)` because if we used only just"] - #[doc = " the `EventIndex` then in case if the topic has the same contents on the next block"] - #[doc = " no notification will be triggered thus the event might be lost."] - pub fn event_topics( - &self, - _0: impl ::std::borrow::Borrow, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::event_topics::EventTopics, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "EventTopics", - vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], - [ - 40u8, 225u8, 14u8, 75u8, 44u8, 176u8, 76u8, 34u8, 143u8, 107u8, 69u8, - 133u8, 114u8, 13u8, 172u8, 250u8, 141u8, 73u8, 12u8, 65u8, 217u8, 63u8, - 120u8, 241u8, 48u8, 106u8, 143u8, 161u8, 128u8, 100u8, 166u8, 59u8, - ], - ) - } - - #[doc = " Stores the `spec_version` and `spec_name` of when the last runtime upgrade happened."] - pub fn last_runtime_upgrade( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::last_runtime_upgrade::LastRuntimeUpgrade, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "LastRuntimeUpgrade", - vec![], - [ - 137u8, 29u8, 175u8, 75u8, 197u8, 208u8, 91u8, 207u8, 156u8, 87u8, - 148u8, 68u8, 91u8, 140u8, 22u8, 233u8, 1u8, 229u8, 56u8, 34u8, 40u8, - 194u8, 253u8, 30u8, 163u8, 39u8, 54u8, 209u8, 13u8, 27u8, 139u8, 184u8, - ], - ) - } - - #[doc = " True if we have upgraded so that `type RefCount` is `u32`. False (default) if not."] - pub fn upgraded_to_u32_ref_count( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::upgraded_to_u32_ref_count::UpgradedToU32RefCount, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "UpgradedToU32RefCount", - vec![], - [ - 229u8, 73u8, 9u8, 132u8, 186u8, 116u8, 151u8, 171u8, 145u8, 29u8, 34u8, - 130u8, 52u8, 146u8, 124u8, 175u8, 79u8, 189u8, 147u8, 230u8, 234u8, - 107u8, 124u8, 31u8, 2u8, 22u8, 86u8, 190u8, 4u8, 147u8, 50u8, 245u8, - ], - ) - } - - #[doc = " True if we have upgraded so that AccountInfo contains three types of `RefCount`. False"] - #[doc = " (default) if not."] - pub fn upgraded_to_triple_ref_count( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::upgraded_to_triple_ref_count::UpgradedToTripleRefCount, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "UpgradedToTripleRefCount", - vec![], - [ - 97u8, 66u8, 124u8, 243u8, 27u8, 167u8, 147u8, 81u8, 254u8, 201u8, - 101u8, 24u8, 40u8, 231u8, 14u8, 179u8, 154u8, 163u8, 71u8, 81u8, 185u8, - 167u8, 82u8, 254u8, 189u8, 3u8, 101u8, 207u8, 206u8, 194u8, 155u8, - 151u8, - ], - ) - } - - #[doc = " The execution phase of the block."] - pub fn execution_phase( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::execution_phase::ExecutionPhase, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "System", - "ExecutionPhase", - vec![], - [ - 191u8, 129u8, 100u8, 134u8, 126u8, 116u8, 154u8, 203u8, 220u8, 200u8, - 0u8, 26u8, 161u8, 250u8, 133u8, 205u8, 146u8, 24u8, 5u8, 156u8, 158u8, - 35u8, 36u8, 253u8, 52u8, 235u8, 86u8, 167u8, 35u8, 100u8, 119u8, 27u8, - ], - ) - } - } - } - pub mod constants { - use super::runtime_types; - pub struct ConstantsApi; - impl ConstantsApi { - #[doc = " Block & extrinsics weights: base values and limits."] - pub fn block_weights( - &self, - ) -> ::subxt::constants::Address - { - ::subxt::constants::Address::new_static( - "System", - "BlockWeights", - [ - 176u8, 124u8, 225u8, 136u8, 25u8, 73u8, 247u8, 33u8, 82u8, 206u8, 85u8, - 190u8, 127u8, 102u8, 71u8, 11u8, 185u8, 8u8, 58u8, 0u8, 94u8, 55u8, - 163u8, 177u8, 104u8, 59u8, 60u8, 136u8, 246u8, 116u8, 0u8, 239u8, - ], - ) - } - - #[doc = " The maximum length of a block (in bytes)."] - pub fn block_length( - &self, - ) -> ::subxt::constants::Address { - ::subxt::constants::Address::new_static( - "System", - "BlockLength", - [ - 23u8, 242u8, 225u8, 39u8, 225u8, 67u8, 152u8, 41u8, 155u8, 104u8, 68u8, - 229u8, 185u8, 133u8, 10u8, 143u8, 184u8, 152u8, 234u8, 44u8, 140u8, - 96u8, 166u8, 235u8, 162u8, 160u8, 72u8, 7u8, 35u8, 194u8, 3u8, 37u8, - ], - ) - } - - #[doc = " Maximum number of block number to block hash mappings to keep (oldest pruned first)."] - pub fn block_hash_count( - &self, - ) -> ::subxt::constants::Address<::core::primitive::u32> { - ::subxt::constants::Address::new_static( - "System", - "BlockHashCount", - [ - 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, - 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, - 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, - 145u8, - ], - ) - } - - #[doc = " The weight of runtime database operations the runtime can invoke."] - pub fn db_weight( - &self, - ) -> ::subxt::constants::Address { - ::subxt::constants::Address::new_static( - "System", - "DbWeight", - [ - 42u8, 43u8, 178u8, 142u8, 243u8, 203u8, 60u8, 173u8, 118u8, 111u8, - 200u8, 170u8, 102u8, 70u8, 237u8, 187u8, 198u8, 120u8, 153u8, 232u8, - 183u8, 76u8, 74u8, 10u8, 70u8, 243u8, 14u8, 218u8, 213u8, 126u8, 29u8, - 177u8, - ], - ) - } - - #[doc = " Get the chain's current version."] - pub fn version( - &self, - ) -> ::subxt::constants::Address { - ::subxt::constants::Address::new_static( - "System", - "Version", - [ - 219u8, 45u8, 162u8, 245u8, 177u8, 246u8, 48u8, 126u8, 191u8, 157u8, - 228u8, 83u8, 111u8, 133u8, 183u8, 13u8, 148u8, 108u8, 92u8, 102u8, - 72u8, 205u8, 74u8, 242u8, 233u8, 79u8, 20u8, 170u8, 72u8, 202u8, 158u8, - 165u8, - ], - ) - } - - #[doc = " The designated SS58 prefix of this chain."] - #[doc = ""] - #[doc = " This replaces the \"ss58Format\" property declared in the chain spec. Reason is"] - #[doc = " that the runtime should know about the prefix in order to make use of it as"] - #[doc = " an identifier of the chain."] - pub fn ss58_prefix(&self) -> ::subxt::constants::Address<::core::primitive::u16> { - ::subxt::constants::Address::new_static( - "System", - "SS58Prefix", - [ - 116u8, 33u8, 2u8, 170u8, 181u8, 147u8, 171u8, 169u8, 167u8, 227u8, - 41u8, 144u8, 11u8, 236u8, 82u8, 100u8, 74u8, 60u8, 184u8, 72u8, 169u8, - 90u8, 208u8, 135u8, 15u8, 117u8, 10u8, 123u8, 128u8, 193u8, 29u8, 70u8, - ], - ) - } - } - } - } - pub mod timestamp { - use super::{root_mod, runtime_types}; - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_timestamp::pallet::Call; - pub mod calls { - use super::{root_mod, runtime_types}; - type DispatchError = runtime_types::sp_runtime::DispatchError; - pub mod types { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::set`]."] - pub struct Set { - #[codec(compact)] - pub now: set::Now, - } - pub mod set { - use super::runtime_types; - pub type Now = ::core::primitive::u64; - } - impl ::subxt::blocks::StaticExtrinsic for Set { - const CALL: &'static str = "set"; - const PALLET: &'static str = "Timestamp"; - } - } - pub struct TransactionApi; - impl TransactionApi { - #[doc = "See [`Pallet::set`]."] - pub fn set(&self, now: types::set::Now) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "Timestamp", - "set", - types::Set { now }, - [ - 37u8, 95u8, 49u8, 218u8, 24u8, 22u8, 0u8, 95u8, 72u8, 35u8, 155u8, - 199u8, 213u8, 54u8, 207u8, 22u8, 185u8, 193u8, 221u8, 70u8, 18u8, - 200u8, 4u8, 231u8, 195u8, 173u8, 6u8, 122u8, 11u8, 203u8, 231u8, 227u8, - ], - ) - } - } - } - pub mod storage { - use super::runtime_types; - pub mod types { - use super::runtime_types; - pub mod now { - use super::runtime_types; - pub type Now = ::core::primitive::u64; - } - pub mod did_update { - use super::runtime_types; - pub type DidUpdate = ::core::primitive::bool; - } - } - pub struct StorageApi; - impl StorageApi { - #[doc = " The current time for the current block."] - pub fn now( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::now::Now, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "Timestamp", - "Now", - vec![], - [ - 44u8, 50u8, 80u8, 30u8, 195u8, 146u8, 123u8, 238u8, 8u8, 163u8, 187u8, - 92u8, 61u8, 39u8, 51u8, 29u8, 173u8, 169u8, 217u8, 158u8, 85u8, 187u8, - 141u8, 26u8, 12u8, 115u8, 51u8, 11u8, 200u8, 244u8, 138u8, 152u8, - ], - ) - } - - #[doc = " Whether the timestamp has been updated in this block."] - #[doc = ""] - #[doc = " This value is updated to `true` upon successful submission of a timestamp by a node."] - #[doc = " It is then checked at the end of each block execution in the `on_finalize` hook."] - pub fn did_update( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::did_update::DidUpdate, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "Timestamp", - "DidUpdate", - vec![], - [ - 229u8, 175u8, 246u8, 102u8, 237u8, 158u8, 212u8, 229u8, 238u8, 214u8, - 205u8, 160u8, 164u8, 252u8, 195u8, 75u8, 139u8, 110u8, 22u8, 34u8, - 248u8, 204u8, 107u8, 46u8, 20u8, 200u8, 238u8, 167u8, 71u8, 41u8, - 214u8, 140u8, - ], - ) - } - } - } - pub mod constants { - use super::runtime_types; - pub struct ConstantsApi; - impl ConstantsApi { - #[doc = " The minimum period between blocks."] - #[doc = ""] - #[doc = " Be aware that this is different to the *expected* period that the block production"] - #[doc = " apparatus provides. Your chosen consensus system will generally work with this to"] - #[doc = " determine a sensible block time. For example, in the Aura pallet it will be double this"] - #[doc = " period on default settings."] - pub fn minimum_period( - &self, - ) -> ::subxt::constants::Address<::core::primitive::u64> { - ::subxt::constants::Address::new_static( - "Timestamp", - "MinimumPeriod", - [ - 128u8, 214u8, 205u8, 242u8, 181u8, 142u8, 124u8, 231u8, 190u8, 146u8, - 59u8, 226u8, 157u8, 101u8, 103u8, 117u8, 249u8, 65u8, 18u8, 191u8, - 103u8, 119u8, 53u8, 85u8, 81u8, 96u8, 220u8, 42u8, 184u8, 239u8, 42u8, - 246u8, - ], - ) - } - } - } - } - pub mod aura { - use super::{root_mod, runtime_types}; - pub mod storage { - use super::runtime_types; - pub mod types { - use super::runtime_types; - pub mod authorities { - use super::runtime_types; - pub type Authorities = - runtime_types::bounded_collections::bounded_vec::BoundedVec< - runtime_types::sp_consensus_aura::sr25519::app_sr25519::Public, - >; - } - pub mod current_slot { - use super::runtime_types; - pub type CurrentSlot = runtime_types::sp_consensus_slots::Slot; - } - } - pub struct StorageApi; - impl StorageApi { - #[doc = " The current authority set."] - pub fn authorities( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::authorities::Authorities, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "Aura", - "Authorities", - vec![], - [ - 232u8, 129u8, 167u8, 104u8, 47u8, 188u8, 238u8, 164u8, 6u8, 29u8, - 129u8, 45u8, 64u8, 182u8, 194u8, 47u8, 0u8, 73u8, 63u8, 102u8, 204u8, - 94u8, 111u8, 96u8, 137u8, 7u8, 141u8, 110u8, 180u8, 80u8, 228u8, 16u8, - ], - ) - } - - #[doc = " The current slot of this block."] - #[doc = ""] - #[doc = " This will be set in `on_initialize`."] - pub fn current_slot( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::current_slot::CurrentSlot, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "Aura", - "CurrentSlot", - vec![], - [ - 112u8, 199u8, 115u8, 248u8, 217u8, 242u8, 45u8, 231u8, 178u8, 53u8, - 236u8, 167u8, 219u8, 238u8, 81u8, 243u8, 39u8, 140u8, 68u8, 19u8, - 201u8, 169u8, 211u8, 133u8, 135u8, 213u8, 150u8, 105u8, 60u8, 252u8, - 43u8, 57u8, - ], - ) - } - } - } - } - pub mod grandpa { - use super::{root_mod, runtime_types}; - #[doc = "The `Error` enum of this pallet."] - pub type Error = runtime_types::pallet_grandpa::pallet::Error; - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_grandpa::pallet::Call; - pub mod calls { - use super::{root_mod, runtime_types}; - type DispatchError = runtime_types::sp_runtime::DispatchError; - pub mod types { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::report_equivocation`]."] - pub struct ReportEquivocation { - pub equivocation_proof: - ::std::boxed::Box, - pub key_owner_proof: report_equivocation::KeyOwnerProof, - } - pub mod report_equivocation { - use super::runtime_types; - pub type EquivocationProof = - runtime_types::sp_consensus_grandpa::EquivocationProof< - ::subxt::utils::H256, - ::core::primitive::u32, - >; - pub type KeyOwnerProof = runtime_types::sp_core::Void; - } - impl ::subxt::blocks::StaticExtrinsic for ReportEquivocation { - const CALL: &'static str = "report_equivocation"; - const PALLET: &'static str = "Grandpa"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::report_equivocation_unsigned`]."] - pub struct ReportEquivocationUnsigned { - pub equivocation_proof: - ::std::boxed::Box, - pub key_owner_proof: report_equivocation_unsigned::KeyOwnerProof, - } - pub mod report_equivocation_unsigned { - use super::runtime_types; - pub type EquivocationProof = - runtime_types::sp_consensus_grandpa::EquivocationProof< - ::subxt::utils::H256, - ::core::primitive::u32, - >; - pub type KeyOwnerProof = runtime_types::sp_core::Void; - } - impl ::subxt::blocks::StaticExtrinsic for ReportEquivocationUnsigned { - const CALL: &'static str = "report_equivocation_unsigned"; - const PALLET: &'static str = "Grandpa"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::note_stalled`]."] - pub struct NoteStalled { - pub delay: note_stalled::Delay, - pub best_finalized_block_number: note_stalled::BestFinalizedBlockNumber, - } - pub mod note_stalled { - use super::runtime_types; - pub type Delay = ::core::primitive::u32; - pub type BestFinalizedBlockNumber = ::core::primitive::u32; - } - impl ::subxt::blocks::StaticExtrinsic for NoteStalled { - const CALL: &'static str = "note_stalled"; - const PALLET: &'static str = "Grandpa"; - } - } - pub struct TransactionApi; - impl TransactionApi { - #[doc = "See [`Pallet::report_equivocation`]."] - pub fn report_equivocation( - &self, - equivocation_proof: types::report_equivocation::EquivocationProof, - key_owner_proof: types::report_equivocation::KeyOwnerProof, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "Grandpa", - "report_equivocation", - types::ReportEquivocation { - equivocation_proof: ::std::boxed::Box::new(equivocation_proof), - key_owner_proof, - }, - [ - 158u8, 70u8, 189u8, 51u8, 231u8, 191u8, 199u8, 33u8, 64u8, 156u8, 71u8, - 243u8, 122u8, 199u8, 216u8, 10u8, 45u8, 73u8, 198u8, 141u8, 31u8, - 209u8, 58u8, 164u8, 219u8, 124u8, 242u8, 26u8, 114u8, 52u8, 65u8, - 106u8, - ], - ) - } - - #[doc = "See [`Pallet::report_equivocation_unsigned`]."] - pub fn report_equivocation_unsigned( - &self, - equivocation_proof: types::report_equivocation_unsigned::EquivocationProof, - key_owner_proof: types::report_equivocation_unsigned::KeyOwnerProof, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "Grandpa", - "report_equivocation_unsigned", - types::ReportEquivocationUnsigned { - equivocation_proof: ::std::boxed::Box::new(equivocation_proof), - key_owner_proof, - }, - [ - 53u8, 23u8, 255u8, 215u8, 105u8, 11u8, 67u8, 177u8, 234u8, 248u8, - 183u8, 57u8, 230u8, 239u8, 54u8, 238u8, 115u8, 170u8, 153u8, 18u8, - 55u8, 195u8, 85u8, 98u8, 109u8, 194u8, 57u8, 225u8, 139u8, 237u8, - 171u8, 152u8, - ], - ) - } - - #[doc = "See [`Pallet::note_stalled`]."] - pub fn note_stalled( - &self, - delay: types::note_stalled::Delay, - best_finalized_block_number: types::note_stalled::BestFinalizedBlockNumber, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "Grandpa", - "note_stalled", - types::NoteStalled { delay, best_finalized_block_number }, - [ - 158u8, 25u8, 64u8, 114u8, 131u8, 139u8, 227u8, 132u8, 42u8, 107u8, - 40u8, 249u8, 18u8, 93u8, 254u8, 86u8, 37u8, 67u8, 250u8, 35u8, 241u8, - 194u8, 209u8, 20u8, 39u8, 75u8, 186u8, 21u8, 48u8, 124u8, 151u8, 31u8, - ], - ) - } - } - } - #[doc = "The `Event` enum of this pallet"] - pub type Event = runtime_types::pallet_grandpa::pallet::Event; - pub mod events { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "New authority set has been applied."] - pub struct NewAuthorities { - pub authority_set: new_authorities::AuthoritySet, - } - pub mod new_authorities { - use super::runtime_types; - pub type AuthoritySet = ::std::vec::Vec<( - runtime_types::sp_consensus_grandpa::app::Public, - ::core::primitive::u64, - )>; - } - impl ::subxt::events::StaticEvent for NewAuthorities { - const EVENT: &'static str = "NewAuthorities"; - const PALLET: &'static str = "Grandpa"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "Current authority set has been paused."] - pub struct Paused; - impl ::subxt::events::StaticEvent for Paused { - const EVENT: &'static str = "Paused"; - const PALLET: &'static str = "Grandpa"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "Current authority set has been resumed."] - pub struct Resumed; - impl ::subxt::events::StaticEvent for Resumed { - const EVENT: &'static str = "Resumed"; - const PALLET: &'static str = "Grandpa"; - } - } - pub mod storage { - use super::runtime_types; - pub mod types { - use super::runtime_types; - pub mod state { - use super::runtime_types; - pub type State = - runtime_types::pallet_grandpa::StoredState<::core::primitive::u32>; - } - pub mod pending_change { - use super::runtime_types; - pub type PendingChange = - runtime_types::pallet_grandpa::StoredPendingChange<::core::primitive::u32>; - } - pub mod next_forced { - use super::runtime_types; - pub type NextForced = ::core::primitive::u32; - } - pub mod stalled { - use super::runtime_types; - pub type Stalled = (::core::primitive::u32, ::core::primitive::u32); - } - pub mod current_set_id { - use super::runtime_types; - pub type CurrentSetId = ::core::primitive::u64; - } - pub mod set_id_session { - use super::runtime_types; - pub type SetIdSession = ::core::primitive::u32; - pub type Param0 = ::core::primitive::u64; - } - } - pub struct StorageApi; - impl StorageApi { - #[doc = " State of the current authority set."] - pub fn state( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::state::State, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "Grandpa", - "State", - vec![], - [ - 73u8, 71u8, 112u8, 83u8, 238u8, 75u8, 44u8, 9u8, 180u8, 33u8, 30u8, - 121u8, 98u8, 96u8, 61u8, 133u8, 16u8, 70u8, 30u8, 249u8, 34u8, 148u8, - 15u8, 239u8, 164u8, 157u8, 52u8, 27u8, 144u8, 52u8, 223u8, 109u8, - ], - ) - } - - #[doc = " Pending change: (signaled at, scheduled change)."] - pub fn pending_change( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::pending_change::PendingChange, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "Grandpa", - "PendingChange", - vec![], - [ - 150u8, 194u8, 185u8, 248u8, 239u8, 43u8, 141u8, 253u8, 61u8, 106u8, - 74u8, 164u8, 209u8, 204u8, 206u8, 200u8, 32u8, 38u8, 11u8, 78u8, 84u8, - 243u8, 181u8, 142u8, 179u8, 151u8, 81u8, 204u8, 244u8, 150u8, 137u8, - 250u8, - ], - ) - } - - #[doc = " next block number where we can force a change."] - pub fn next_forced( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::next_forced::NextForced, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "Grandpa", - "NextForced", - vec![], - [ - 3u8, 231u8, 56u8, 18u8, 87u8, 112u8, 227u8, 126u8, 180u8, 131u8, 255u8, - 141u8, 82u8, 34u8, 61u8, 47u8, 234u8, 37u8, 95u8, 62u8, 33u8, 235u8, - 231u8, 122u8, 125u8, 8u8, 223u8, 95u8, 255u8, 204u8, 40u8, 97u8, - ], - ) - } - - #[doc = " `true` if we are currently stalled."] - pub fn stalled( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::stalled::Stalled, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "Grandpa", - "Stalled", - vec![], - [ - 6u8, 81u8, 205u8, 142u8, 195u8, 48u8, 0u8, 247u8, 108u8, 170u8, 10u8, - 249u8, 72u8, 206u8, 32u8, 103u8, 109u8, 57u8, 51u8, 21u8, 144u8, 204u8, - 79u8, 8u8, 191u8, 185u8, 38u8, 34u8, 118u8, 223u8, 75u8, 241u8, - ], - ) - } - - #[doc = " The number of changes (both in terms of keys and underlying economic responsibilities)"] - #[doc = " in the \"set\" of Grandpa validators from genesis."] - pub fn current_set_id( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::current_set_id::CurrentSetId, - ::subxt::storage::address::Yes, - ::subxt::storage::address::Yes, - (), - > { - ::subxt::storage::address::Address::new_static( - "Grandpa", - "CurrentSetId", - vec![], - [ - 234u8, 215u8, 218u8, 42u8, 30u8, 76u8, 129u8, 40u8, 125u8, 137u8, - 207u8, 47u8, 46u8, 213u8, 159u8, 50u8, 175u8, 81u8, 155u8, 123u8, - 246u8, 175u8, 156u8, 68u8, 22u8, 113u8, 135u8, 137u8, 163u8, 18u8, - 115u8, 73u8, - ], - ) - } - - #[doc = " A mapping from grandpa set ID to the index of the *most recent* session for which its"] - #[doc = " members were responsible."] - #[doc = ""] - #[doc = " This is only used for validating equivocation proofs. An equivocation proof must"] - #[doc = " contains a key-ownership proof for a given session, therefore we need a way to tie"] - #[doc = " together sessions and GRANDPA set ids, i.e. we need to validate that a validator"] - #[doc = " was the owner of a given key on a given session, and what the active set ID was"] - #[doc = " during that session."] - #[doc = ""] - #[doc = " TWOX-NOTE: `SetId` is not under user control."] - pub fn set_id_session_iter( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::set_id_session::SetIdSession, - (), - (), - ::subxt::storage::address::Yes, - > { - ::subxt::storage::address::Address::new_static( - "Grandpa", - "SetIdSession", - vec![], - [ - 47u8, 0u8, 239u8, 121u8, 187u8, 213u8, 254u8, 50u8, 238u8, 10u8, 162u8, - 65u8, 189u8, 166u8, 37u8, 74u8, 82u8, 81u8, 160u8, 20u8, 180u8, 253u8, - 238u8, 18u8, 209u8, 203u8, 38u8, 148u8, 16u8, 105u8, 72u8, 169u8, - ], - ) - } - - #[doc = " A mapping from grandpa set ID to the index of the *most recent* session for which its"] - #[doc = " members were responsible."] - #[doc = ""] - #[doc = " This is only used for validating equivocation proofs. An equivocation proof must"] - #[doc = " contains a key-ownership proof for a given session, therefore we need a way to tie"] - #[doc = " together sessions and GRANDPA set ids, i.e. we need to validate that a validator"] - #[doc = " was the owner of a given key on a given session, and what the active set ID was"] - #[doc = " during that session."] - #[doc = ""] - #[doc = " TWOX-NOTE: `SetId` is not under user control."] - pub fn set_id_session( - &self, - _0: impl ::std::borrow::Borrow, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::set_id_session::SetIdSession, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "Grandpa", - "SetIdSession", - vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], - [ - 47u8, 0u8, 239u8, 121u8, 187u8, 213u8, 254u8, 50u8, 238u8, 10u8, 162u8, - 65u8, 189u8, 166u8, 37u8, 74u8, 82u8, 81u8, 160u8, 20u8, 180u8, 253u8, - 238u8, 18u8, 209u8, 203u8, 38u8, 148u8, 16u8, 105u8, 72u8, 169u8, - ], - ) - } - } - } - pub mod constants { - use super::runtime_types; - pub struct ConstantsApi; - impl ConstantsApi { - #[doc = " Max Authorities in use"] - pub fn max_authorities( - &self, - ) -> ::subxt::constants::Address<::core::primitive::u32> { - ::subxt::constants::Address::new_static( - "Grandpa", - "MaxAuthorities", - [ - 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, - 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, - 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, - 145u8, - ], - ) - } - - #[doc = " The maximum number of nominators for each validator."] - pub fn max_nominators( - &self, - ) -> ::subxt::constants::Address<::core::primitive::u32> { - ::subxt::constants::Address::new_static( - "Grandpa", - "MaxNominators", - [ - 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, - 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, - 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, - 145u8, - ], - ) - } - - #[doc = " The maximum number of entries to keep in the set id to session index mapping."] - #[doc = ""] - #[doc = " Since the `SetIdSession` map is only used for validating equivocations this"] - #[doc = " value should relate to the bonding duration of whatever staking system is"] - #[doc = " being used (if any). If equivocation handling is not enabled then this value"] - #[doc = " can be zero."] - pub fn max_set_id_session_entries( - &self, - ) -> ::subxt::constants::Address<::core::primitive::u64> { - ::subxt::constants::Address::new_static( - "Grandpa", - "MaxSetIdSessionEntries", - [ - 128u8, 214u8, 205u8, 242u8, 181u8, 142u8, 124u8, 231u8, 190u8, 146u8, - 59u8, 226u8, 157u8, 101u8, 103u8, 117u8, 249u8, 65u8, 18u8, 191u8, - 103u8, 119u8, 53u8, 85u8, 81u8, 96u8, 220u8, 42u8, 184u8, 239u8, 42u8, - 246u8, - ], - ) - } - } - } - } - pub mod sudo { - use super::{root_mod, runtime_types}; - #[doc = "Error for the Sudo pallet"] - pub type Error = runtime_types::pallet_sudo::pallet::Error; - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_sudo::pallet::Call; - pub mod calls { - use super::{root_mod, runtime_types}; - type DispatchError = runtime_types::sp_runtime::DispatchError; - pub mod types { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::sudo`]."] - pub struct Sudo { - pub call: ::std::boxed::Box, - } - pub mod sudo { - use super::runtime_types; - pub type Call = runtime_types::runtime_chronicle::RuntimeCall; - } - impl ::subxt::blocks::StaticExtrinsic for Sudo { - const CALL: &'static str = "sudo"; - const PALLET: &'static str = "Sudo"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::sudo_unchecked_weight`]."] - pub struct SudoUncheckedWeight { - pub call: ::std::boxed::Box, - pub weight: sudo_unchecked_weight::Weight, - } - pub mod sudo_unchecked_weight { - use super::runtime_types; - pub type Call = runtime_types::runtime_chronicle::RuntimeCall; - pub type Weight = runtime_types::sp_weights::weight_v2::Weight; - } - impl ::subxt::blocks::StaticExtrinsic for SudoUncheckedWeight { - const CALL: &'static str = "sudo_unchecked_weight"; - const PALLET: &'static str = "Sudo"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::set_key`]."] - pub struct SetKey { - pub new: set_key::New, - } - pub mod set_key { - use super::runtime_types; - pub type New = ::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()>; - } - impl ::subxt::blocks::StaticExtrinsic for SetKey { - const CALL: &'static str = "set_key"; - const PALLET: &'static str = "Sudo"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::sudo_as`]."] - pub struct SudoAs { - pub who: sudo_as::Who, - pub call: ::std::boxed::Box, - } - pub mod sudo_as { - use super::runtime_types; - pub type Who = ::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()>; - pub type Call = runtime_types::runtime_chronicle::RuntimeCall; - } - impl ::subxt::blocks::StaticExtrinsic for SudoAs { - const CALL: &'static str = "sudo_as"; - const PALLET: &'static str = "Sudo"; - } - } - pub struct TransactionApi; - impl TransactionApi { - #[doc = "See [`Pallet::sudo`]."] - pub fn sudo(&self, call: types::sudo::Call) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "Sudo", - "sudo", - types::Sudo { call: ::std::boxed::Box::new(call) }, - [ - 237u8, 167u8, 188u8, 42u8, 53u8, 81u8, 128u8, 15u8, 168u8, 39u8, 8u8, - 134u8, 49u8, 136u8, 251u8, 162u8, 141u8, 66u8, 243u8, 169u8, 44u8, - 68u8, 82u8, 232u8, 87u8, 62u8, 193u8, 74u8, 68u8, 123u8, 241u8, 151u8, - ], - ) - } - - #[doc = "See [`Pallet::sudo_unchecked_weight`]."] - pub fn sudo_unchecked_weight( - &self, - call: types::sudo_unchecked_weight::Call, - weight: types::sudo_unchecked_weight::Weight, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "Sudo", - "sudo_unchecked_weight", - types::SudoUncheckedWeight { call: ::std::boxed::Box::new(call), weight }, - [ - 191u8, 162u8, 221u8, 59u8, 231u8, 212u8, 11u8, 144u8, 158u8, 138u8, - 158u8, 143u8, 73u8, 173u8, 231u8, 102u8, 250u8, 172u8, 214u8, 16u8, - 184u8, 159u8, 182u8, 106u8, 161u8, 61u8, 28u8, 251u8, 117u8, 159u8, - 255u8, 124u8, - ], - ) - } - - #[doc = "See [`Pallet::set_key`]."] - pub fn set_key( - &self, - new: types::set_key::New, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "Sudo", - "set_key", - types::SetKey { new }, - [ - 9u8, 73u8, 39u8, 205u8, 188u8, 127u8, 143u8, 54u8, 128u8, 94u8, 8u8, - 227u8, 197u8, 44u8, 70u8, 93u8, 228u8, 196u8, 64u8, 165u8, 226u8, - 158u8, 101u8, 192u8, 22u8, 193u8, 102u8, 84u8, 21u8, 35u8, 92u8, 198u8, - ], - ) - } - - #[doc = "See [`Pallet::sudo_as`]."] - pub fn sudo_as( - &self, - who: types::sudo_as::Who, - call: types::sudo_as::Call, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "Sudo", - "sudo_as", - types::SudoAs { who, call: ::std::boxed::Box::new(call) }, - [ - 230u8, 21u8, 191u8, 185u8, 54u8, 39u8, 134u8, 240u8, 51u8, 145u8, - 105u8, 151u8, 191u8, 224u8, 205u8, 96u8, 71u8, 3u8, 149u8, 212u8, 92u8, - 9u8, 75u8, 107u8, 144u8, 158u8, 151u8, 129u8, 2u8, 45u8, 228u8, 118u8, - ], - ) - } - } - } - #[doc = "The `Event` enum of this pallet"] - pub type Event = runtime_types::pallet_sudo::pallet::Event; - pub mod events { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "A sudo call just took place."] - pub struct Sudid { - pub sudo_result: sudid::SudoResult, - } - pub mod sudid { - use super::runtime_types; - pub type SudoResult = - ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>; - } - impl ::subxt::events::StaticEvent for Sudid { - const EVENT: &'static str = "Sudid"; - const PALLET: &'static str = "Sudo"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "The sudo key has been updated."] - pub struct KeyChanged { - pub old_sudoer: key_changed::OldSudoer, - } - pub mod key_changed { - use super::runtime_types; - pub type OldSudoer = ::core::option::Option<::subxt::utils::AccountId32>; - } - impl ::subxt::events::StaticEvent for KeyChanged { - const EVENT: &'static str = "KeyChanged"; - const PALLET: &'static str = "Sudo"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "A [sudo_as](Pallet::sudo_as) call just took place."] - pub struct SudoAsDone { - pub sudo_result: sudo_as_done::SudoResult, - } - pub mod sudo_as_done { - use super::runtime_types; - pub type SudoResult = - ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>; - } - impl ::subxt::events::StaticEvent for SudoAsDone { - const EVENT: &'static str = "SudoAsDone"; - const PALLET: &'static str = "Sudo"; - } - } - pub mod storage { - use super::runtime_types; - pub mod types { - use super::runtime_types; - pub mod key { - use super::runtime_types; - pub type Key = ::subxt::utils::AccountId32; - } - } - pub struct StorageApi; - impl StorageApi { - #[doc = " The `AccountId` of the sudo key."] - pub fn key( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::key::Key, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "Sudo", - "Key", - vec![], - [ - 72u8, 14u8, 225u8, 162u8, 205u8, 247u8, 227u8, 105u8, 116u8, 57u8, 4u8, - 31u8, 84u8, 137u8, 227u8, 228u8, 133u8, 245u8, 206u8, 227u8, 117u8, - 36u8, 252u8, 151u8, 107u8, 15u8, 180u8, 4u8, 4u8, 152u8, 195u8, 144u8, - ], - ) - } - } - } - } - pub mod chronicle { - use super::{root_mod, runtime_types}; - #[doc = "The `Error` enum of this pallet."] - pub type Error = runtime_types::pallet_chronicle::pallet::Error; - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_chronicle::pallet::Call; - pub mod calls { - use super::{root_mod, runtime_types}; - type DispatchError = runtime_types::sp_runtime::DispatchError; - pub mod types { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::apply`]."] - pub struct Apply { - pub operations: apply::Operations, - } - pub mod apply { - use super::runtime_types; - pub type Operations = runtime_types::common::ledger::OperationSubmission; - } - impl ::subxt::blocks::StaticExtrinsic for Apply { - const CALL: &'static str = "apply"; - const PALLET: &'static str = "Chronicle"; - } - } - pub struct TransactionApi; - impl TransactionApi { - #[doc = "See [`Pallet::apply`]."] - pub fn apply( - &self, - operations: types::apply::Operations, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "Chronicle", - "apply", - types::Apply { operations }, - [ - 155u8, 52u8, 231u8, 240u8, 97u8, 198u8, 219u8, 89u8, 101u8, 93u8, 60u8, - 206u8, 9u8, 244u8, 58u8, 69u8, 176u8, 61u8, 109u8, 126u8, 75u8, 178u8, - 195u8, 2u8, 158u8, 67u8, 158u8, 143u8, 9u8, 252u8, 61u8, 139u8, - ], - ) - } - } - } - #[doc = "The `Event` enum of this pallet"] - pub type Event = runtime_types::pallet_chronicle::pallet::Event; - pub mod events { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Applied(pub applied::Field0, pub applied::Field1, pub applied::Field2); - pub mod applied { - use super::runtime_types; - pub type Field0 = runtime_types::common::prov::model::ProvModel; - pub type Field1 = runtime_types::common::identity::SignedIdentity; - pub type Field2 = [::core::primitive::u8; 16usize]; - } - impl ::subxt::events::StaticEvent for Applied { - const EVENT: &'static str = "Applied"; - const PALLET: &'static str = "Chronicle"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Contradiction( - pub contradiction::Field0, - pub contradiction::Field1, - pub contradiction::Field2, - ); - pub mod contradiction { - use super::runtime_types; - pub type Field0 = runtime_types::common::prov::model::contradiction::Contradiction; - pub type Field1 = runtime_types::common::identity::SignedIdentity; - pub type Field2 = [::core::primitive::u8; 16usize]; - } - impl ::subxt::events::StaticEvent for Contradiction { - const EVENT: &'static str = "Contradiction"; - const PALLET: &'static str = "Chronicle"; - } - } - pub mod storage { - use super::runtime_types; - pub mod types { - use super::runtime_types; - pub mod provenance { - use super::runtime_types; - pub type Provenance = runtime_types::common::prov::model::ProvModel; - pub type Param0 = runtime_types::common::ledger::ChronicleAddress; - } - pub mod opa_settings { - use super::runtime_types; - pub type OpaSettings = - ::core::option::Option; - } - } - pub struct StorageApi; - impl StorageApi { - pub fn provenance_iter( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::provenance::Provenance, - (), - (), - ::subxt::storage::address::Yes, - > { - ::subxt::storage::address::Address::new_static( - "Chronicle", - "Provenance", - vec![], - [ - 89u8, 248u8, 19u8, 1u8, 96u8, 148u8, 157u8, 57u8, 205u8, 85u8, 157u8, - 10u8, 226u8, 22u8, 253u8, 189u8, 239u8, 95u8, 193u8, 72u8, 200u8, 4u8, - 236u8, 165u8, 80u8, 97u8, 150u8, 137u8, 142u8, 46u8, 37u8, 37u8, - ], - ) - } - - pub fn provenance( - &self, - _0: impl ::std::borrow::Borrow, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::provenance::Provenance, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "Chronicle", - "Provenance", - vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], - [ - 89u8, 248u8, 19u8, 1u8, 96u8, 148u8, 157u8, 57u8, 205u8, 85u8, 157u8, - 10u8, 226u8, 22u8, 253u8, 189u8, 239u8, 95u8, 193u8, 72u8, 200u8, 4u8, - 236u8, 165u8, 80u8, 97u8, 150u8, 137u8, 142u8, 46u8, 37u8, 37u8, - ], - ) - } - - pub fn opa_settings( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::opa_settings::OpaSettings, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "Chronicle", - "OpaSettings", - vec![], - [ - 147u8, 57u8, 197u8, 174u8, 245u8, 128u8, 185u8, 25u8, 59u8, 211u8, - 103u8, 144u8, 133u8, 65u8, 135u8, 26u8, 249u8, 122u8, 98u8, 119u8, - 113u8, 203u8, 8u8, 216u8, 144u8, 203u8, 28u8, 152u8, 76u8, 108u8, 17u8, - 149u8, - ], - ) - } - } - } - } - pub mod opa { - use super::{root_mod, runtime_types}; - #[doc = "The `Error` enum of this pallet."] - pub type Error = runtime_types::pallet_opa::pallet::Error; - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_opa::pallet::Call; - pub mod calls { - use super::{root_mod, runtime_types}; - type DispatchError = runtime_types::sp_runtime::DispatchError; - pub mod types { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "See [`Pallet::apply`]."] - pub struct Apply { - pub submission: apply::Submission, - } - pub mod apply { - use super::runtime_types; - pub type Submission = runtime_types::common::opa::core::codec::OpaSubmissionV1; - } - impl ::subxt::blocks::StaticExtrinsic for Apply { - const CALL: &'static str = "apply"; - const PALLET: &'static str = "Opa"; - } - } - pub struct TransactionApi; - impl TransactionApi { - #[doc = "See [`Pallet::apply`]."] - pub fn apply( - &self, - submission: types::apply::Submission, - ) -> ::subxt::tx::Payload { - ::subxt::tx::Payload::new_static( - "Opa", - "apply", - types::Apply { submission }, - [ - 234u8, 194u8, 237u8, 194u8, 37u8, 84u8, 219u8, 67u8, 228u8, 177u8, - 34u8, 4u8, 100u8, 5u8, 196u8, 246u8, 3u8, 28u8, 65u8, 188u8, 66u8, - 227u8, 204u8, 143u8, 143u8, 230u8, 11u8, 229u8, 77u8, 61u8, 108u8, - 19u8, - ], - ) - } - } - } - #[doc = "The `Event` enum of this pallet"] - pub type Event = runtime_types::pallet_opa::pallet::Event; - pub mod events { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct PolicyUpdate(pub policy_update::Field0, pub policy_update::Field1); - pub mod policy_update { - use super::runtime_types; - pub type Field0 = runtime_types::common::opa::core::codec::PolicyMetaV1; - pub type Field1 = runtime_types::common::prov::model::ChronicleTransactionId; - } - impl ::subxt::events::StaticEvent for PolicyUpdate { - const EVENT: &'static str = "PolicyUpdate"; - const PALLET: &'static str = "Opa"; - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct KeyUpdate(pub key_update::Field0, pub key_update::Field1); - pub mod key_update { - use super::runtime_types; - pub type Field0 = runtime_types::common::opa::core::codec::KeysV1; - pub type Field1 = runtime_types::common::prov::model::ChronicleTransactionId; - } - impl ::subxt::events::StaticEvent for KeyUpdate { - const EVENT: &'static str = "KeyUpdate"; - const PALLET: &'static str = "Opa"; - } - } - pub mod storage { - use super::runtime_types; - pub mod types { - use super::runtime_types; - pub mod policy_store { - use super::runtime_types; - pub type PolicyStore = runtime_types::common::opa::core::codec::PolicyV1; - pub type Param0 = runtime_types::common::opa::core::PolicyAddress; - } - pub mod policy_meta_store { - use super::runtime_types; - pub type PolicyMetaStore = - runtime_types::common::opa::core::codec::PolicyMetaV1; - pub type Param0 = runtime_types::common::opa::core::PolicyMetaAddress; - } - pub mod key_store { - use super::runtime_types; - pub type KeyStore = runtime_types::common::opa::core::codec::KeysV1; - pub type Param0 = runtime_types::common::opa::core::KeyAddress; - } - } - pub struct StorageApi; - impl StorageApi { - pub fn policy_store_iter( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::policy_store::PolicyStore, - (), - (), - ::subxt::storage::address::Yes, - > { - ::subxt::storage::address::Address::new_static( - "Opa", - "PolicyStore", - vec![], - [ - 196u8, 59u8, 202u8, 150u8, 122u8, 101u8, 78u8, 223u8, 11u8, 18u8, - 183u8, 27u8, 146u8, 220u8, 7u8, 187u8, 13u8, 188u8, 251u8, 24u8, 81u8, - 227u8, 248u8, 52u8, 162u8, 245u8, 38u8, 136u8, 20u8, 90u8, 197u8, - 181u8, - ], - ) - } - - pub fn policy_store( - &self, - _0: impl ::std::borrow::Borrow, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::policy_store::PolicyStore, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "Opa", - "PolicyStore", - vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], - [ - 196u8, 59u8, 202u8, 150u8, 122u8, 101u8, 78u8, 223u8, 11u8, 18u8, - 183u8, 27u8, 146u8, 220u8, 7u8, 187u8, 13u8, 188u8, 251u8, 24u8, 81u8, - 227u8, 248u8, 52u8, 162u8, 245u8, 38u8, 136u8, 20u8, 90u8, 197u8, - 181u8, - ], - ) - } - - pub fn policy_meta_store_iter( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::policy_meta_store::PolicyMetaStore, - (), - (), - ::subxt::storage::address::Yes, - > { - ::subxt::storage::address::Address::new_static( - "Opa", - "PolicyMetaStore", - vec![], - [ - 189u8, 108u8, 84u8, 44u8, 122u8, 229u8, 34u8, 242u8, 101u8, 92u8, - 113u8, 242u8, 103u8, 46u8, 77u8, 145u8, 102u8, 172u8, 41u8, 9u8, 189u8, - 102u8, 178u8, 31u8, 0u8, 164u8, 222u8, 220u8, 240u8, 91u8, 126u8, - 249u8, - ], - ) - } - - pub fn policy_meta_store( - &self, - _0: impl ::std::borrow::Borrow, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::policy_meta_store::PolicyMetaStore, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "Opa", - "PolicyMetaStore", - vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], - [ - 189u8, 108u8, 84u8, 44u8, 122u8, 229u8, 34u8, 242u8, 101u8, 92u8, - 113u8, 242u8, 103u8, 46u8, 77u8, 145u8, 102u8, 172u8, 41u8, 9u8, 189u8, - 102u8, 178u8, 31u8, 0u8, 164u8, 222u8, 220u8, 240u8, 91u8, 126u8, - 249u8, - ], - ) - } - - pub fn key_store_iter( - &self, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::key_store::KeyStore, - (), - (), - ::subxt::storage::address::Yes, - > { - ::subxt::storage::address::Address::new_static( - "Opa", - "KeyStore", - vec![], - [ - 169u8, 58u8, 57u8, 223u8, 245u8, 168u8, 156u8, 245u8, 216u8, 144u8, - 41u8, 29u8, 118u8, 241u8, 23u8, 231u8, 77u8, 178u8, 178u8, 237u8, 99u8, - 240u8, 13u8, 53u8, 27u8, 166u8, 232u8, 13u8, 61u8, 138u8, 218u8, 67u8, - ], - ) - } - - pub fn key_store( - &self, - _0: impl ::std::borrow::Borrow, - ) -> ::subxt::storage::address::Address< - ::subxt::storage::address::StaticStorageMapKey, - types::key_store::KeyStore, - ::subxt::storage::address::Yes, - (), - (), - > { - ::subxt::storage::address::Address::new_static( - "Opa", - "KeyStore", - vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], - [ - 169u8, 58u8, 57u8, 223u8, 245u8, 168u8, 156u8, 245u8, 216u8, 144u8, - 41u8, 29u8, 118u8, 241u8, 23u8, 231u8, 77u8, 178u8, 178u8, 237u8, 99u8, - 240u8, 13u8, 53u8, 27u8, 166u8, 232u8, 13u8, 61u8, 138u8, 218u8, 67u8, - ], - ) - } - } - } - } - pub mod runtime_types { - use super::runtime_types; - pub mod bounded_collections { - use super::runtime_types; - pub mod bounded_vec { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct BoundedVec<_0>(pub ::std::vec::Vec<_0>); - } - pub mod weak_bounded_vec { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct WeakBoundedVec<_0>(pub ::std::vec::Vec<_0>); - } - } - pub mod common { - use super::runtime_types; - pub mod attributes { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Attribute { - pub typ: ::std::string::String, - pub value: runtime_types::common::attributes::SerdeWrapper, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Attributes { - pub typ: ::core::option::Option, - pub items: ::subxt::utils::KeyedVec< - ::std::string::String, - runtime_types::common::attributes::Attribute, - >, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct SerdeWrapper(pub ::std::string::String); - } - pub mod identity { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct SignedIdentity { - pub identity: ::std::string::String, - pub signature: ::core::option::Option<::std::vec::Vec<::core::primitive::u8>>, - pub verifying_key: - ::core::option::Option<::std::vec::Vec<::core::primitive::u8>>, - } - } - pub mod ledger { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ChronicleAddress { - pub namespace: - ::core::option::Option, - pub resource: runtime_types::common::prov::id::ChronicleIri, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct OperationSubmission { - pub correlation_id: [::core::primitive::u8; 16usize], - pub items: ::std::vec::Vec< - runtime_types::common::prov::operations::ChronicleOperation, - >, - pub identity: runtime_types::common::identity::SignedIdentity, - } - } - pub mod opa { - use super::runtime_types; - pub mod core { - use super::runtime_types; - pub mod codec { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct BootstrapRootV1 { - pub public_key: runtime_types::common::opa::core::PemEncoded, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct KeyRegistrationV1 { - pub key: runtime_types::common::opa::core::PemEncoded, - pub version: ::core::primitive::u64, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct KeysV1 { - pub id: ::std::string::String, - pub current: runtime_types::common::opa::core::codec::KeyRegistrationV1, - pub expired: ::core::option::Option< - runtime_types::common::opa::core::codec::KeyRegistrationV1, - >, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct NewPublicKeyV1 { - pub public_key: runtime_types::common::opa::core::PemEncoded, - pub id: ::std::string::String, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct OpaSubmissionV1 { - pub version: ::std::string::String, - pub correlation_id: [::core::primitive::u8; 16usize], - pub span_id: ::core::primitive::u64, - pub payload: runtime_types::common::opa::core::codec::PayloadV1, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum OperationV1 { - #[codec(index = 0)] - RegisterKey(runtime_types::common::opa::core::codec::RegisterKeyV1), - #[codec(index = 1)] - RotateKey(runtime_types::common::opa::core::codec::RotateKeyV1), - #[codec(index = 2)] - SetPolicy(runtime_types::common::opa::core::codec::SetPolicyV1), - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum PayloadV1 { - #[codec(index = 0)] - BootstrapRoot(runtime_types::common::opa::core::codec::BootstrapRootV1), - #[codec(index = 1)] - SignedOperation( - runtime_types::common::opa::core::codec::SignedOperationV1, - ), - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct PolicyMetaV1 { - pub id: ::std::string::String, - pub hash: runtime_types::common::opa::core::H128, - pub policy_address: runtime_types::common::opa::core::PolicyAddress, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct PolicyV1(pub ::std::vec::Vec<::core::primitive::u8>); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct RegisterKeyV1 { - pub public_key: runtime_types::common::opa::core::PemEncoded, - pub id: ::std::string::String, - pub overwrite_existing: ::core::primitive::bool, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct RotateKeyV1 { - pub payload: runtime_types::common::opa::core::codec::NewPublicKeyV1, - pub previous_signing_key: runtime_types::common::opa::core::PemEncoded, - pub previous_signature: ::std::vec::Vec<::core::primitive::u8>, - pub new_signing_key: runtime_types::common::opa::core::PemEncoded, - pub new_signature: ::std::vec::Vec<::core::primitive::u8>, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct SetPolicyV1 { - pub id: ::std::string::String, - pub policy: runtime_types::common::opa::core::Policy, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct SignedOperationPayloadV1 { - pub operation: runtime_types::common::opa::core::codec::OperationV1, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct SignedOperationV1 { - pub payload: - runtime_types::common::opa::core::codec::SignedOperationPayloadV1, - pub verifying_key: runtime_types::common::opa::core::PemEncoded, - pub signature: ::std::vec::Vec<::core::primitive::u8>, - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct H128(pub [::core::primitive::u8; 16usize]); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct KeyAddress(pub runtime_types::common::opa::core::H128); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct OpaSettings { - pub policy_address: runtime_types::common::opa::core::PolicyAddress, - pub policy_name: ::std::string::String, - pub entrypoint: ::std::string::String, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct PemEncoded(pub ::std::string::String); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Policy(pub ::std::vec::Vec<::core::primitive::u8>); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct PolicyAddress(pub runtime_types::common::opa::core::H128); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct PolicyMetaAddress(pub runtime_types::common::opa::core::H128); - } - } - pub mod prov { - use super::runtime_types; - pub mod id { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ActivityId(pub runtime_types::common::prov::id::ExternalId); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct AgentId(pub runtime_types::common::prov::id::ExternalId); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct AssociationId { - pub agent: runtime_types::common::prov::id::ExternalId, - pub activity: runtime_types::common::prov::id::ExternalId, - pub role: ::core::option::Option, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct AttributionId { - pub agent: runtime_types::common::prov::id::ExternalId, - pub entity: runtime_types::common::prov::id::ExternalId, - pub role: ::core::option::Option, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum ChronicleIri { - #[codec(index = 0)] - Namespace(runtime_types::common::prov::id::NamespaceId), - #[codec(index = 1)] - Domaintype(runtime_types::common::prov::id::DomaintypeId), - #[codec(index = 2)] - Entity(runtime_types::common::prov::id::EntityId), - #[codec(index = 3)] - Agent(runtime_types::common::prov::id::AgentId), - #[codec(index = 4)] - Activity(runtime_types::common::prov::id::ActivityId), - #[codec(index = 5)] - Association(runtime_types::common::prov::id::AssociationId), - #[codec(index = 6)] - Attribution(runtime_types::common::prov::id::AttributionId), - #[codec(index = 7)] - Delegation(runtime_types::common::prov::id::DelegationId), - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct DelegationId { - pub delegate: runtime_types::common::prov::id::ExternalId, - pub responsible: runtime_types::common::prov::id::ExternalId, - pub activity: - ::core::option::Option, - pub role: ::core::option::Option, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct DomaintypeId(pub runtime_types::common::prov::id::ExternalId); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct EntityId(pub runtime_types::common::prov::id::ExternalId); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ExternalId(pub ::std::string::String); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct NamespaceId { - pub external_id: runtime_types::common::prov::id::ExternalId, - pub uuid: [::core::primitive::u8; 16usize], - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Role(pub ::std::string::String); - } - pub mod model { - use super::runtime_types; - pub mod contradiction { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Contradiction { pub id : runtime_types :: common :: prov :: id :: ChronicleIri , pub namespace : runtime_types :: common :: prov :: id :: NamespaceId , pub contradiction : :: std :: vec :: Vec < runtime_types :: common :: prov :: model :: contradiction :: ContradictionDetail > , } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum ContradictionDetail { - #[codec(index = 0)] - AttributeValueChange { - name: ::std::string::String, - value: runtime_types::common::attributes::Attribute, - attempted: runtime_types::common::attributes::Attribute, - }, - #[codec(index = 1)] - StartAlteration { - value: runtime_types::common::prov::operations::TimeWrapper, - attempted: runtime_types::common::prov::operations::TimeWrapper, - }, - #[codec(index = 2)] - EndAlteration { - value: runtime_types::common::prov::operations::TimeWrapper, - attempted: runtime_types::common::prov::operations::TimeWrapper, - }, - #[codec(index = 3)] - InvalidRange { - start: runtime_types::common::prov::operations::TimeWrapper, - end: runtime_types::common::prov::operations::TimeWrapper, - }, - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Activity { - pub id: runtime_types::common::prov::id::ActivityId, - pub namespace_id: runtime_types::common::prov::id::NamespaceId, - pub external_id: runtime_types::common::prov::id::ExternalId, - pub domaintype_id: - ::core::option::Option, - pub attributes: ::subxt::utils::KeyedVec< - ::std::string::String, - runtime_types::common::attributes::Attribute, - >, - pub started: ::core::option::Option< - runtime_types::common::prov::operations::TimeWrapper, - >, - pub ended: ::core::option::Option< - runtime_types::common::prov::operations::TimeWrapper, - >, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Agent { - pub id: runtime_types::common::prov::id::AgentId, - pub namespaceid: runtime_types::common::prov::id::NamespaceId, - pub external_id: runtime_types::common::prov::id::ExternalId, - pub domaintypeid: - ::core::option::Option, - pub attributes: ::subxt::utils::KeyedVec< - ::std::string::String, - runtime_types::common::attributes::Attribute, - >, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Association { - pub namespace_id: runtime_types::common::prov::id::NamespaceId, - pub id: runtime_types::common::prov::id::AssociationId, - pub agent_id: runtime_types::common::prov::id::AgentId, - pub activity_id: runtime_types::common::prov::id::ActivityId, - pub role: ::core::option::Option, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Attribution { - pub namespace_id: runtime_types::common::prov::id::NamespaceId, - pub id: runtime_types::common::prov::id::AttributionId, - pub agent_id: runtime_types::common::prov::id::AgentId, - pub entity_id: runtime_types::common::prov::id::EntityId, - pub role: ::core::option::Option, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ChronicleTransactionId(pub [::core::primitive::u8; 16usize]); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Delegation { - pub namespace_id: runtime_types::common::prov::id::NamespaceId, - pub id: runtime_types::common::prov::id::DelegationId, - pub delegate_id: runtime_types::common::prov::id::AgentId, - pub responsible_id: runtime_types::common::prov::id::AgentId, - pub activity_id: - ::core::option::Option, - pub role: ::core::option::Option, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Derivation { - pub generated_id: runtime_types::common::prov::id::EntityId, - pub used_id: runtime_types::common::prov::id::EntityId, - pub activity_id: - ::core::option::Option, - pub typ: runtime_types::common::prov::operations::DerivationType, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Entity { - pub id: runtime_types::common::prov::id::EntityId, - pub namespace_id: runtime_types::common::prov::id::NamespaceId, - pub external_id: runtime_types::common::prov::id::ExternalId, - pub domaintypeid: - ::core::option::Option, - pub attributes: ::subxt::utils::KeyedVec< - ::std::string::String, - runtime_types::common::attributes::Attribute, - >, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct GeneratedEntity { - pub entity_id: runtime_types::common::prov::id::EntityId, - pub generated_id: runtime_types::common::prov::id::ActivityId, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Generation { - pub activity_id: runtime_types::common::prov::id::ActivityId, - pub generated_id: runtime_types::common::prov::id::EntityId, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Namespace { - pub id: runtime_types::common::prov::id::NamespaceId, - pub uuid: [::core::primitive::u8; 16usize], - pub external_id: runtime_types::common::prov::id::ExternalId, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ProvModel { - pub namespaces: ::subxt::utils::KeyedVec< - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::model::Namespace, - >, - pub agents: ::subxt::utils::KeyedVec< - ( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::AgentId, - ), - runtime_types::common::prov::model::Agent, - >, - pub acted_on_behalf_of: ::subxt::utils::KeyedVec< - ( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::AgentId, - ), - ::std::vec::Vec, - >, - pub delegation: ::subxt::utils::KeyedVec< - ( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::AgentId, - ), - ::std::vec::Vec, - >, - pub entities: ::subxt::utils::KeyedVec< - ( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::EntityId, - ), - runtime_types::common::prov::model::Entity, - >, - pub derivation: ::subxt::utils::KeyedVec< - ( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::EntityId, - ), - ::std::vec::Vec, - >, - pub generation: ::subxt::utils::KeyedVec< - ( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::EntityId, - ), - ::std::vec::Vec, - >, - pub attribution: ::subxt::utils::KeyedVec< - ( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::EntityId, - ), - ::std::vec::Vec, - >, - pub activities: ::subxt::utils::KeyedVec< - ( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::ActivityId, - ), - runtime_types::common::prov::model::Activity, - >, - pub was_informed_by: ::subxt::utils::KeyedVec< - ( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::ActivityId, - ), - ::std::vec::Vec<( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::ActivityId, - )>, - >, - pub generated: ::subxt::utils::KeyedVec< - ( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::ActivityId, - ), - ::std::vec::Vec, - >, - pub association: ::subxt::utils::KeyedVec< - ( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::ActivityId, - ), - ::std::vec::Vec, - >, - pub usage: ::subxt::utils::KeyedVec< - ( - runtime_types::common::prov::id::NamespaceId, - runtime_types::common::prov::id::ActivityId, - ), - ::std::vec::Vec, - >, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Usage { - pub activity_id: runtime_types::common::prov::id::ActivityId, - pub entity_id: runtime_types::common::prov::id::EntityId, - } - } - pub mod operations { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ActivityExists { - pub namespace: runtime_types::common::prov::id::NamespaceId, - pub external_id: runtime_types::common::prov::id::ExternalId, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ActivityUses { - pub namespace: runtime_types::common::prov::id::NamespaceId, - pub id: runtime_types::common::prov::id::EntityId, - pub activity: runtime_types::common::prov::id::ActivityId, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ActsOnBehalfOf { - pub id: runtime_types::common::prov::id::DelegationId, - pub role: ::core::option::Option, - pub activity_id: - ::core::option::Option, - pub responsible_id: runtime_types::common::prov::id::AgentId, - pub delegate_id: runtime_types::common::prov::id::AgentId, - pub namespace: runtime_types::common::prov::id::NamespaceId, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct AgentExists { - pub namespace: runtime_types::common::prov::id::NamespaceId, - pub external_id: runtime_types::common::prov::id::ExternalId, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum ChronicleOperation { - #[codec(index = 0)] - CreateNamespace(runtime_types::common::prov::operations::CreateNamespace), - #[codec(index = 1)] - AgentExists(runtime_types::common::prov::operations::AgentExists), - #[codec(index = 2)] - AgentActsOnBehalfOf( - runtime_types::common::prov::operations::ActsOnBehalfOf, - ), - #[codec(index = 3)] - ActivityExists(runtime_types::common::prov::operations::ActivityExists), - #[codec(index = 4)] - StartActivity(runtime_types::common::prov::operations::StartActivity), - #[codec(index = 5)] - EndActivity(runtime_types::common::prov::operations::EndActivity), - #[codec(index = 6)] - ActivityUses(runtime_types::common::prov::operations::ActivityUses), - #[codec(index = 7)] - EntityExists(runtime_types::common::prov::operations::EntityExists), - #[codec(index = 8)] - WasGeneratedBy(runtime_types::common::prov::operations::WasGeneratedBy), - #[codec(index = 9)] - EntityDerive(runtime_types::common::prov::operations::EntityDerive), - #[codec(index = 10)] - SetAttributes(runtime_types::common::prov::operations::SetAttributes), - #[codec(index = 11)] - WasAssociatedWith( - runtime_types::common::prov::operations::WasAssociatedWith, - ), - #[codec(index = 12)] - WasAttributedTo(runtime_types::common::prov::operations::WasAttributedTo), - #[codec(index = 13)] - WasInformedBy(runtime_types::common::prov::operations::WasInformedBy), - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct CreateNamespace { - pub id: runtime_types::common::prov::id::NamespaceId, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum DerivationType { - #[codec(index = 0)] - None, - #[codec(index = 1)] - Revision, - #[codec(index = 2)] - Quotation, - #[codec(index = 3)] - PrimarySource, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct EndActivity { - pub namespace: runtime_types::common::prov::id::NamespaceId, - pub id: runtime_types::common::prov::id::ActivityId, - pub time: runtime_types::common::prov::operations::TimeWrapper, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct EntityDerive { - pub namespace: runtime_types::common::prov::id::NamespaceId, - pub id: runtime_types::common::prov::id::EntityId, - pub used_id: runtime_types::common::prov::id::EntityId, - pub activity_id: - ::core::option::Option, - pub typ: runtime_types::common::prov::operations::DerivationType, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct EntityExists { - pub namespace: runtime_types::common::prov::id::NamespaceId, - pub external_id: runtime_types::common::prov::id::ExternalId, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum SetAttributes { - #[codec(index = 0)] - Entity { - namespace: runtime_types::common::prov::id::NamespaceId, - id: runtime_types::common::prov::id::EntityId, - attributes: runtime_types::common::attributes::Attributes, - }, - #[codec(index = 1)] - Agent { - namespace: runtime_types::common::prov::id::NamespaceId, - id: runtime_types::common::prov::id::AgentId, - attributes: runtime_types::common::attributes::Attributes, - }, - #[codec(index = 2)] - Activity { - namespace: runtime_types::common::prov::id::NamespaceId, - id: runtime_types::common::prov::id::ActivityId, - attributes: runtime_types::common::attributes::Attributes, - }, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct StartActivity { - pub namespace: runtime_types::common::prov::id::NamespaceId, - pub id: runtime_types::common::prov::id::ActivityId, - pub time: runtime_types::common::prov::operations::TimeWrapper, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct TimeWrapper(pub ::core::primitive::i64, pub ::core::primitive::u32); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct WasAssociatedWith { - pub id: runtime_types::common::prov::id::AssociationId, - pub role: ::core::option::Option, - pub namespace: runtime_types::common::prov::id::NamespaceId, - pub activity_id: runtime_types::common::prov::id::ActivityId, - pub agent_id: runtime_types::common::prov::id::AgentId, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct WasAttributedTo { - pub id: runtime_types::common::prov::id::AttributionId, - pub role: ::core::option::Option, - pub namespace: runtime_types::common::prov::id::NamespaceId, - pub entity_id: runtime_types::common::prov::id::EntityId, - pub agent_id: runtime_types::common::prov::id::AgentId, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct WasGeneratedBy { - pub namespace: runtime_types::common::prov::id::NamespaceId, - pub id: runtime_types::common::prov::id::EntityId, - pub activity: runtime_types::common::prov::id::ActivityId, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct WasInformedBy { - pub namespace: runtime_types::common::prov::id::NamespaceId, - pub activity: runtime_types::common::prov::id::ActivityId, - pub informing_activity: runtime_types::common::prov::id::ActivityId, - } - } - } - } - pub mod finality_grandpa { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Equivocation<_0, _1, _2> { - pub round_number: ::core::primitive::u64, - pub identity: _0, - pub first: (_1, _2), - pub second: (_1, _2), - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Precommit<_0, _1> { - pub target_hash: _0, - pub target_number: _1, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Prevote<_0, _1> { - pub target_hash: _0, - pub target_number: _1, - } - } - pub mod frame_support { - use super::runtime_types; - pub mod dispatch { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum DispatchClass { - #[codec(index = 0)] - Normal, - #[codec(index = 1)] - Operational, - #[codec(index = 2)] - Mandatory, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct DispatchInfo { - pub weight: runtime_types::sp_weights::weight_v2::Weight, - pub class: runtime_types::frame_support::dispatch::DispatchClass, - pub pays_fee: runtime_types::frame_support::dispatch::Pays, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum Pays { - #[codec(index = 0)] - Yes, - #[codec(index = 1)] - No, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct PerDispatchClass<_0> { - pub normal: _0, - pub operational: _0, - pub mandatory: _0, - } - } - } - pub mod frame_system { - use super::runtime_types; - pub mod extensions { - use super::runtime_types; - pub mod check_genesis { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct CheckGenesis; - } - pub mod check_mortality { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct CheckMortality(pub runtime_types::sp_runtime::generic::era::Era); - } - pub mod check_non_zero_sender { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct CheckNonZeroSender; - } - pub mod check_spec_version { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct CheckSpecVersion; - } - pub mod check_tx_version { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct CheckTxVersion; - } - pub mod check_weight { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct CheckWeight; - } - } - pub mod limits { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct BlockLength { - pub max: runtime_types::frame_support::dispatch::PerDispatchClass< - ::core::primitive::u32, - >, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct BlockWeights { - pub base_block: runtime_types::sp_weights::weight_v2::Weight, - pub max_block: runtime_types::sp_weights::weight_v2::Weight, - pub per_class: runtime_types::frame_support::dispatch::PerDispatchClass< - runtime_types::frame_system::limits::WeightsPerClass, - >, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct WeightsPerClass { - pub base_extrinsic: runtime_types::sp_weights::weight_v2::Weight, - pub max_extrinsic: - ::core::option::Option, - pub max_total: - ::core::option::Option, - pub reserved: - ::core::option::Option, - } - } - pub mod pallet { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub enum Call { - #[codec(index = 0)] - #[doc = "See [`Pallet::remark`]."] - remark { remark: ::std::vec::Vec<::core::primitive::u8> }, - #[codec(index = 1)] - #[doc = "See [`Pallet::set_heap_pages`]."] - set_heap_pages { pages: ::core::primitive::u64 }, - #[codec(index = 2)] - #[doc = "See [`Pallet::set_code`]."] - set_code { code: ::std::vec::Vec<::core::primitive::u8> }, - #[codec(index = 3)] - #[doc = "See [`Pallet::set_code_without_checks`]."] - set_code_without_checks { code: ::std::vec::Vec<::core::primitive::u8> }, - #[codec(index = 4)] - #[doc = "See [`Pallet::set_storage`]."] - set_storage { - items: ::std::vec::Vec<( - ::std::vec::Vec<::core::primitive::u8>, - ::std::vec::Vec<::core::primitive::u8>, - )>, - }, - #[codec(index = 5)] - #[doc = "See [`Pallet::kill_storage`]."] - kill_storage { keys: ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>> }, - #[codec(index = 6)] - #[doc = "See [`Pallet::kill_prefix`]."] - kill_prefix { - prefix: ::std::vec::Vec<::core::primitive::u8>, - subkeys: ::core::primitive::u32, - }, - #[codec(index = 7)] - #[doc = "See [`Pallet::remark_with_event`]."] - remark_with_event { remark: ::std::vec::Vec<::core::primitive::u8> }, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "Error for the System pallet"] - pub enum Error { - #[codec(index = 0)] - #[doc = "The name of specification does not match between the current runtime"] - #[doc = "and the new runtime."] - InvalidSpecName, - #[codec(index = 1)] - #[doc = "The specification version is not allowed to decrease between the current runtime"] - #[doc = "and the new runtime."] - SpecVersionNeedsToIncrease, - #[codec(index = 2)] - #[doc = "Failed to extract the runtime version from the new runtime."] - #[doc = ""] - #[doc = "Either calling `Core_version` or decoding `RuntimeVersion` failed."] - FailedToExtractRuntimeVersion, - #[codec(index = 3)] - #[doc = "Suicide called when the account has non-default composite data."] - NonDefaultComposite, - #[codec(index = 4)] - #[doc = "There is a non-zero reference count preventing the account from being purged."] - NonZeroRefCount, - #[codec(index = 5)] - #[doc = "The origin filter prevent the call to be dispatched."] - CallFiltered, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "Event for the System pallet."] - pub enum Event { - #[codec(index = 0)] - #[doc = "An extrinsic completed successfully."] - ExtrinsicSuccess { - dispatch_info: runtime_types::frame_support::dispatch::DispatchInfo, - }, - #[codec(index = 1)] - #[doc = "An extrinsic failed."] - ExtrinsicFailed { - dispatch_error: runtime_types::sp_runtime::DispatchError, - dispatch_info: runtime_types::frame_support::dispatch::DispatchInfo, - }, - #[codec(index = 2)] - #[doc = "`:code` was updated."] - CodeUpdated, - #[codec(index = 3)] - #[doc = "A new account was created."] - NewAccount { account: ::subxt::utils::AccountId32 }, - #[codec(index = 4)] - #[doc = "An account was reaped."] - KilledAccount { account: ::subxt::utils::AccountId32 }, - #[codec(index = 5)] - #[doc = "On on-chain remark happened."] - Remarked { sender: ::subxt::utils::AccountId32, hash: ::subxt::utils::H256 }, - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct AccountInfo<_0, _1> { - pub nonce: _0, - pub consumers: ::core::primitive::u32, - pub providers: ::core::primitive::u32, - pub sufficients: ::core::primitive::u32, - pub data: _1, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct EventRecord<_0, _1> { - pub phase: runtime_types::frame_system::Phase, - pub event: _0, - pub topics: ::std::vec::Vec<_1>, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct LastRuntimeUpgradeInfo { - #[codec(compact)] - pub spec_version: ::core::primitive::u32, - pub spec_name: ::std::string::String, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum Phase { - #[codec(index = 0)] - ApplyExtrinsic(::core::primitive::u32), - #[codec(index = 1)] - Finalization, - #[codec(index = 2)] - Initialization, - } - } - pub mod pallet_chronicle { - use super::runtime_types; - pub mod pallet { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub enum Call { - #[codec(index = 0)] - #[doc = "See [`Pallet::apply`]."] - apply { operations: runtime_types::common::ledger::OperationSubmission }, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "The `Error` enum of this pallet."] - pub enum Error { - #[codec(index = 0)] - Address, - #[codec(index = 1)] - Contradiction, - #[codec(index = 2)] - Compaction, - #[codec(index = 3)] - Expansion, - #[codec(index = 4)] - Identity, - #[codec(index = 5)] - IRef, - #[codec(index = 6)] - NotAChronicleIri, - #[codec(index = 7)] - MissingId, - #[codec(index = 8)] - MissingProperty, - #[codec(index = 9)] - NotANode, - #[codec(index = 10)] - NotAnObject, - #[codec(index = 11)] - OpaExecutor, - #[codec(index = 12)] - SerdeJson, - #[codec(index = 13)] - SubmissionFormat, - #[codec(index = 14)] - Time, - #[codec(index = 15)] - Tokio, - #[codec(index = 16)] - Utf8, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "The `Event` enum of this pallet"] - pub enum Event { - #[codec(index = 0)] - Applied( - runtime_types::common::prov::model::ProvModel, - runtime_types::common::identity::SignedIdentity, - [::core::primitive::u8; 16usize], - ), - #[codec(index = 1)] - Contradiction( - runtime_types::common::prov::model::contradiction::Contradiction, - runtime_types::common::identity::SignedIdentity, - [::core::primitive::u8; 16usize], - ), - } - } - } - pub mod pallet_grandpa { - use super::runtime_types; - pub mod pallet { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub enum Call { - #[codec(index = 0)] - #[doc = "See [`Pallet::report_equivocation`]."] - report_equivocation { - equivocation_proof: ::std::boxed::Box< - runtime_types::sp_consensus_grandpa::EquivocationProof< - ::subxt::utils::H256, - ::core::primitive::u32, - >, - >, - key_owner_proof: runtime_types::sp_core::Void, - }, - #[codec(index = 1)] - #[doc = "See [`Pallet::report_equivocation_unsigned`]."] - report_equivocation_unsigned { - equivocation_proof: ::std::boxed::Box< - runtime_types::sp_consensus_grandpa::EquivocationProof< - ::subxt::utils::H256, - ::core::primitive::u32, - >, - >, - key_owner_proof: runtime_types::sp_core::Void, - }, - #[codec(index = 2)] - #[doc = "See [`Pallet::note_stalled`]."] - note_stalled { - delay: ::core::primitive::u32, - best_finalized_block_number: ::core::primitive::u32, - }, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "The `Error` enum of this pallet."] - pub enum Error { - #[codec(index = 0)] - #[doc = "Attempt to signal GRANDPA pause when the authority set isn't live"] - #[doc = "(either paused or already pending pause)."] - PauseFailed, - #[codec(index = 1)] - #[doc = "Attempt to signal GRANDPA resume when the authority set isn't paused"] - #[doc = "(either live or already pending resume)."] - ResumeFailed, - #[codec(index = 2)] - #[doc = "Attempt to signal GRANDPA change with one already pending."] - ChangePending, - #[codec(index = 3)] - #[doc = "Cannot signal forced change so soon after last."] - TooSoon, - #[codec(index = 4)] - #[doc = "A key ownership proof provided as part of an equivocation report is invalid."] - InvalidKeyOwnershipProof, - #[codec(index = 5)] - #[doc = "An equivocation proof provided as part of an equivocation report is invalid."] - InvalidEquivocationProof, - #[codec(index = 6)] - #[doc = "A given equivocation report is valid but already previously reported."] - DuplicateOffenceReport, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "The `Event` enum of this pallet"] - pub enum Event { - #[codec(index = 0)] - #[doc = "New authority set has been applied."] - NewAuthorities { - authority_set: ::std::vec::Vec<( - runtime_types::sp_consensus_grandpa::app::Public, - ::core::primitive::u64, - )>, - }, - #[codec(index = 1)] - #[doc = "Current authority set has been paused."] - Paused, - #[codec(index = 2)] - #[doc = "Current authority set has been resumed."] - Resumed, - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct StoredPendingChange<_0> { - pub scheduled_at: _0, - pub delay: _0, - pub next_authorities: - runtime_types::bounded_collections::weak_bounded_vec::WeakBoundedVec<( - runtime_types::sp_consensus_grandpa::app::Public, - ::core::primitive::u64, - )>, - pub forced: ::core::option::Option<_0>, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum StoredState<_0> { - #[codec(index = 0)] - Live, - #[codec(index = 1)] - PendingPause { scheduled_at: _0, delay: _0 }, - #[codec(index = 2)] - Paused, - #[codec(index = 3)] - PendingResume { scheduled_at: _0, delay: _0 }, - } - } - pub mod pallet_opa { - use super::runtime_types; - pub mod pallet { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub enum Call { - #[codec(index = 0)] - #[doc = "See [`Pallet::apply`]."] - apply { submission: runtime_types::common::opa::core::codec::OpaSubmissionV1 }, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "The `Error` enum of this pallet."] - pub enum Error { - #[codec(index = 0)] - OperationSignatureVerification, - #[codec(index = 1)] - InvalidSigningKey, - #[codec(index = 2)] - JsonSerialize, - #[codec(index = 3)] - InvalidOperation, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "The `Event` enum of this pallet"] - pub enum Event { - #[codec(index = 0)] - PolicyUpdate( - runtime_types::common::opa::core::codec::PolicyMetaV1, - runtime_types::common::prov::model::ChronicleTransactionId, - ), - #[codec(index = 1)] - KeyUpdate( - runtime_types::common::opa::core::codec::KeysV1, - runtime_types::common::prov::model::ChronicleTransactionId, - ), - } - } - } - pub mod pallet_sudo { - use super::runtime_types; - pub mod pallet { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub enum Call { - #[codec(index = 0)] - #[doc = "See [`Pallet::sudo`]."] - sudo { call: ::std::boxed::Box }, - #[codec(index = 1)] - #[doc = "See [`Pallet::sudo_unchecked_weight`]."] - sudo_unchecked_weight { - call: ::std::boxed::Box, - weight: runtime_types::sp_weights::weight_v2::Weight, - }, - #[codec(index = 2)] - #[doc = "See [`Pallet::set_key`]."] - set_key { new: ::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()> }, - #[codec(index = 3)] - #[doc = "See [`Pallet::sudo_as`]."] - sudo_as { - who: ::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()>, - call: ::std::boxed::Box, - }, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "Error for the Sudo pallet"] - pub enum Error { - #[codec(index = 0)] - #[doc = "Sender must be the Sudo account"] - RequireSudo, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "The `Event` enum of this pallet"] - pub enum Event { - #[codec(index = 0)] - #[doc = "A sudo call just took place."] - Sudid { - sudo_result: - ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>, - }, - #[codec(index = 1)] - #[doc = "The sudo key has been updated."] - KeyChanged { old_sudoer: ::core::option::Option<::subxt::utils::AccountId32> }, - #[codec(index = 2)] - #[doc = "A [sudo_as](Pallet::sudo_as) call just took place."] - SudoAsDone { - sudo_result: - ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>, - }, - } - } - } - pub mod pallet_timestamp { - use super::runtime_types; - pub mod pallet { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub enum Call { - #[codec(index = 0)] - #[doc = "See [`Pallet::set`]."] - set { - #[codec(compact)] - now: ::core::primitive::u64, - }, - } - } - } - pub mod runtime_chronicle { - use super::runtime_types; - pub mod no_nonce_fees { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct CheckNonce(#[codec(compact)] pub ::core::primitive::u32); - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Runtime; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum RuntimeCall { - #[codec(index = 0)] - System(runtime_types::frame_system::pallet::Call), - #[codec(index = 1)] - Timestamp(runtime_types::pallet_timestamp::pallet::Call), - #[codec(index = 3)] - Grandpa(runtime_types::pallet_grandpa::pallet::Call), - #[codec(index = 4)] - Sudo(runtime_types::pallet_sudo::pallet::Call), - #[codec(index = 5)] - Chronicle(runtime_types::pallet_chronicle::pallet::Call), - #[codec(index = 6)] - Opa(runtime_types::pallet_opa::pallet::Call), - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum RuntimeError { - #[codec(index = 0)] - System(runtime_types::frame_system::pallet::Error), - #[codec(index = 3)] - Grandpa(runtime_types::pallet_grandpa::pallet::Error), - #[codec(index = 4)] - Sudo(runtime_types::pallet_sudo::pallet::Error), - #[codec(index = 5)] - Chronicle(runtime_types::pallet_chronicle::pallet::Error), - #[codec(index = 6)] - Opa(runtime_types::pallet_opa::pallet::Error), - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum RuntimeEvent { - #[codec(index = 0)] - System(runtime_types::frame_system::pallet::Event), - #[codec(index = 3)] - Grandpa(runtime_types::pallet_grandpa::pallet::Event), - #[codec(index = 4)] - Sudo(runtime_types::pallet_sudo::pallet::Event), - #[codec(index = 5)] - Chronicle(runtime_types::pallet_chronicle::pallet::Event), - #[codec(index = 6)] - Opa(runtime_types::pallet_opa::pallet::Event), - } - } - pub mod sp_arithmetic { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum ArithmeticError { - #[codec(index = 0)] - Underflow, - #[codec(index = 1)] - Overflow, - #[codec(index = 2)] - DivisionByZero, - } - } - pub mod sp_consensus_aura { - use super::runtime_types; - pub mod sr25519 { - use super::runtime_types; - pub mod app_sr25519 { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Public(pub runtime_types::sp_core::sr25519::Public); - } - } - } - pub mod sp_consensus_grandpa { - use super::runtime_types; - pub mod app { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Public(pub runtime_types::sp_core::ed25519::Public); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Signature(pub runtime_types::sp_core::ed25519::Signature); - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum Equivocation<_0, _1> { - #[codec(index = 0)] - Prevote( - runtime_types::finality_grandpa::Equivocation< - runtime_types::sp_consensus_grandpa::app::Public, - runtime_types::finality_grandpa::Prevote<_0, _1>, - runtime_types::sp_consensus_grandpa::app::Signature, - >, - ), - #[codec(index = 1)] - Precommit( - runtime_types::finality_grandpa::Equivocation< - runtime_types::sp_consensus_grandpa::app::Public, - runtime_types::finality_grandpa::Precommit<_0, _1>, - runtime_types::sp_consensus_grandpa::app::Signature, - >, - ), - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct EquivocationProof<_0, _1> { - pub set_id: ::core::primitive::u64, - pub equivocation: runtime_types::sp_consensus_grandpa::Equivocation<_0, _1>, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct OpaqueKeyOwnershipProof(pub ::std::vec::Vec<::core::primitive::u8>); - } - pub mod sp_consensus_slots { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: CompactAs, - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Slot(pub ::core::primitive::u64); - #[derive( - :: subxt :: ext :: codec :: CompactAs, - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct SlotDuration(pub ::core::primitive::u64); - } - pub mod sp_core { - use super::runtime_types; - pub mod crypto { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct KeyTypeId(pub [::core::primitive::u8; 4usize]); - } - pub mod ecdsa { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Signature(pub [::core::primitive::u8; 65usize]); - } - pub mod ed25519 { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Public(pub [::core::primitive::u8; 32usize]); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Signature(pub [::core::primitive::u8; 64usize]); - } - pub mod sr25519 { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Public(pub [::core::primitive::u8; 32usize]); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Signature(pub [::core::primitive::u8; 64usize]); - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct OpaqueMetadata(pub ::std::vec::Vec<::core::primitive::u8>); - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum Void {} - } - pub mod sp_inherents { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct CheckInherentsResult { - pub okay: ::core::primitive::bool, - pub fatal_error: ::core::primitive::bool, - pub errors: runtime_types::sp_inherents::InherentData, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct InherentData { - pub data: ::subxt::utils::KeyedVec< - [::core::primitive::u8; 8usize], - ::std::vec::Vec<::core::primitive::u8>, - >, - } - } - pub mod sp_runtime { - use super::runtime_types; - pub mod generic { - use super::runtime_types; - pub mod block { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Block<_0, _1> { - pub header: _0, - pub extrinsics: ::std::vec::Vec<_1>, - } - } - pub mod digest { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Digest { - pub logs: - ::std::vec::Vec, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum DigestItem { - #[codec(index = 6)] - PreRuntime( - [::core::primitive::u8; 4usize], - ::std::vec::Vec<::core::primitive::u8>, - ), - #[codec(index = 4)] - Consensus( - [::core::primitive::u8; 4usize], - ::std::vec::Vec<::core::primitive::u8>, - ), - #[codec(index = 5)] - Seal( - [::core::primitive::u8; 4usize], - ::std::vec::Vec<::core::primitive::u8>, - ), - #[codec(index = 0)] - Other(::std::vec::Vec<::core::primitive::u8>), - #[codec(index = 8)] - RuntimeEnvironmentUpdated, - } - } - pub mod era { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum Era { - #[codec(index = 0)] - Immortal, - #[codec(index = 1)] - Mortal1(::core::primitive::u8), - #[codec(index = 2)] - Mortal2(::core::primitive::u8), - #[codec(index = 3)] - Mortal3(::core::primitive::u8), - #[codec(index = 4)] - Mortal4(::core::primitive::u8), - #[codec(index = 5)] - Mortal5(::core::primitive::u8), - #[codec(index = 6)] - Mortal6(::core::primitive::u8), - #[codec(index = 7)] - Mortal7(::core::primitive::u8), - #[codec(index = 8)] - Mortal8(::core::primitive::u8), - #[codec(index = 9)] - Mortal9(::core::primitive::u8), - #[codec(index = 10)] - Mortal10(::core::primitive::u8), - #[codec(index = 11)] - Mortal11(::core::primitive::u8), - #[codec(index = 12)] - Mortal12(::core::primitive::u8), - #[codec(index = 13)] - Mortal13(::core::primitive::u8), - #[codec(index = 14)] - Mortal14(::core::primitive::u8), - #[codec(index = 15)] - Mortal15(::core::primitive::u8), - #[codec(index = 16)] - Mortal16(::core::primitive::u8), - #[codec(index = 17)] - Mortal17(::core::primitive::u8), - #[codec(index = 18)] - Mortal18(::core::primitive::u8), - #[codec(index = 19)] - Mortal19(::core::primitive::u8), - #[codec(index = 20)] - Mortal20(::core::primitive::u8), - #[codec(index = 21)] - Mortal21(::core::primitive::u8), - #[codec(index = 22)] - Mortal22(::core::primitive::u8), - #[codec(index = 23)] - Mortal23(::core::primitive::u8), - #[codec(index = 24)] - Mortal24(::core::primitive::u8), - #[codec(index = 25)] - Mortal25(::core::primitive::u8), - #[codec(index = 26)] - Mortal26(::core::primitive::u8), - #[codec(index = 27)] - Mortal27(::core::primitive::u8), - #[codec(index = 28)] - Mortal28(::core::primitive::u8), - #[codec(index = 29)] - Mortal29(::core::primitive::u8), - #[codec(index = 30)] - Mortal30(::core::primitive::u8), - #[codec(index = 31)] - Mortal31(::core::primitive::u8), - #[codec(index = 32)] - Mortal32(::core::primitive::u8), - #[codec(index = 33)] - Mortal33(::core::primitive::u8), - #[codec(index = 34)] - Mortal34(::core::primitive::u8), - #[codec(index = 35)] - Mortal35(::core::primitive::u8), - #[codec(index = 36)] - Mortal36(::core::primitive::u8), - #[codec(index = 37)] - Mortal37(::core::primitive::u8), - #[codec(index = 38)] - Mortal38(::core::primitive::u8), - #[codec(index = 39)] - Mortal39(::core::primitive::u8), - #[codec(index = 40)] - Mortal40(::core::primitive::u8), - #[codec(index = 41)] - Mortal41(::core::primitive::u8), - #[codec(index = 42)] - Mortal42(::core::primitive::u8), - #[codec(index = 43)] - Mortal43(::core::primitive::u8), - #[codec(index = 44)] - Mortal44(::core::primitive::u8), - #[codec(index = 45)] - Mortal45(::core::primitive::u8), - #[codec(index = 46)] - Mortal46(::core::primitive::u8), - #[codec(index = 47)] - Mortal47(::core::primitive::u8), - #[codec(index = 48)] - Mortal48(::core::primitive::u8), - #[codec(index = 49)] - Mortal49(::core::primitive::u8), - #[codec(index = 50)] - Mortal50(::core::primitive::u8), - #[codec(index = 51)] - Mortal51(::core::primitive::u8), - #[codec(index = 52)] - Mortal52(::core::primitive::u8), - #[codec(index = 53)] - Mortal53(::core::primitive::u8), - #[codec(index = 54)] - Mortal54(::core::primitive::u8), - #[codec(index = 55)] - Mortal55(::core::primitive::u8), - #[codec(index = 56)] - Mortal56(::core::primitive::u8), - #[codec(index = 57)] - Mortal57(::core::primitive::u8), - #[codec(index = 58)] - Mortal58(::core::primitive::u8), - #[codec(index = 59)] - Mortal59(::core::primitive::u8), - #[codec(index = 60)] - Mortal60(::core::primitive::u8), - #[codec(index = 61)] - Mortal61(::core::primitive::u8), - #[codec(index = 62)] - Mortal62(::core::primitive::u8), - #[codec(index = 63)] - Mortal63(::core::primitive::u8), - #[codec(index = 64)] - Mortal64(::core::primitive::u8), - #[codec(index = 65)] - Mortal65(::core::primitive::u8), - #[codec(index = 66)] - Mortal66(::core::primitive::u8), - #[codec(index = 67)] - Mortal67(::core::primitive::u8), - #[codec(index = 68)] - Mortal68(::core::primitive::u8), - #[codec(index = 69)] - Mortal69(::core::primitive::u8), - #[codec(index = 70)] - Mortal70(::core::primitive::u8), - #[codec(index = 71)] - Mortal71(::core::primitive::u8), - #[codec(index = 72)] - Mortal72(::core::primitive::u8), - #[codec(index = 73)] - Mortal73(::core::primitive::u8), - #[codec(index = 74)] - Mortal74(::core::primitive::u8), - #[codec(index = 75)] - Mortal75(::core::primitive::u8), - #[codec(index = 76)] - Mortal76(::core::primitive::u8), - #[codec(index = 77)] - Mortal77(::core::primitive::u8), - #[codec(index = 78)] - Mortal78(::core::primitive::u8), - #[codec(index = 79)] - Mortal79(::core::primitive::u8), - #[codec(index = 80)] - Mortal80(::core::primitive::u8), - #[codec(index = 81)] - Mortal81(::core::primitive::u8), - #[codec(index = 82)] - Mortal82(::core::primitive::u8), - #[codec(index = 83)] - Mortal83(::core::primitive::u8), - #[codec(index = 84)] - Mortal84(::core::primitive::u8), - #[codec(index = 85)] - Mortal85(::core::primitive::u8), - #[codec(index = 86)] - Mortal86(::core::primitive::u8), - #[codec(index = 87)] - Mortal87(::core::primitive::u8), - #[codec(index = 88)] - Mortal88(::core::primitive::u8), - #[codec(index = 89)] - Mortal89(::core::primitive::u8), - #[codec(index = 90)] - Mortal90(::core::primitive::u8), - #[codec(index = 91)] - Mortal91(::core::primitive::u8), - #[codec(index = 92)] - Mortal92(::core::primitive::u8), - #[codec(index = 93)] - Mortal93(::core::primitive::u8), - #[codec(index = 94)] - Mortal94(::core::primitive::u8), - #[codec(index = 95)] - Mortal95(::core::primitive::u8), - #[codec(index = 96)] - Mortal96(::core::primitive::u8), - #[codec(index = 97)] - Mortal97(::core::primitive::u8), - #[codec(index = 98)] - Mortal98(::core::primitive::u8), - #[codec(index = 99)] - Mortal99(::core::primitive::u8), - #[codec(index = 100)] - Mortal100(::core::primitive::u8), - #[codec(index = 101)] - Mortal101(::core::primitive::u8), - #[codec(index = 102)] - Mortal102(::core::primitive::u8), - #[codec(index = 103)] - Mortal103(::core::primitive::u8), - #[codec(index = 104)] - Mortal104(::core::primitive::u8), - #[codec(index = 105)] - Mortal105(::core::primitive::u8), - #[codec(index = 106)] - Mortal106(::core::primitive::u8), - #[codec(index = 107)] - Mortal107(::core::primitive::u8), - #[codec(index = 108)] - Mortal108(::core::primitive::u8), - #[codec(index = 109)] - Mortal109(::core::primitive::u8), - #[codec(index = 110)] - Mortal110(::core::primitive::u8), - #[codec(index = 111)] - Mortal111(::core::primitive::u8), - #[codec(index = 112)] - Mortal112(::core::primitive::u8), - #[codec(index = 113)] - Mortal113(::core::primitive::u8), - #[codec(index = 114)] - Mortal114(::core::primitive::u8), - #[codec(index = 115)] - Mortal115(::core::primitive::u8), - #[codec(index = 116)] - Mortal116(::core::primitive::u8), - #[codec(index = 117)] - Mortal117(::core::primitive::u8), - #[codec(index = 118)] - Mortal118(::core::primitive::u8), - #[codec(index = 119)] - Mortal119(::core::primitive::u8), - #[codec(index = 120)] - Mortal120(::core::primitive::u8), - #[codec(index = 121)] - Mortal121(::core::primitive::u8), - #[codec(index = 122)] - Mortal122(::core::primitive::u8), - #[codec(index = 123)] - Mortal123(::core::primitive::u8), - #[codec(index = 124)] - Mortal124(::core::primitive::u8), - #[codec(index = 125)] - Mortal125(::core::primitive::u8), - #[codec(index = 126)] - Mortal126(::core::primitive::u8), - #[codec(index = 127)] - Mortal127(::core::primitive::u8), - #[codec(index = 128)] - Mortal128(::core::primitive::u8), - #[codec(index = 129)] - Mortal129(::core::primitive::u8), - #[codec(index = 130)] - Mortal130(::core::primitive::u8), - #[codec(index = 131)] - Mortal131(::core::primitive::u8), - #[codec(index = 132)] - Mortal132(::core::primitive::u8), - #[codec(index = 133)] - Mortal133(::core::primitive::u8), - #[codec(index = 134)] - Mortal134(::core::primitive::u8), - #[codec(index = 135)] - Mortal135(::core::primitive::u8), - #[codec(index = 136)] - Mortal136(::core::primitive::u8), - #[codec(index = 137)] - Mortal137(::core::primitive::u8), - #[codec(index = 138)] - Mortal138(::core::primitive::u8), - #[codec(index = 139)] - Mortal139(::core::primitive::u8), - #[codec(index = 140)] - Mortal140(::core::primitive::u8), - #[codec(index = 141)] - Mortal141(::core::primitive::u8), - #[codec(index = 142)] - Mortal142(::core::primitive::u8), - #[codec(index = 143)] - Mortal143(::core::primitive::u8), - #[codec(index = 144)] - Mortal144(::core::primitive::u8), - #[codec(index = 145)] - Mortal145(::core::primitive::u8), - #[codec(index = 146)] - Mortal146(::core::primitive::u8), - #[codec(index = 147)] - Mortal147(::core::primitive::u8), - #[codec(index = 148)] - Mortal148(::core::primitive::u8), - #[codec(index = 149)] - Mortal149(::core::primitive::u8), - #[codec(index = 150)] - Mortal150(::core::primitive::u8), - #[codec(index = 151)] - Mortal151(::core::primitive::u8), - #[codec(index = 152)] - Mortal152(::core::primitive::u8), - #[codec(index = 153)] - Mortal153(::core::primitive::u8), - #[codec(index = 154)] - Mortal154(::core::primitive::u8), - #[codec(index = 155)] - Mortal155(::core::primitive::u8), - #[codec(index = 156)] - Mortal156(::core::primitive::u8), - #[codec(index = 157)] - Mortal157(::core::primitive::u8), - #[codec(index = 158)] - Mortal158(::core::primitive::u8), - #[codec(index = 159)] - Mortal159(::core::primitive::u8), - #[codec(index = 160)] - Mortal160(::core::primitive::u8), - #[codec(index = 161)] - Mortal161(::core::primitive::u8), - #[codec(index = 162)] - Mortal162(::core::primitive::u8), - #[codec(index = 163)] - Mortal163(::core::primitive::u8), - #[codec(index = 164)] - Mortal164(::core::primitive::u8), - #[codec(index = 165)] - Mortal165(::core::primitive::u8), - #[codec(index = 166)] - Mortal166(::core::primitive::u8), - #[codec(index = 167)] - Mortal167(::core::primitive::u8), - #[codec(index = 168)] - Mortal168(::core::primitive::u8), - #[codec(index = 169)] - Mortal169(::core::primitive::u8), - #[codec(index = 170)] - Mortal170(::core::primitive::u8), - #[codec(index = 171)] - Mortal171(::core::primitive::u8), - #[codec(index = 172)] - Mortal172(::core::primitive::u8), - #[codec(index = 173)] - Mortal173(::core::primitive::u8), - #[codec(index = 174)] - Mortal174(::core::primitive::u8), - #[codec(index = 175)] - Mortal175(::core::primitive::u8), - #[codec(index = 176)] - Mortal176(::core::primitive::u8), - #[codec(index = 177)] - Mortal177(::core::primitive::u8), - #[codec(index = 178)] - Mortal178(::core::primitive::u8), - #[codec(index = 179)] - Mortal179(::core::primitive::u8), - #[codec(index = 180)] - Mortal180(::core::primitive::u8), - #[codec(index = 181)] - Mortal181(::core::primitive::u8), - #[codec(index = 182)] - Mortal182(::core::primitive::u8), - #[codec(index = 183)] - Mortal183(::core::primitive::u8), - #[codec(index = 184)] - Mortal184(::core::primitive::u8), - #[codec(index = 185)] - Mortal185(::core::primitive::u8), - #[codec(index = 186)] - Mortal186(::core::primitive::u8), - #[codec(index = 187)] - Mortal187(::core::primitive::u8), - #[codec(index = 188)] - Mortal188(::core::primitive::u8), - #[codec(index = 189)] - Mortal189(::core::primitive::u8), - #[codec(index = 190)] - Mortal190(::core::primitive::u8), - #[codec(index = 191)] - Mortal191(::core::primitive::u8), - #[codec(index = 192)] - Mortal192(::core::primitive::u8), - #[codec(index = 193)] - Mortal193(::core::primitive::u8), - #[codec(index = 194)] - Mortal194(::core::primitive::u8), - #[codec(index = 195)] - Mortal195(::core::primitive::u8), - #[codec(index = 196)] - Mortal196(::core::primitive::u8), - #[codec(index = 197)] - Mortal197(::core::primitive::u8), - #[codec(index = 198)] - Mortal198(::core::primitive::u8), - #[codec(index = 199)] - Mortal199(::core::primitive::u8), - #[codec(index = 200)] - Mortal200(::core::primitive::u8), - #[codec(index = 201)] - Mortal201(::core::primitive::u8), - #[codec(index = 202)] - Mortal202(::core::primitive::u8), - #[codec(index = 203)] - Mortal203(::core::primitive::u8), - #[codec(index = 204)] - Mortal204(::core::primitive::u8), - #[codec(index = 205)] - Mortal205(::core::primitive::u8), - #[codec(index = 206)] - Mortal206(::core::primitive::u8), - #[codec(index = 207)] - Mortal207(::core::primitive::u8), - #[codec(index = 208)] - Mortal208(::core::primitive::u8), - #[codec(index = 209)] - Mortal209(::core::primitive::u8), - #[codec(index = 210)] - Mortal210(::core::primitive::u8), - #[codec(index = 211)] - Mortal211(::core::primitive::u8), - #[codec(index = 212)] - Mortal212(::core::primitive::u8), - #[codec(index = 213)] - Mortal213(::core::primitive::u8), - #[codec(index = 214)] - Mortal214(::core::primitive::u8), - #[codec(index = 215)] - Mortal215(::core::primitive::u8), - #[codec(index = 216)] - Mortal216(::core::primitive::u8), - #[codec(index = 217)] - Mortal217(::core::primitive::u8), - #[codec(index = 218)] - Mortal218(::core::primitive::u8), - #[codec(index = 219)] - Mortal219(::core::primitive::u8), - #[codec(index = 220)] - Mortal220(::core::primitive::u8), - #[codec(index = 221)] - Mortal221(::core::primitive::u8), - #[codec(index = 222)] - Mortal222(::core::primitive::u8), - #[codec(index = 223)] - Mortal223(::core::primitive::u8), - #[codec(index = 224)] - Mortal224(::core::primitive::u8), - #[codec(index = 225)] - Mortal225(::core::primitive::u8), - #[codec(index = 226)] - Mortal226(::core::primitive::u8), - #[codec(index = 227)] - Mortal227(::core::primitive::u8), - #[codec(index = 228)] - Mortal228(::core::primitive::u8), - #[codec(index = 229)] - Mortal229(::core::primitive::u8), - #[codec(index = 230)] - Mortal230(::core::primitive::u8), - #[codec(index = 231)] - Mortal231(::core::primitive::u8), - #[codec(index = 232)] - Mortal232(::core::primitive::u8), - #[codec(index = 233)] - Mortal233(::core::primitive::u8), - #[codec(index = 234)] - Mortal234(::core::primitive::u8), - #[codec(index = 235)] - Mortal235(::core::primitive::u8), - #[codec(index = 236)] - Mortal236(::core::primitive::u8), - #[codec(index = 237)] - Mortal237(::core::primitive::u8), - #[codec(index = 238)] - Mortal238(::core::primitive::u8), - #[codec(index = 239)] - Mortal239(::core::primitive::u8), - #[codec(index = 240)] - Mortal240(::core::primitive::u8), - #[codec(index = 241)] - Mortal241(::core::primitive::u8), - #[codec(index = 242)] - Mortal242(::core::primitive::u8), - #[codec(index = 243)] - Mortal243(::core::primitive::u8), - #[codec(index = 244)] - Mortal244(::core::primitive::u8), - #[codec(index = 245)] - Mortal245(::core::primitive::u8), - #[codec(index = 246)] - Mortal246(::core::primitive::u8), - #[codec(index = 247)] - Mortal247(::core::primitive::u8), - #[codec(index = 248)] - Mortal248(::core::primitive::u8), - #[codec(index = 249)] - Mortal249(::core::primitive::u8), - #[codec(index = 250)] - Mortal250(::core::primitive::u8), - #[codec(index = 251)] - Mortal251(::core::primitive::u8), - #[codec(index = 252)] - Mortal252(::core::primitive::u8), - #[codec(index = 253)] - Mortal253(::core::primitive::u8), - #[codec(index = 254)] - Mortal254(::core::primitive::u8), - #[codec(index = 255)] - Mortal255(::core::primitive::u8), - } - } - pub mod header { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Header<_0> { - pub parent_hash: ::subxt::utils::H256, - #[codec(compact)] - pub number: _0, - pub state_root: ::subxt::utils::H256, - pub extrinsics_root: ::subxt::utils::H256, - pub digest: runtime_types::sp_runtime::generic::digest::Digest, - } - } - } - pub mod transaction_validity { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum InvalidTransaction { - #[codec(index = 0)] - Call, - #[codec(index = 1)] - Payment, - #[codec(index = 2)] - Future, - #[codec(index = 3)] - Stale, - #[codec(index = 4)] - BadProof, - #[codec(index = 5)] - AncientBirthBlock, - #[codec(index = 6)] - ExhaustsResources, - #[codec(index = 7)] - Custom(::core::primitive::u8), - #[codec(index = 8)] - BadMandatory, - #[codec(index = 9)] - MandatoryValidation, - #[codec(index = 10)] - BadSigner, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum TransactionSource { - #[codec(index = 0)] - InBlock, - #[codec(index = 1)] - Local, - #[codec(index = 2)] - External, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum TransactionValidityError { - #[codec(index = 0)] - Invalid(runtime_types::sp_runtime::transaction_validity::InvalidTransaction), - #[codec(index = 1)] - Unknown(runtime_types::sp_runtime::transaction_validity::UnknownTransaction), - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum UnknownTransaction { - #[codec(index = 0)] - CannotLookup, - #[codec(index = 1)] - NoUnsignedValidator, - #[codec(index = 2)] - Custom(::core::primitive::u8), - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ValidTransaction { - pub priority: ::core::primitive::u64, - pub requires: ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>>, - pub provides: ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>>, - pub longevity: ::core::primitive::u64, - pub propagate: ::core::primitive::bool, - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum DispatchError { - #[codec(index = 0)] - Other, - #[codec(index = 1)] - CannotLookup, - #[codec(index = 2)] - BadOrigin, - #[codec(index = 3)] - Module(runtime_types::sp_runtime::ModuleError), - #[codec(index = 4)] - ConsumerRemaining, - #[codec(index = 5)] - NoProviders, - #[codec(index = 6)] - TooManyConsumers, - #[codec(index = 7)] - Token(runtime_types::sp_runtime::TokenError), - #[codec(index = 8)] - Arithmetic(runtime_types::sp_arithmetic::ArithmeticError), - #[codec(index = 9)] - Transactional(runtime_types::sp_runtime::TransactionalError), - #[codec(index = 10)] - Exhausted, - #[codec(index = 11)] - Corruption, - #[codec(index = 12)] - Unavailable, - #[codec(index = 13)] - RootNotAllowed, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct ModuleError { - pub index: ::core::primitive::u8, - pub error: [::core::primitive::u8; 4usize], - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum MultiSignature { - #[codec(index = 0)] - Ed25519(runtime_types::sp_core::ed25519::Signature), - #[codec(index = 1)] - Sr25519(runtime_types::sp_core::sr25519::Signature), - #[codec(index = 2)] - Ecdsa(runtime_types::sp_core::ecdsa::Signature), - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum TokenError { - #[codec(index = 0)] - FundsUnavailable, - #[codec(index = 1)] - OnlyProvider, - #[codec(index = 2)] - BelowMinimum, - #[codec(index = 3)] - CannotCreate, - #[codec(index = 4)] - UnknownAsset, - #[codec(index = 5)] - Frozen, - #[codec(index = 6)] - Unsupported, - #[codec(index = 7)] - CannotCreateHold, - #[codec(index = 8)] - NotExpendable, - #[codec(index = 9)] - Blocked, - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub enum TransactionalError { - #[codec(index = 0)] - LimitReached, - #[codec(index = 1)] - NoLayer, - } - } - pub mod sp_version { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct RuntimeVersion { - pub spec_name: ::std::string::String, - pub impl_name: ::std::string::String, - pub authoring_version: ::core::primitive::u32, - pub spec_version: ::core::primitive::u32, - pub impl_version: ::core::primitive::u32, - pub apis: - ::std::vec::Vec<([::core::primitive::u8; 8usize], ::core::primitive::u32)>, - pub transaction_version: ::core::primitive::u32, - pub state_version: ::core::primitive::u8, - } - } - pub mod sp_weights { - use super::runtime_types; - pub mod weight_v2 { - use super::runtime_types; - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct Weight { - #[codec(compact)] - pub ref_time: ::core::primitive::u64, - #[codec(compact)] - pub proof_size: ::core::primitive::u64, - } - } - #[derive( - :: subxt :: ext :: codec :: Decode, - :: subxt :: ext :: codec :: Encode, - :: subxt :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - # [codec (crate = :: subxt :: ext :: codec)] - #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] - pub struct RuntimeDbWeight { - pub read: ::core::primitive::u64, - pub write: ::core::primitive::u64, - } - } - } + #[allow(unused_imports)] + mod root_mod { + pub use super::*; + } + + pub static PALLETS: [&str; 7usize] = + ["System", "Timestamp", "Aura", "Grandpa", "Sudo", "Chronicle", "Opa"]; + pub static RUNTIME_APIS: [&str; 10usize] = [ + "ChronicleApi", + "Core", + "Metadata", + "BlockBuilder", + "TaggedTransactionQueue", + "OffchainWorkerApi", + "AuraApi", + "SessionKeys", + "GrandpaApi", + "AccountNonceApi", + ]; + + #[doc = r" The error type returned when there is a runtime issue."] + pub type DispatchError = runtime_types::sp_runtime::DispatchError; + #[doc = r" The outer event enum."] + pub type Event = runtime_types::runtime_chronicle::RuntimeEvent; + #[doc = r" The outer extrinsic enum."] + pub type Call = runtime_types::runtime_chronicle::RuntimeCall; + #[doc = r" The outer error enum representing the DispatchError's Module variant."] + pub type Error = runtime_types::runtime_chronicle::RuntimeError; + + pub fn constants() -> ConstantsApi { + ConstantsApi + } + + pub fn storage() -> StorageApi { + StorageApi + } + + pub fn tx() -> TransactionApi { + TransactionApi + } + + pub fn apis() -> runtime_apis::RuntimeApi { + runtime_apis::RuntimeApi + } + + pub mod runtime_apis { + use super::{root_mod, runtime_types}; + use subxt::ext::codec::Encode; + + pub struct RuntimeApi; + + impl RuntimeApi { + pub fn chronicle_api(&self) -> chronicle_api::ChronicleApi { + chronicle_api::ChronicleApi + } + + pub fn core(&self) -> core::Core { + core::Core + } + + pub fn metadata(&self) -> metadata::Metadata { + metadata::Metadata + } + + pub fn block_builder(&self) -> block_builder::BlockBuilder { + block_builder::BlockBuilder + } + + pub fn tagged_transaction_queue( + &self, + ) -> tagged_transaction_queue::TaggedTransactionQueue { + tagged_transaction_queue::TaggedTransactionQueue + } + + pub fn offchain_worker_api(&self) -> offchain_worker_api::OffchainWorkerApi { + offchain_worker_api::OffchainWorkerApi + } + + pub fn aura_api(&self) -> aura_api::AuraApi { + aura_api::AuraApi + } + + pub fn session_keys(&self) -> session_keys::SessionKeys { + session_keys::SessionKeys + } + + pub fn grandpa_api(&self) -> grandpa_api::GrandpaApi { + grandpa_api::GrandpaApi + } + + pub fn account_nonce_api(&self) -> account_nonce_api::AccountNonceApi { + account_nonce_api::AccountNonceApi + } + } + + pub mod chronicle_api { + use super::{root_mod, runtime_types}; + + pub struct ChronicleApi; + + impl ChronicleApi { + pub fn placeholder( + &self, + ) -> ::subxt::runtime_api::Payload< + types::Placeholder, + types::placeholder::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "ChronicleApi", + "placeholder", + types::Placeholder {}, + [ + 69u8, 86u8, 182u8, 109u8, 157u8, 7u8, 62u8, 57u8, 188u8, 29u8, 49u8, + 204u8, 192u8, 72u8, 129u8, 172u8, 6u8, 99u8, 90u8, 91u8, 65u8, 63u8, + 182u8, 117u8, 15u8, 156u8, 227u8, 205u8, 229u8, 70u8, 212u8, 119u8, + ], + ) + } + } + + pub mod types { + use super::runtime_types; + + pub mod placeholder { + use super::runtime_types; + + pub mod output { + use super::runtime_types; + + pub type Output = ::core::primitive::u32; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Placeholder {} + } + } + + pub mod core { + use super::{root_mod, runtime_types}; + + #[doc = " The `Core` runtime api that every Substrate runtime needs to implement."] + pub struct Core; + + impl Core { + #[doc = " Returns the version of the runtime."] + pub fn version( + &self, + ) -> ::subxt::runtime_api::Payload { + ::subxt::runtime_api::Payload::new_static( + "Core", + "version", + types::Version {}, + [ + 76u8, 202u8, 17u8, 117u8, 189u8, 237u8, 239u8, 237u8, 151u8, 17u8, + 125u8, 159u8, 218u8, 92u8, 57u8, 238u8, 64u8, 147u8, 40u8, 72u8, 157u8, + 116u8, 37u8, 195u8, 156u8, 27u8, 123u8, 173u8, 178u8, 102u8, 136u8, + 6u8, + ], + ) + } + + #[doc = " Execute the given block."] + pub fn execute_block( + &self, + block: types::execute_block::Block, + ) -> ::subxt::runtime_api::Payload< + types::ExecuteBlock, + types::execute_block::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "Core", + "execute_block", + types::ExecuteBlock { block }, + [ + 133u8, 135u8, 228u8, 65u8, 106u8, 27u8, 85u8, 158u8, 112u8, 254u8, + 93u8, 26u8, 102u8, 201u8, 118u8, 216u8, 249u8, 247u8, 91u8, 74u8, 56u8, + 208u8, 231u8, 115u8, 131u8, 29u8, 209u8, 6u8, 65u8, 57u8, 214u8, 125u8, + ], + ) + } + + #[doc = " Initialize a block with the given header."] + pub fn initialize_block( + &self, + header: types::initialize_block::Header, + ) -> ::subxt::runtime_api::Payload< + types::InitializeBlock, + types::initialize_block::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "Core", + "initialize_block", + types::InitializeBlock { header }, + [ + 146u8, 138u8, 72u8, 240u8, 63u8, 96u8, 110u8, 189u8, 77u8, 92u8, 96u8, + 232u8, 41u8, 217u8, 105u8, 148u8, 83u8, 190u8, 152u8, 219u8, 19u8, + 87u8, 163u8, 1u8, 232u8, 25u8, 221u8, 74u8, 224u8, 67u8, 223u8, 34u8, + ], + ) + } + } + + pub mod types { + use super::runtime_types; + + pub mod version { + use super::runtime_types; + + pub mod output { + use super::runtime_types; + + pub type Output = runtime_types::sp_version::RuntimeVersion; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Version {} + + pub mod execute_block { + use super::runtime_types; + + pub type Block = runtime_types::sp_runtime::generic::block::Block, ::subxt::utils::UncheckedExtrinsic<::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()>, runtime_types::runtime_chronicle::RuntimeCall, runtime_types::sp_runtime::MultiSignature, (runtime_types::frame_system::extensions::check_non_zero_sender::CheckNonZeroSender, runtime_types::frame_system::extensions::check_spec_version::CheckSpecVersion, runtime_types::frame_system::extensions::check_tx_version::CheckTxVersion, runtime_types::frame_system::extensions::check_genesis::CheckGenesis, runtime_types::frame_system::extensions::check_mortality::CheckMortality, runtime_types::runtime_chronicle::no_nonce_fees::CheckNonce, runtime_types::frame_system::extensions::check_weight::CheckWeight, )>>; + + pub mod output { + use super::runtime_types; + + pub type Output = (); + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ExecuteBlock { + pub block: execute_block::Block, + } + + pub mod initialize_block { + use super::runtime_types; + + pub type Header = + runtime_types::sp_runtime::generic::header::Header<::core::primitive::u32>; + + pub mod output { + use super::runtime_types; + + pub type Output = (); + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct InitializeBlock { + pub header: initialize_block::Header, + } + } + } + + pub mod metadata { + use super::{root_mod, runtime_types}; + + #[doc = " The `Metadata` api trait that returns metadata for the runtime."] + pub struct Metadata; + + impl Metadata { + #[doc = " Returns the metadata of a runtime."] + pub fn metadata( + &self, + ) -> ::subxt::runtime_api::Payload + { + ::subxt::runtime_api::Payload::new_static( + "Metadata", + "metadata", + types::Metadata {}, + [ + 231u8, 24u8, 67u8, 152u8, 23u8, 26u8, 188u8, 82u8, 229u8, 6u8, 185u8, + 27u8, 175u8, 68u8, 83u8, 122u8, 69u8, 89u8, 185u8, 74u8, 248u8, 87u8, + 217u8, 124u8, 193u8, 252u8, 199u8, 186u8, 196u8, 179u8, 179u8, 96u8, + ], + ) + } + + #[doc = " Returns the metadata at a given version."] + #[doc = ""] + #[doc = " If the given `version` isn't supported, this will return `None`."] + #[doc = " Use [`Self::metadata_versions`] to find out about supported metadata version of the runtime."] + pub fn metadata_at_version( + &self, + version: types::metadata_at_version::Version, + ) -> ::subxt::runtime_api::Payload< + types::MetadataAtVersion, + types::metadata_at_version::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "Metadata", + "metadata_at_version", + types::MetadataAtVersion { version }, + [ + 131u8, 53u8, 212u8, 234u8, 16u8, 25u8, 120u8, 252u8, 153u8, 153u8, + 216u8, 28u8, 54u8, 113u8, 52u8, 236u8, 146u8, 68u8, 142u8, 8u8, 10u8, + 169u8, 131u8, 142u8, 204u8, 38u8, 48u8, 108u8, 134u8, 86u8, 226u8, + 61u8, + ], + ) + } + + #[doc = " Returns the supported metadata versions."] + #[doc = ""] + #[doc = " This can be used to call `metadata_at_version`."] + pub fn metadata_versions( + &self, + ) -> ::subxt::runtime_api::Payload< + types::MetadataVersions, + types::metadata_versions::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "Metadata", + "metadata_versions", + types::MetadataVersions {}, + [ + 23u8, 144u8, 137u8, 91u8, 188u8, 39u8, 231u8, 208u8, 252u8, 218u8, + 224u8, 176u8, 77u8, 32u8, 130u8, 212u8, 223u8, 76u8, 100u8, 190u8, + 82u8, 94u8, 190u8, 8u8, 82u8, 244u8, 225u8, 179u8, 85u8, 176u8, 56u8, + 16u8, + ], + ) + } + } + + pub mod types { + use super::runtime_types; + + pub mod metadata { + use super::runtime_types; + + pub mod output { + use super::runtime_types; + + pub type Output = runtime_types::sp_core::OpaqueMetadata; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Metadata {} + + pub mod metadata_at_version { + use super::runtime_types; + + pub type Version = ::core::primitive::u32; + + pub mod output { + use super::runtime_types; + + pub type Output = + ::core::option::Option; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct MetadataAtVersion { + pub version: metadata_at_version::Version, + } + + pub mod metadata_versions { + use super::runtime_types; + + pub mod output { + use super::runtime_types; + + pub type Output = ::std::vec::Vec<::core::primitive::u32>; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct MetadataVersions {} + } + } + + pub mod block_builder { + use super::{root_mod, runtime_types}; + + #[doc = " The `BlockBuilder` api trait that provides the required functionality for building a block."] + pub struct BlockBuilder; + + impl BlockBuilder { + #[doc = " Apply the given extrinsic."] + #[doc = ""] + #[doc = " Returns an inclusion outcome which specifies if this extrinsic is included in"] + #[doc = " this block or not."] + pub fn apply_extrinsic( + &self, + extrinsic: types::apply_extrinsic::Extrinsic, + ) -> ::subxt::runtime_api::Payload< + types::ApplyExtrinsic, + types::apply_extrinsic::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "BlockBuilder", + "apply_extrinsic", + types::ApplyExtrinsic { extrinsic }, + [ + 72u8, 54u8, 139u8, 3u8, 118u8, 136u8, 65u8, 47u8, 6u8, 105u8, 125u8, + 223u8, 160u8, 29u8, 103u8, 74u8, 79u8, 149u8, 48u8, 90u8, 237u8, 2u8, + 97u8, 201u8, 123u8, 34u8, 167u8, 37u8, 187u8, 35u8, 176u8, 97u8, + ], + ) + } + + #[doc = " Finish the current block."] + pub fn finalize_block( + &self, + ) -> ::subxt::runtime_api::Payload< + types::FinalizeBlock, + types::finalize_block::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "BlockBuilder", + "finalize_block", + types::FinalizeBlock {}, + [ + 244u8, 207u8, 24u8, 33u8, 13u8, 69u8, 9u8, 249u8, 145u8, 143u8, 122u8, + 96u8, 197u8, 55u8, 64u8, 111u8, 238u8, 224u8, 34u8, 201u8, 27u8, 146u8, + 232u8, 99u8, 191u8, 30u8, 114u8, 16u8, 32u8, 220u8, 58u8, 62u8, + ], + ) + } + + #[doc = " Generate inherent extrinsics. The inherent data will vary from chain to chain."] + pub fn inherent_extrinsics( + &self, + inherent: types::inherent_extrinsics::Inherent, + ) -> ::subxt::runtime_api::Payload< + types::InherentExtrinsics, + types::inherent_extrinsics::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "BlockBuilder", + "inherent_extrinsics", + types::InherentExtrinsics { inherent }, + [ + 254u8, 110u8, 245u8, 201u8, 250u8, 192u8, 27u8, 228u8, 151u8, 213u8, + 166u8, 89u8, 94u8, 81u8, 189u8, 234u8, 64u8, 18u8, 245u8, 80u8, 29u8, + 18u8, 140u8, 129u8, 113u8, 236u8, 135u8, 55u8, 79u8, 159u8, 175u8, + 183u8, + ], + ) + } + + #[doc = " Check that the inherents are valid. The inherent data will vary from chain to chain."] + pub fn check_inherents( + &self, + block: types::check_inherents::Block, + data: types::check_inherents::Data, + ) -> ::subxt::runtime_api::Payload< + types::CheckInherents, + types::check_inherents::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "BlockBuilder", + "check_inherents", + types::CheckInherents { block, data }, + [ + 153u8, 134u8, 1u8, 215u8, 139u8, 11u8, 53u8, 51u8, 210u8, 175u8, 197u8, + 28u8, 38u8, 209u8, 175u8, 247u8, 142u8, 157u8, 50u8, 151u8, 164u8, + 191u8, 181u8, 118u8, 80u8, 97u8, 160u8, 248u8, 110u8, 217u8, 181u8, + 234u8, + ], + ) + } + } + + pub mod types { + use super::runtime_types; + + pub mod apply_extrinsic { + use super::runtime_types; + + pub type Extrinsic = ::subxt::utils::UncheckedExtrinsic<::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()>, runtime_types::runtime_chronicle::RuntimeCall, runtime_types::sp_runtime::MultiSignature, (runtime_types::frame_system::extensions::check_non_zero_sender::CheckNonZeroSender, runtime_types::frame_system::extensions::check_spec_version::CheckSpecVersion, runtime_types::frame_system::extensions::check_tx_version::CheckTxVersion, runtime_types::frame_system::extensions::check_genesis::CheckGenesis, runtime_types::frame_system::extensions::check_mortality::CheckMortality, runtime_types::runtime_chronicle::no_nonce_fees::CheckNonce, runtime_types::frame_system::extensions::check_weight::CheckWeight, )>; + + pub mod output { + use super::runtime_types; + + pub type Output = ::core::result::Result<::core::result::Result<(), runtime_types::sp_runtime::DispatchError>, runtime_types::sp_runtime::transaction_validity::TransactionValidityError>; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ApplyExtrinsic { + pub extrinsic: apply_extrinsic::Extrinsic, + } + + pub mod finalize_block { + use super::runtime_types; + + pub mod output { + use super::runtime_types; + + pub type Output = runtime_types::sp_runtime::generic::header::Header< + ::core::primitive::u32, + >; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct FinalizeBlock {} + + pub mod inherent_extrinsics { + use super::runtime_types; + + pub type Inherent = runtime_types::sp_inherents::InherentData; + + pub mod output { + use super::runtime_types; + + pub type Output = ::std::vec::Vec<::subxt::utils::UncheckedExtrinsic<::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()>, runtime_types::runtime_chronicle::RuntimeCall, runtime_types::sp_runtime::MultiSignature, (runtime_types::frame_system::extensions::check_non_zero_sender::CheckNonZeroSender, runtime_types::frame_system::extensions::check_spec_version::CheckSpecVersion, runtime_types::frame_system::extensions::check_tx_version::CheckTxVersion, runtime_types::frame_system::extensions::check_genesis::CheckGenesis, runtime_types::frame_system::extensions::check_mortality::CheckMortality, runtime_types::runtime_chronicle::no_nonce_fees::CheckNonce, runtime_types::frame_system::extensions::check_weight::CheckWeight, )>>; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct InherentExtrinsics { + pub inherent: inherent_extrinsics::Inherent, + } + + pub mod check_inherents { + use super::runtime_types; + + pub type Block = runtime_types::sp_runtime::generic::block::Block, ::subxt::utils::UncheckedExtrinsic<::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()>, runtime_types::runtime_chronicle::RuntimeCall, runtime_types::sp_runtime::MultiSignature, (runtime_types::frame_system::extensions::check_non_zero_sender::CheckNonZeroSender, runtime_types::frame_system::extensions::check_spec_version::CheckSpecVersion, runtime_types::frame_system::extensions::check_tx_version::CheckTxVersion, runtime_types::frame_system::extensions::check_genesis::CheckGenesis, runtime_types::frame_system::extensions::check_mortality::CheckMortality, runtime_types::runtime_chronicle::no_nonce_fees::CheckNonce, runtime_types::frame_system::extensions::check_weight::CheckWeight, )>>; + pub type Data = runtime_types::sp_inherents::InherentData; + + pub mod output { + use super::runtime_types; + + pub type Output = runtime_types::sp_inherents::CheckInherentsResult; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct CheckInherents { + pub block: check_inherents::Block, + pub data: check_inherents::Data, + } + } + } + + pub mod tagged_transaction_queue { + use super::{root_mod, runtime_types}; + + #[doc = " The `TaggedTransactionQueue` api trait for interfering with the transaction queue."] + pub struct TaggedTransactionQueue; + + impl TaggedTransactionQueue { + #[doc = " Validate the transaction."] + #[doc = ""] + #[doc = " This method is invoked by the transaction pool to learn details about given transaction."] + #[doc = " The implementation should make sure to verify the correctness of the transaction"] + #[doc = " against current state. The given `block_hash` corresponds to the hash of the block"] + #[doc = " that is used as current state."] + #[doc = ""] + #[doc = " Note that this call may be performed by the pool multiple times and transactions"] + #[doc = " might be verified in any possible order."] + pub fn validate_transaction( + &self, + source: types::validate_transaction::Source, + tx: types::validate_transaction::Tx, + block_hash: types::validate_transaction::BlockHash, + ) -> ::subxt::runtime_api::Payload< + types::ValidateTransaction, + types::validate_transaction::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "TaggedTransactionQueue", + "validate_transaction", + types::ValidateTransaction { source, tx, block_hash }, + [ + 196u8, 50u8, 90u8, 49u8, 109u8, 251u8, 200u8, 35u8, 23u8, 150u8, 140u8, + 143u8, 232u8, 164u8, 133u8, 89u8, 32u8, 240u8, 115u8, 39u8, 95u8, 70u8, + 162u8, 76u8, 122u8, 73u8, 151u8, 144u8, 234u8, 120u8, 100u8, 29u8, + ], + ) + } + } + + pub mod types { + use super::runtime_types; + + pub mod validate_transaction { + use super::runtime_types; + + pub type Source = + runtime_types::sp_runtime::transaction_validity::TransactionSource; + pub type Tx = ::subxt::utils::UncheckedExtrinsic<::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()>, runtime_types::runtime_chronicle::RuntimeCall, runtime_types::sp_runtime::MultiSignature, (runtime_types::frame_system::extensions::check_non_zero_sender::CheckNonZeroSender, runtime_types::frame_system::extensions::check_spec_version::CheckSpecVersion, runtime_types::frame_system::extensions::check_tx_version::CheckTxVersion, runtime_types::frame_system::extensions::check_genesis::CheckGenesis, runtime_types::frame_system::extensions::check_mortality::CheckMortality, runtime_types::runtime_chronicle::no_nonce_fees::CheckNonce, runtime_types::frame_system::extensions::check_weight::CheckWeight, )>; + pub type BlockHash = ::subxt::utils::H256; + + pub mod output { + use super::runtime_types; + + pub type Output = ::core::result::Result; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ValidateTransaction { + pub source: validate_transaction::Source, + pub tx: validate_transaction::Tx, + pub block_hash: validate_transaction::BlockHash, + } + } + } + + pub mod offchain_worker_api { + use super::{root_mod, runtime_types}; + + #[doc = " The offchain worker api."] + pub struct OffchainWorkerApi; + + impl OffchainWorkerApi { + #[doc = " Starts the off-chain task for given block header."] + pub fn offchain_worker( + &self, + header: types::offchain_worker::Header, + ) -> ::subxt::runtime_api::Payload< + types::OffchainWorker, + types::offchain_worker::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "OffchainWorkerApi", + "offchain_worker", + types::OffchainWorker { header }, + [ + 10u8, 135u8, 19u8, 153u8, 33u8, 216u8, 18u8, 242u8, 33u8, 140u8, 4u8, + 223u8, 200u8, 130u8, 103u8, 118u8, 137u8, 24u8, 19u8, 127u8, 161u8, + 29u8, 184u8, 111u8, 222u8, 111u8, 253u8, 73u8, 45u8, 31u8, 79u8, 60u8, + ], + ) + } + } + + pub mod types { + use super::runtime_types; + + pub mod offchain_worker { + use super::runtime_types; + + pub type Header = + runtime_types::sp_runtime::generic::header::Header<::core::primitive::u32>; + + pub mod output { + use super::runtime_types; + + pub type Output = (); + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct OffchainWorker { + pub header: offchain_worker::Header, + } + } + } + + pub mod aura_api { + use super::{root_mod, runtime_types}; + + #[doc = " API necessary for block authorship with aura."] + pub struct AuraApi; + + impl AuraApi { + #[doc = " Returns the slot duration for Aura."] + #[doc = ""] + #[doc = " Currently, only the value provided by this type at genesis will be used."] + pub fn slot_duration( + &self, + ) -> ::subxt::runtime_api::Payload< + types::SlotDuration, + types::slot_duration::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "AuraApi", + "slot_duration", + types::SlotDuration {}, + [ + 233u8, 210u8, 132u8, 172u8, 100u8, 125u8, 239u8, 92u8, 114u8, 82u8, + 7u8, 110u8, 179u8, 196u8, 10u8, 19u8, 211u8, 15u8, 174u8, 2u8, 91u8, + 73u8, 133u8, 100u8, 205u8, 201u8, 191u8, 60u8, 163u8, 122u8, 215u8, + 10u8, + ], + ) + } + + #[doc = " Return the current set of authorities."] + pub fn authorities( + &self, + ) -> ::subxt::runtime_api::Payload< + types::Authorities, + types::authorities::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "AuraApi", + "authorities", + types::Authorities {}, + [ + 96u8, 136u8, 226u8, 244u8, 105u8, 189u8, 8u8, 250u8, 71u8, 230u8, 37u8, + 123u8, 218u8, 47u8, 179u8, 16u8, 170u8, 181u8, 165u8, 77u8, 102u8, + 51u8, 43u8, 51u8, 186u8, 84u8, 49u8, 15u8, 208u8, 226u8, 129u8, 230u8, + ], + ) + } + } + + pub mod types { + use super::runtime_types; + + pub mod slot_duration { + use super::runtime_types; + + pub mod output { + use super::runtime_types; + + pub type Output = runtime_types::sp_consensus_slots::SlotDuration; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct SlotDuration {} + + pub mod authorities { + use super::runtime_types; + + pub mod output { + use super::runtime_types; + + pub type Output = ::std::vec::Vec< + runtime_types::sp_consensus_aura::sr25519::app_sr25519::Public, + >; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Authorities {} + } + } + + pub mod session_keys { + use super::{root_mod, runtime_types}; + + #[doc = " Session keys runtime api."] + pub struct SessionKeys; + + impl SessionKeys { + #[doc = " Generate a set of session keys with optionally using the given seed."] + #[doc = " The keys should be stored within the keystore exposed via runtime"] + #[doc = " externalities."] + #[doc = ""] + #[doc = " The seed needs to be a valid `utf8` string."] + #[doc = ""] + #[doc = " Returns the concatenated SCALE encoded public keys."] + pub fn generate_session_keys( + &self, + seed: types::generate_session_keys::Seed, + ) -> ::subxt::runtime_api::Payload< + types::GenerateSessionKeys, + types::generate_session_keys::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "SessionKeys", + "generate_session_keys", + types::GenerateSessionKeys { seed }, + [ + 96u8, 171u8, 164u8, 166u8, 175u8, 102u8, 101u8, 47u8, 133u8, 95u8, + 102u8, 202u8, 83u8, 26u8, 238u8, 47u8, 126u8, 132u8, 22u8, 11u8, 33u8, + 190u8, 175u8, 94u8, 58u8, 245u8, 46u8, 80u8, 195u8, 184u8, 107u8, 65u8, + ], + ) + } + + #[doc = " Decode the given public session keys."] + #[doc = ""] + #[doc = " Returns the list of public raw public keys + key type."] + pub fn decode_session_keys( + &self, + encoded: types::decode_session_keys::Encoded, + ) -> ::subxt::runtime_api::Payload< + types::DecodeSessionKeys, + types::decode_session_keys::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "SessionKeys", + "decode_session_keys", + types::DecodeSessionKeys { encoded }, + [ + 57u8, 242u8, 18u8, 51u8, 132u8, 110u8, 238u8, 255u8, 39u8, 194u8, 8u8, + 54u8, 198u8, 178u8, 75u8, 151u8, 148u8, 176u8, 144u8, 197u8, 87u8, + 29u8, 179u8, 235u8, 176u8, 78u8, 252u8, 103u8, 72u8, 203u8, 151u8, + 248u8, + ], + ) + } + } + + pub mod types { + use super::runtime_types; + + pub mod generate_session_keys { + use super::runtime_types; + + pub type Seed = ::core::option::Option<::std::vec::Vec<::core::primitive::u8>>; + + pub mod output { + use super::runtime_types; + + pub type Output = ::std::vec::Vec<::core::primitive::u8>; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct GenerateSessionKeys { + pub seed: generate_session_keys::Seed, + } + + pub mod decode_session_keys { + use super::runtime_types; + + pub type Encoded = ::std::vec::Vec<::core::primitive::u8>; + + pub mod output { + use super::runtime_types; + + pub type Output = ::core::option::Option< + ::std::vec::Vec<( + ::std::vec::Vec<::core::primitive::u8>, + runtime_types::sp_core::crypto::KeyTypeId, + )>, + >; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct DecodeSessionKeys { + pub encoded: decode_session_keys::Encoded, + } + } + } + + pub mod grandpa_api { + use super::{root_mod, runtime_types}; + + #[doc = " APIs for integrating the GRANDPA finality gadget into runtimes."] + #[doc = " This should be implemented on the runtime side."] + #[doc = ""] + #[doc = " This is primarily used for negotiating authority-set changes for the"] + #[doc = " gadget. GRANDPA uses a signaling model of changing authority sets:"] + #[doc = " changes should be signaled with a delay of N blocks, and then automatically"] + #[doc = " applied in the runtime after those N blocks have passed."] + #[doc = ""] + #[doc = " The consensus protocol will coordinate the handoff externally."] + pub struct GrandpaApi; + + impl GrandpaApi { + #[doc = " Get the current GRANDPA authorities and weights. This should not change except"] + #[doc = " for when changes are scheduled and the corresponding delay has passed."] + #[doc = ""] + #[doc = " When called at block B, it will return the set of authorities that should be"] + #[doc = " used to finalize descendants of this block (B+1, B+2, ...). The block B itself"] + #[doc = " is finalized by the authorities from block B-1."] + pub fn grandpa_authorities( + &self, + ) -> ::subxt::runtime_api::Payload< + types::GrandpaAuthorities, + types::grandpa_authorities::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "GrandpaApi", + "grandpa_authorities", + types::GrandpaAuthorities {}, + [ + 166u8, 76u8, 160u8, 101u8, 242u8, 145u8, 213u8, 10u8, 16u8, 130u8, + 230u8, 196u8, 125u8, 152u8, 92u8, 143u8, 119u8, 223u8, 140u8, 189u8, + 203u8, 95u8, 52u8, 105u8, 147u8, 107u8, 135u8, 228u8, 62u8, 178u8, + 128u8, 33u8, + ], + ) + } + + #[doc = " Submits an unsigned extrinsic to report an equivocation. The caller"] + #[doc = " must provide the equivocation proof and a key ownership proof"] + #[doc = " (should be obtained using `generate_key_ownership_proof`). The"] + #[doc = " extrinsic will be unsigned and should only be accepted for local"] + #[doc = " authorship (not to be broadcast to the network). This method returns"] + #[doc = " `None` when creation of the extrinsic fails, e.g. if equivocation"] + #[doc = " reporting is disabled for the given runtime (i.e. this method is"] + #[doc = " hardcoded to return `None`). Only useful in an offchain context."] + pub fn submit_report_equivocation_unsigned_extrinsic( + &self, + equivocation_proof: types::submit_report_equivocation_unsigned_extrinsic::EquivocationProof, + key_owner_proof: types::submit_report_equivocation_unsigned_extrinsic::KeyOwnerProof, + ) -> ::subxt::runtime_api::Payload< + types::SubmitReportEquivocationUnsignedExtrinsic, + types::submit_report_equivocation_unsigned_extrinsic::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "GrandpaApi", + "submit_report_equivocation_unsigned_extrinsic", + types::SubmitReportEquivocationUnsignedExtrinsic { + equivocation_proof, + key_owner_proof, + }, + [ + 112u8, 94u8, 150u8, 250u8, 132u8, 127u8, 185u8, 24u8, 113u8, 62u8, + 28u8, 171u8, 83u8, 9u8, 41u8, 228u8, 92u8, 137u8, 29u8, 190u8, 214u8, + 232u8, 100u8, 66u8, 100u8, 168u8, 149u8, 122u8, 93u8, 17u8, 236u8, + 104u8, + ], + ) + } + + #[doc = " Generates a proof of key ownership for the given authority in the"] + #[doc = " given set. An example usage of this module is coupled with the"] + #[doc = " session historical module to prove that a given authority key is"] + #[doc = " tied to a given staking identity during a specific session. Proofs"] + #[doc = " of key ownership are necessary for submitting equivocation reports."] + #[doc = " NOTE: even though the API takes a `set_id` as parameter the current"] + #[doc = " implementations ignore this parameter and instead rely on this"] + #[doc = " method being called at the correct block height, i.e. any point at"] + #[doc = " which the given set id is live on-chain. Future implementations will"] + #[doc = " instead use indexed data through an offchain worker, not requiring"] + #[doc = " older states to be available."] + pub fn generate_key_ownership_proof( + &self, + set_id: types::generate_key_ownership_proof::SetId, + authority_id: types::generate_key_ownership_proof::AuthorityId, + ) -> ::subxt::runtime_api::Payload< + types::GenerateKeyOwnershipProof, + types::generate_key_ownership_proof::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "GrandpaApi", + "generate_key_ownership_proof", + types::GenerateKeyOwnershipProof { set_id, authority_id }, + [ + 40u8, 126u8, 113u8, 27u8, 245u8, 45u8, 123u8, 138u8, 12u8, 3u8, 125u8, + 186u8, 151u8, 53u8, 186u8, 93u8, 13u8, 150u8, 163u8, 176u8, 206u8, + 89u8, 244u8, 127u8, 182u8, 85u8, 203u8, 41u8, 101u8, 183u8, 209u8, + 179u8, + ], + ) + } + + #[doc = " Get current GRANDPA authority set id."] + pub fn current_set_id( + &self, + ) -> ::subxt::runtime_api::Payload< + types::CurrentSetId, + types::current_set_id::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "GrandpaApi", + "current_set_id", + types::CurrentSetId {}, + [ + 42u8, 230u8, 120u8, 211u8, 156u8, 245u8, 109u8, 86u8, 100u8, 146u8, + 234u8, 205u8, 41u8, 183u8, 109u8, 42u8, 17u8, 33u8, 156u8, 25u8, 139u8, + 84u8, 101u8, 75u8, 232u8, 198u8, 87u8, 136u8, 218u8, 233u8, 103u8, + 156u8, + ], + ) + } + } + + pub mod types { + use super::runtime_types; + + pub mod grandpa_authorities { + use super::runtime_types; + + pub mod output { + use super::runtime_types; + + pub type Output = ::std::vec::Vec<( + runtime_types::sp_consensus_grandpa::app::Public, + ::core::primitive::u64, + )>; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct GrandpaAuthorities {} + + pub mod submit_report_equivocation_unsigned_extrinsic { + use super::runtime_types; + + pub type EquivocationProof = + runtime_types::sp_consensus_grandpa::EquivocationProof< + ::subxt::utils::H256, + ::core::primitive::u32, + >; + pub type KeyOwnerProof = + runtime_types::sp_consensus_grandpa::OpaqueKeyOwnershipProof; + + pub mod output { + use super::runtime_types; + + pub type Output = ::core::option::Option<()>; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct SubmitReportEquivocationUnsignedExtrinsic { + pub equivocation_proof: + submit_report_equivocation_unsigned_extrinsic::EquivocationProof, + pub key_owner_proof: + submit_report_equivocation_unsigned_extrinsic::KeyOwnerProof, + } + + pub mod generate_key_ownership_proof { + use super::runtime_types; + + pub type SetId = ::core::primitive::u64; + pub type AuthorityId = runtime_types::sp_consensus_grandpa::app::Public; + + pub mod output { + use super::runtime_types; + + pub type Output = ::core::option::Option< + runtime_types::sp_consensus_grandpa::OpaqueKeyOwnershipProof, + >; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct GenerateKeyOwnershipProof { + pub set_id: generate_key_ownership_proof::SetId, + pub authority_id: generate_key_ownership_proof::AuthorityId, + } + + pub mod current_set_id { + use super::runtime_types; + + pub mod output { + use super::runtime_types; + + pub type Output = ::core::primitive::u64; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct CurrentSetId {} + } + } + + pub mod account_nonce_api { + use super::{root_mod, runtime_types}; + + #[doc = " The API to query account nonce."] + pub struct AccountNonceApi; + + impl AccountNonceApi { + #[doc = " Get current account nonce of given `AccountId`."] + pub fn account_nonce( + &self, + account: types::account_nonce::Account, + ) -> ::subxt::runtime_api::Payload< + types::AccountNonce, + types::account_nonce::output::Output, + > { + ::subxt::runtime_api::Payload::new_static( + "AccountNonceApi", + "account_nonce", + types::AccountNonce { account }, + [ + 231u8, 82u8, 7u8, 227u8, 131u8, 2u8, 215u8, 252u8, 173u8, 82u8, 11u8, + 103u8, 200u8, 25u8, 114u8, 116u8, 79u8, 229u8, 152u8, 150u8, 236u8, + 37u8, 101u8, 26u8, 220u8, 146u8, 182u8, 101u8, 73u8, 55u8, 191u8, + 171u8, + ], + ) + } + } + + pub mod types { + use super::runtime_types; + + pub mod account_nonce { + use super::runtime_types; + + pub type Account = ::subxt::utils::AccountId32; + + pub mod output { + use super::runtime_types; + + pub type Output = ::core::primitive::u32; + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct AccountNonce { + pub account: account_nonce::Account, + } + } + } + } + + pub fn custom() -> CustomValuesApi { + CustomValuesApi + } + + pub struct CustomValuesApi; + + impl CustomValuesApi {} + + pub struct ConstantsApi; + + impl ConstantsApi { + pub fn system(&self) -> system::constants::ConstantsApi { + system::constants::ConstantsApi + } + + pub fn timestamp(&self) -> timestamp::constants::ConstantsApi { + timestamp::constants::ConstantsApi + } + + pub fn grandpa(&self) -> grandpa::constants::ConstantsApi { + grandpa::constants::ConstantsApi + } + } + + pub struct StorageApi; + + impl StorageApi { + pub fn system(&self) -> system::storage::StorageApi { + system::storage::StorageApi + } + + pub fn timestamp(&self) -> timestamp::storage::StorageApi { + timestamp::storage::StorageApi + } + + pub fn aura(&self) -> aura::storage::StorageApi { + aura::storage::StorageApi + } + + pub fn grandpa(&self) -> grandpa::storage::StorageApi { + grandpa::storage::StorageApi + } + + pub fn sudo(&self) -> sudo::storage::StorageApi { + sudo::storage::StorageApi + } + + pub fn chronicle(&self) -> chronicle::storage::StorageApi { + chronicle::storage::StorageApi + } + + pub fn opa(&self) -> opa::storage::StorageApi { + opa::storage::StorageApi + } + } + + pub struct TransactionApi; + + impl TransactionApi { + pub fn system(&self) -> system::calls::TransactionApi { + system::calls::TransactionApi + } + + pub fn timestamp(&self) -> timestamp::calls::TransactionApi { + timestamp::calls::TransactionApi + } + + pub fn grandpa(&self) -> grandpa::calls::TransactionApi { + grandpa::calls::TransactionApi + } + + pub fn sudo(&self) -> sudo::calls::TransactionApi { + sudo::calls::TransactionApi + } + + pub fn chronicle(&self) -> chronicle::calls::TransactionApi { + chronicle::calls::TransactionApi + } + + pub fn opa(&self) -> opa::calls::TransactionApi { + opa::calls::TransactionApi + } + } + + #[doc = r" check whether the metadata provided is aligned with this statically generated code."] + pub fn is_codegen_valid_for(metadata: &::subxt::Metadata) -> bool { + let runtime_metadata_hash = metadata + .hasher() + .only_these_pallets(&PALLETS) + .only_these_runtime_apis(&RUNTIME_APIS) + .hash(); + runtime_metadata_hash + == [ + 132u8, 151u8, 134u8, 46u8, 233u8, 247u8, 71u8, 77u8, 208u8, 250u8, 224u8, 194u8, + 87u8, 250u8, 180u8, 8u8, 171u8, 141u8, 155u8, 124u8, 69u8, 131u8, 176u8, 140u8, + 166u8, 22u8, 252u8, 16u8, 219u8, 185u8, 158u8, 56u8, + ] + } + + pub mod system { + use super::{root_mod, runtime_types}; + + #[doc = "Error for the System pallet"] + pub type Error = runtime_types::frame_system::pallet::Error; + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub type Call = runtime_types::frame_system::pallet::Call; + + pub mod calls { + use super::{root_mod, runtime_types}; + + type DispatchError = runtime_types::sp_runtime::DispatchError; + + pub mod types { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::remark`]."] + pub struct Remark { + pub remark: remark::Remark, + } + + pub mod remark { + use super::runtime_types; + + pub type Remark = ::std::vec::Vec<::core::primitive::u8>; + } + + impl ::subxt::blocks::StaticExtrinsic for Remark { + const CALL: &'static str = "remark"; + const PALLET: &'static str = "System"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::set_heap_pages`]."] + pub struct SetHeapPages { + pub pages: set_heap_pages::Pages, + } + + pub mod set_heap_pages { + use super::runtime_types; + + pub type Pages = ::core::primitive::u64; + } + + impl ::subxt::blocks::StaticExtrinsic for SetHeapPages { + const CALL: &'static str = "set_heap_pages"; + const PALLET: &'static str = "System"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::set_code`]."] + pub struct SetCode { + pub code: set_code::Code, + } + + pub mod set_code { + use super::runtime_types; + + pub type Code = ::std::vec::Vec<::core::primitive::u8>; + } + + impl ::subxt::blocks::StaticExtrinsic for SetCode { + const CALL: &'static str = "set_code"; + const PALLET: &'static str = "System"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::set_code_without_checks`]."] + pub struct SetCodeWithoutChecks { + pub code: set_code_without_checks::Code, + } + + pub mod set_code_without_checks { + use super::runtime_types; + + pub type Code = ::std::vec::Vec<::core::primitive::u8>; + } + + impl ::subxt::blocks::StaticExtrinsic for SetCodeWithoutChecks { + const CALL: &'static str = "set_code_without_checks"; + const PALLET: &'static str = "System"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::set_storage`]."] + pub struct SetStorage { + pub items: set_storage::Items, + } + + pub mod set_storage { + use super::runtime_types; + + pub type Items = ::std::vec::Vec<( + ::std::vec::Vec<::core::primitive::u8>, + ::std::vec::Vec<::core::primitive::u8>, + )>; + } + + impl ::subxt::blocks::StaticExtrinsic for SetStorage { + const CALL: &'static str = "set_storage"; + const PALLET: &'static str = "System"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::kill_storage`]."] + pub struct KillStorage { + pub keys: kill_storage::Keys, + } + + pub mod kill_storage { + use super::runtime_types; + + pub type Keys = ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>>; + } + + impl ::subxt::blocks::StaticExtrinsic for KillStorage { + const CALL: &'static str = "kill_storage"; + const PALLET: &'static str = "System"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::kill_prefix`]."] + pub struct KillPrefix { + pub prefix: kill_prefix::Prefix, + pub subkeys: kill_prefix::Subkeys, + } + + pub mod kill_prefix { + use super::runtime_types; + + pub type Prefix = ::std::vec::Vec<::core::primitive::u8>; + pub type Subkeys = ::core::primitive::u32; + } + + impl ::subxt::blocks::StaticExtrinsic for KillPrefix { + const CALL: &'static str = "kill_prefix"; + const PALLET: &'static str = "System"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::remark_with_event`]."] + pub struct RemarkWithEvent { + pub remark: remark_with_event::Remark, + } + + pub mod remark_with_event { + use super::runtime_types; + + pub type Remark = ::std::vec::Vec<::core::primitive::u8>; + } + + impl ::subxt::blocks::StaticExtrinsic for RemarkWithEvent { + const CALL: &'static str = "remark_with_event"; + const PALLET: &'static str = "System"; + } + } + + pub struct TransactionApi; + + impl TransactionApi { + #[doc = "See [`Pallet::remark`]."] + pub fn remark( + &self, + remark: types::remark::Remark, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "System", + "remark", + types::Remark { remark }, + [ + 43u8, 126u8, 180u8, 174u8, 141u8, 48u8, 52u8, 125u8, 166u8, 212u8, + 216u8, 98u8, 100u8, 24u8, 132u8, 71u8, 101u8, 64u8, 246u8, 169u8, 33u8, + 250u8, 147u8, 208u8, 2u8, 40u8, 129u8, 209u8, 232u8, 207u8, 207u8, + 13u8, + ], + ) + } + + #[doc = "See [`Pallet::set_heap_pages`]."] + pub fn set_heap_pages( + &self, + pages: types::set_heap_pages::Pages, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "System", + "set_heap_pages", + types::SetHeapPages { pages }, + [ + 188u8, 191u8, 99u8, 216u8, 219u8, 109u8, 141u8, 50u8, 78u8, 235u8, + 215u8, 242u8, 195u8, 24u8, 111u8, 76u8, 229u8, 64u8, 99u8, 225u8, + 134u8, 121u8, 81u8, 209u8, 127u8, 223u8, 98u8, 215u8, 150u8, 70u8, + 57u8, 147u8, + ], + ) + } + + #[doc = "See [`Pallet::set_code`]."] + pub fn set_code( + &self, + code: types::set_code::Code, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "System", + "set_code", + types::SetCode { code }, + [ + 233u8, 248u8, 88u8, 245u8, 28u8, 65u8, 25u8, 169u8, 35u8, 237u8, 19u8, + 203u8, 136u8, 160u8, 18u8, 3u8, 20u8, 197u8, 81u8, 169u8, 244u8, 188u8, + 27u8, 147u8, 147u8, 236u8, 65u8, 25u8, 3u8, 143u8, 182u8, 22u8, + ], + ) + } + + #[doc = "See [`Pallet::set_code_without_checks`]."] + pub fn set_code_without_checks( + &self, + code: types::set_code_without_checks::Code, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "System", + "set_code_without_checks", + types::SetCodeWithoutChecks { code }, + [ + 82u8, 212u8, 157u8, 44u8, 70u8, 0u8, 143u8, 15u8, 109u8, 109u8, 107u8, + 157u8, 141u8, 42u8, 169u8, 11u8, 15u8, 186u8, 252u8, 138u8, 10u8, + 147u8, 15u8, 178u8, 247u8, 229u8, 213u8, 98u8, 207u8, 231u8, 119u8, + 115u8, + ], + ) + } + + #[doc = "See [`Pallet::set_storage`]."] + pub fn set_storage( + &self, + items: types::set_storage::Items, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "System", + "set_storage", + types::SetStorage { items }, + [ + 141u8, 216u8, 52u8, 222u8, 223u8, 136u8, 123u8, 181u8, 19u8, 75u8, + 163u8, 102u8, 229u8, 189u8, 158u8, 142u8, 95u8, 235u8, 240u8, 49u8, + 150u8, 76u8, 78u8, 137u8, 126u8, 88u8, 183u8, 88u8, 231u8, 146u8, + 234u8, 43u8, + ], + ) + } + + #[doc = "See [`Pallet::kill_storage`]."] + pub fn kill_storage( + &self, + keys: types::kill_storage::Keys, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "System", + "kill_storage", + types::KillStorage { keys }, + [ + 73u8, 63u8, 196u8, 36u8, 144u8, 114u8, 34u8, 213u8, 108u8, 93u8, 209u8, + 234u8, 153u8, 185u8, 33u8, 91u8, 187u8, 195u8, 223u8, 130u8, 58u8, + 156u8, 63u8, 47u8, 228u8, 249u8, 216u8, 139u8, 143u8, 177u8, 41u8, + 35u8, + ], + ) + } + + #[doc = "See [`Pallet::kill_prefix`]."] + pub fn kill_prefix( + &self, + prefix: types::kill_prefix::Prefix, + subkeys: types::kill_prefix::Subkeys, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "System", + "kill_prefix", + types::KillPrefix { prefix, subkeys }, + [ + 184u8, 57u8, 139u8, 24u8, 208u8, 87u8, 108u8, 215u8, 198u8, 189u8, + 175u8, 242u8, 167u8, 215u8, 97u8, 63u8, 110u8, 166u8, 238u8, 98u8, + 67u8, 236u8, 111u8, 110u8, 234u8, 81u8, 102u8, 5u8, 182u8, 5u8, 214u8, + 85u8, + ], + ) + } + + #[doc = "See [`Pallet::remark_with_event`]."] + pub fn remark_with_event( + &self, + remark: types::remark_with_event::Remark, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "System", + "remark_with_event", + types::RemarkWithEvent { remark }, + [ + 120u8, 120u8, 153u8, 92u8, 184u8, 85u8, 34u8, 2u8, 174u8, 206u8, 105u8, + 228u8, 233u8, 130u8, 80u8, 246u8, 228u8, 59u8, 234u8, 240u8, 4u8, 49u8, + 147u8, 170u8, 115u8, 91u8, 149u8, 200u8, 228u8, 181u8, 8u8, 154u8, + ], + ) + } + } + } + + #[doc = "Event for the System pallet."] + pub type Event = runtime_types::frame_system::pallet::Event; + + pub mod events { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "An extrinsic completed successfully."] + pub struct ExtrinsicSuccess { + pub dispatch_info: extrinsic_success::DispatchInfo, + } + + pub mod extrinsic_success { + use super::runtime_types; + + pub type DispatchInfo = runtime_types::frame_support::dispatch::DispatchInfo; + } + + impl ::subxt::events::StaticEvent for ExtrinsicSuccess { + const EVENT: &'static str = "ExtrinsicSuccess"; + const PALLET: &'static str = "System"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "An extrinsic failed."] + pub struct ExtrinsicFailed { + pub dispatch_error: extrinsic_failed::DispatchError, + pub dispatch_info: extrinsic_failed::DispatchInfo, + } + + pub mod extrinsic_failed { + use super::runtime_types; + + pub type DispatchError = runtime_types::sp_runtime::DispatchError; + pub type DispatchInfo = runtime_types::frame_support::dispatch::DispatchInfo; + } + + impl ::subxt::events::StaticEvent for ExtrinsicFailed { + const EVENT: &'static str = "ExtrinsicFailed"; + const PALLET: &'static str = "System"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "`:code` was updated."] + pub struct CodeUpdated; + + impl ::subxt::events::StaticEvent for CodeUpdated { + const EVENT: &'static str = "CodeUpdated"; + const PALLET: &'static str = "System"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "A new account was created."] + pub struct NewAccount { + pub account: new_account::Account, + } + + pub mod new_account { + use super::runtime_types; + + pub type Account = ::subxt::utils::AccountId32; + } + + impl ::subxt::events::StaticEvent for NewAccount { + const EVENT: &'static str = "NewAccount"; + const PALLET: &'static str = "System"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "An account was reaped."] + pub struct KilledAccount { + pub account: killed_account::Account, + } + + pub mod killed_account { + use super::runtime_types; + + pub type Account = ::subxt::utils::AccountId32; + } + + impl ::subxt::events::StaticEvent for KilledAccount { + const EVENT: &'static str = "KilledAccount"; + const PALLET: &'static str = "System"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "On on-chain remark happened."] + pub struct Remarked { + pub sender: remarked::Sender, + pub hash: remarked::Hash, + } + + pub mod remarked { + use super::runtime_types; + + pub type Sender = ::subxt::utils::AccountId32; + pub type Hash = ::subxt::utils::H256; + } + + impl ::subxt::events::StaticEvent for Remarked { + const EVENT: &'static str = "Remarked"; + const PALLET: &'static str = "System"; + } + } + + pub mod storage { + use super::runtime_types; + + pub mod types { + use super::runtime_types; + + pub mod account { + use super::runtime_types; + + pub type Account = + runtime_types::frame_system::AccountInfo<::core::primitive::u32, ()>; + pub type Param0 = ::subxt::utils::AccountId32; + } + + pub mod extrinsic_count { + use super::runtime_types; + + pub type ExtrinsicCount = ::core::primitive::u32; + } + + pub mod block_weight { + use super::runtime_types; + + pub type BlockWeight = runtime_types::frame_support::dispatch::PerDispatchClass< + runtime_types::sp_weights::weight_v2::Weight, + >; + } + + pub mod all_extrinsics_len { + use super::runtime_types; + + pub type AllExtrinsicsLen = ::core::primitive::u32; + } + + pub mod block_hash { + use super::runtime_types; + + pub type BlockHash = ::subxt::utils::H256; + pub type Param0 = ::core::primitive::u32; + } + + pub mod extrinsic_data { + use super::runtime_types; + + pub type ExtrinsicData = ::std::vec::Vec<::core::primitive::u8>; + pub type Param0 = ::core::primitive::u32; + } + + pub mod number { + use super::runtime_types; + + pub type Number = ::core::primitive::u32; + } + + pub mod parent_hash { + use super::runtime_types; + + pub type ParentHash = ::subxt::utils::H256; + } + + pub mod digest { + use super::runtime_types; + + pub type Digest = runtime_types::sp_runtime::generic::digest::Digest; + } + + pub mod events { + use super::runtime_types; + + pub type Events = ::std::vec::Vec< + runtime_types::frame_system::EventRecord< + runtime_types::runtime_chronicle::RuntimeEvent, + ::subxt::utils::H256, + >, + >; + } + + pub mod event_count { + use super::runtime_types; + + pub type EventCount = ::core::primitive::u32; + } + + pub mod event_topics { + use super::runtime_types; + + pub type EventTopics = + ::std::vec::Vec<(::core::primitive::u32, ::core::primitive::u32)>; + pub type Param0 = ::subxt::utils::H256; + } + + pub mod last_runtime_upgrade { + use super::runtime_types; + + pub type LastRuntimeUpgrade = + runtime_types::frame_system::LastRuntimeUpgradeInfo; + } + + pub mod upgraded_to_u32_ref_count { + use super::runtime_types; + + pub type UpgradedToU32RefCount = ::core::primitive::bool; + } + + pub mod upgraded_to_triple_ref_count { + use super::runtime_types; + + pub type UpgradedToTripleRefCount = ::core::primitive::bool; + } + + pub mod execution_phase { + use super::runtime_types; + + pub type ExecutionPhase = runtime_types::frame_system::Phase; + } + } + + pub struct StorageApi; + + impl StorageApi { + #[doc = " The full account information for a particular account ID."] + pub fn account_iter( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::account::Account, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::Address::new_static( + "System", + "Account", + vec![], + [ + 207u8, 128u8, 217u8, 6u8, 244u8, 231u8, 113u8, 230u8, 246u8, 220u8, + 226u8, 62u8, 206u8, 203u8, 104u8, 119u8, 181u8, 97u8, 211u8, 3u8, + 157u8, 102u8, 196u8, 131u8, 51u8, 221u8, 41u8, 183u8, 108u8, 28u8, + 247u8, 73u8, + ], + ) + } + + #[doc = " The full account information for a particular account ID."] + pub fn account( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::account::Account, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "Account", + vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], + [ + 207u8, 128u8, 217u8, 6u8, 244u8, 231u8, 113u8, 230u8, 246u8, 220u8, + 226u8, 62u8, 206u8, 203u8, 104u8, 119u8, 181u8, 97u8, 211u8, 3u8, + 157u8, 102u8, 196u8, 131u8, 51u8, 221u8, 41u8, 183u8, 108u8, 28u8, + 247u8, 73u8, + ], + ) + } + + #[doc = " Total extrinsics count for the current block."] + pub fn extrinsic_count( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::extrinsic_count::ExtrinsicCount, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "ExtrinsicCount", + vec![], + [ + 102u8, 76u8, 236u8, 42u8, 40u8, 231u8, 33u8, 222u8, 123u8, 147u8, + 153u8, 148u8, 234u8, 203u8, 181u8, 119u8, 6u8, 187u8, 177u8, 199u8, + 120u8, 47u8, 137u8, 254u8, 96u8, 100u8, 165u8, 182u8, 249u8, 230u8, + 159u8, 79u8, + ], + ) + } + + #[doc = " The current weight for the block."] + pub fn block_weight( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::block_weight::BlockWeight, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "BlockWeight", + vec![], + [ + 158u8, 46u8, 228u8, 89u8, 210u8, 214u8, 84u8, 154u8, 50u8, 68u8, 63u8, + 62u8, 43u8, 42u8, 99u8, 27u8, 54u8, 42u8, 146u8, 44u8, 241u8, 216u8, + 229u8, 30u8, 216u8, 255u8, 165u8, 238u8, 181u8, 130u8, 36u8, 102u8, + ], + ) + } + + #[doc = " Total length (in bytes) for all extrinsics put together, for the current block."] + pub fn all_extrinsics_len( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::all_extrinsics_len::AllExtrinsicsLen, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "AllExtrinsicsLen", + vec![], + [ + 117u8, 86u8, 61u8, 243u8, 41u8, 51u8, 102u8, 214u8, 137u8, 100u8, + 243u8, 185u8, 122u8, 174u8, 187u8, 117u8, 86u8, 189u8, 63u8, 135u8, + 101u8, 218u8, 203u8, 201u8, 237u8, 254u8, 128u8, 183u8, 169u8, 221u8, + 242u8, 65u8, + ], + ) + } + + #[doc = " Map of block numbers to block hashes."] + pub fn block_hash_iter( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::block_hash::BlockHash, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::Address::new_static( + "System", + "BlockHash", + vec![], + [ + 217u8, 32u8, 215u8, 253u8, 24u8, 182u8, 207u8, 178u8, 157u8, 24u8, + 103u8, 100u8, 195u8, 165u8, 69u8, 152u8, 112u8, 181u8, 56u8, 192u8, + 164u8, 16u8, 20u8, 222u8, 28u8, 214u8, 144u8, 142u8, 146u8, 69u8, + 202u8, 118u8, + ], + ) + } + + #[doc = " Map of block numbers to block hashes."] + pub fn block_hash( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::block_hash::BlockHash, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "BlockHash", + vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], + [ + 217u8, 32u8, 215u8, 253u8, 24u8, 182u8, 207u8, 178u8, 157u8, 24u8, + 103u8, 100u8, 195u8, 165u8, 69u8, 152u8, 112u8, 181u8, 56u8, 192u8, + 164u8, 16u8, 20u8, 222u8, 28u8, 214u8, 144u8, 142u8, 146u8, 69u8, + 202u8, 118u8, + ], + ) + } + + #[doc = " Extrinsics data for the current block (maps an extrinsic's index to its data)."] + pub fn extrinsic_data_iter( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::extrinsic_data::ExtrinsicData, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::Address::new_static( + "System", + "ExtrinsicData", + vec![], + [ + 160u8, 180u8, 122u8, 18u8, 196u8, 26u8, 2u8, 37u8, 115u8, 232u8, 133u8, + 220u8, 106u8, 245u8, 4u8, 129u8, 42u8, 84u8, 241u8, 45u8, 199u8, 179u8, + 128u8, 61u8, 170u8, 137u8, 231u8, 156u8, 247u8, 57u8, 47u8, 38u8, + ], + ) + } + + #[doc = " Extrinsics data for the current block (maps an extrinsic's index to its data)."] + pub fn extrinsic_data( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::extrinsic_data::ExtrinsicData, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "ExtrinsicData", + vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], + [ + 160u8, 180u8, 122u8, 18u8, 196u8, 26u8, 2u8, 37u8, 115u8, 232u8, 133u8, + 220u8, 106u8, 245u8, 4u8, 129u8, 42u8, 84u8, 241u8, 45u8, 199u8, 179u8, + 128u8, 61u8, 170u8, 137u8, 231u8, 156u8, 247u8, 57u8, 47u8, 38u8, + ], + ) + } + + #[doc = " The current block number being processed. Set by `execute_block`."] + pub fn number( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::number::Number, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "Number", + vec![], + [ + 30u8, 194u8, 177u8, 90u8, 194u8, 232u8, 46u8, 180u8, 85u8, 129u8, 14u8, + 9u8, 8u8, 8u8, 23u8, 95u8, 230u8, 5u8, 13u8, 105u8, 125u8, 2u8, 22u8, + 200u8, 78u8, 93u8, 115u8, 28u8, 150u8, 113u8, 48u8, 53u8, + ], + ) + } + + #[doc = " Hash of the previous block."] + pub fn parent_hash( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::parent_hash::ParentHash, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "ParentHash", + vec![], + [ + 26u8, 130u8, 11u8, 216u8, 155u8, 71u8, 128u8, 170u8, 30u8, 153u8, 21u8, + 192u8, 62u8, 93u8, 137u8, 80u8, 120u8, 81u8, 202u8, 94u8, 248u8, 125u8, + 71u8, 82u8, 141u8, 229u8, 32u8, 56u8, 73u8, 50u8, 101u8, 78u8, + ], + ) + } + + #[doc = " Digest of the current block, also part of the block header."] + pub fn digest( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::digest::Digest, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "Digest", + vec![], + [ + 61u8, 64u8, 237u8, 91u8, 145u8, 232u8, 17u8, 254u8, 181u8, 16u8, 234u8, + 91u8, 51u8, 140u8, 254u8, 131u8, 98u8, 135u8, 21u8, 37u8, 251u8, 20u8, + 58u8, 92u8, 123u8, 141u8, 14u8, 227u8, 146u8, 46u8, 222u8, 117u8, + ], + ) + } + + #[doc = " Events deposited for the current block."] + #[doc = ""] + #[doc = " NOTE: The item is unbound and should therefore never be read on chain."] + #[doc = " It could otherwise inflate the PoV size of a block."] + #[doc = ""] + #[doc = " Events have a large in-memory size. Box the events to not go out-of-memory"] + #[doc = " just in case someone still reads them from within the runtime."] + pub fn events( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::events::Events, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "Events", + vec![], + [ + 47u8, 5u8, 76u8, 40u8, 21u8, 207u8, 254u8, 42u8, 181u8, 203u8, 152u8, + 15u8, 76u8, 55u8, 70u8, 116u8, 60u8, 212u8, 81u8, 157u8, 220u8, 244u8, + 168u8, 174u8, 57u8, 37u8, 145u8, 109u8, 39u8, 83u8, 134u8, 248u8, + ], + ) + } + + #[doc = " The number of events in the `Events` list."] + pub fn event_count( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::event_count::EventCount, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "EventCount", + vec![], + [ + 175u8, 24u8, 252u8, 184u8, 210u8, 167u8, 146u8, 143u8, 164u8, 80u8, + 151u8, 205u8, 189u8, 189u8, 55u8, 220u8, 47u8, 101u8, 181u8, 33u8, + 254u8, 131u8, 13u8, 143u8, 3u8, 244u8, 245u8, 45u8, 2u8, 210u8, 79u8, + 133u8, + ], + ) + } + + #[doc = " Mapping between a topic (represented by T::Hash) and a vector of indexes"] + #[doc = " of events in the `>` list."] + #[doc = ""] + #[doc = " All topic vectors have deterministic storage locations depending on the topic. This"] + #[doc = " allows light-clients to leverage the changes trie storage tracking mechanism and"] + #[doc = " in case of changes fetch the list of events of interest."] + #[doc = ""] + #[doc = " The value has the type `(BlockNumberFor, EventIndex)` because if we used only just"] + #[doc = " the `EventIndex` then in case if the topic has the same contents on the next block"] + #[doc = " no notification will be triggered thus the event might be lost."] + pub fn event_topics_iter( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::event_topics::EventTopics, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::Address::new_static( + "System", + "EventTopics", + vec![], + [ + 40u8, 225u8, 14u8, 75u8, 44u8, 176u8, 76u8, 34u8, 143u8, 107u8, 69u8, + 133u8, 114u8, 13u8, 172u8, 250u8, 141u8, 73u8, 12u8, 65u8, 217u8, 63u8, + 120u8, 241u8, 48u8, 106u8, 143u8, 161u8, 128u8, 100u8, 166u8, 59u8, + ], + ) + } + + #[doc = " Mapping between a topic (represented by T::Hash) and a vector of indexes"] + #[doc = " of events in the `>` list."] + #[doc = ""] + #[doc = " All topic vectors have deterministic storage locations depending on the topic. This"] + #[doc = " allows light-clients to leverage the changes trie storage tracking mechanism and"] + #[doc = " in case of changes fetch the list of events of interest."] + #[doc = ""] + #[doc = " The value has the type `(BlockNumberFor, EventIndex)` because if we used only just"] + #[doc = " the `EventIndex` then in case if the topic has the same contents on the next block"] + #[doc = " no notification will be triggered thus the event might be lost."] + pub fn event_topics( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::event_topics::EventTopics, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "EventTopics", + vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], + [ + 40u8, 225u8, 14u8, 75u8, 44u8, 176u8, 76u8, 34u8, 143u8, 107u8, 69u8, + 133u8, 114u8, 13u8, 172u8, 250u8, 141u8, 73u8, 12u8, 65u8, 217u8, 63u8, + 120u8, 241u8, 48u8, 106u8, 143u8, 161u8, 128u8, 100u8, 166u8, 59u8, + ], + ) + } + + #[doc = " Stores the `spec_version` and `spec_name` of when the last runtime upgrade happened."] + pub fn last_runtime_upgrade( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::last_runtime_upgrade::LastRuntimeUpgrade, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "LastRuntimeUpgrade", + vec![], + [ + 137u8, 29u8, 175u8, 75u8, 197u8, 208u8, 91u8, 207u8, 156u8, 87u8, + 148u8, 68u8, 91u8, 140u8, 22u8, 233u8, 1u8, 229u8, 56u8, 34u8, 40u8, + 194u8, 253u8, 30u8, 163u8, 39u8, 54u8, 209u8, 13u8, 27u8, 139u8, 184u8, + ], + ) + } + + #[doc = " True if we have upgraded so that `type RefCount` is `u32`. False (default) if not."] + pub fn upgraded_to_u32_ref_count( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::upgraded_to_u32_ref_count::UpgradedToU32RefCount, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "UpgradedToU32RefCount", + vec![], + [ + 229u8, 73u8, 9u8, 132u8, 186u8, 116u8, 151u8, 171u8, 145u8, 29u8, 34u8, + 130u8, 52u8, 146u8, 124u8, 175u8, 79u8, 189u8, 147u8, 230u8, 234u8, + 107u8, 124u8, 31u8, 2u8, 22u8, 86u8, 190u8, 4u8, 147u8, 50u8, 245u8, + ], + ) + } + + #[doc = " True if we have upgraded so that AccountInfo contains three types of `RefCount`. False"] + #[doc = " (default) if not."] + pub fn upgraded_to_triple_ref_count( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::upgraded_to_triple_ref_count::UpgradedToTripleRefCount, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "UpgradedToTripleRefCount", + vec![], + [ + 97u8, 66u8, 124u8, 243u8, 27u8, 167u8, 147u8, 81u8, 254u8, 201u8, + 101u8, 24u8, 40u8, 231u8, 14u8, 179u8, 154u8, 163u8, 71u8, 81u8, 185u8, + 167u8, 82u8, 254u8, 189u8, 3u8, 101u8, 207u8, 206u8, 194u8, 155u8, + 151u8, + ], + ) + } + + #[doc = " The execution phase of the block."] + pub fn execution_phase( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::execution_phase::ExecutionPhase, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "System", + "ExecutionPhase", + vec![], + [ + 191u8, 129u8, 100u8, 134u8, 126u8, 116u8, 154u8, 203u8, 220u8, 200u8, + 0u8, 26u8, 161u8, 250u8, 133u8, 205u8, 146u8, 24u8, 5u8, 156u8, 158u8, + 35u8, 36u8, 253u8, 52u8, 235u8, 86u8, 167u8, 35u8, 100u8, 119u8, 27u8, + ], + ) + } + } + } + + pub mod constants { + use super::runtime_types; + + pub struct ConstantsApi; + + impl ConstantsApi { + #[doc = " Block & extrinsics weights: base values and limits."] + pub fn block_weights( + &self, + ) -> ::subxt::constants::Address + { + ::subxt::constants::Address::new_static( + "System", + "BlockWeights", + [ + 176u8, 124u8, 225u8, 136u8, 25u8, 73u8, 247u8, 33u8, 82u8, 206u8, 85u8, + 190u8, 127u8, 102u8, 71u8, 11u8, 185u8, 8u8, 58u8, 0u8, 94u8, 55u8, + 163u8, 177u8, 104u8, 59u8, 60u8, 136u8, 246u8, 116u8, 0u8, 239u8, + ], + ) + } + + #[doc = " The maximum length of a block (in bytes)."] + pub fn block_length( + &self, + ) -> ::subxt::constants::Address { + ::subxt::constants::Address::new_static( + "System", + "BlockLength", + [ + 23u8, 242u8, 225u8, 39u8, 225u8, 67u8, 152u8, 41u8, 155u8, 104u8, 68u8, + 229u8, 185u8, 133u8, 10u8, 143u8, 184u8, 152u8, 234u8, 44u8, 140u8, + 96u8, 166u8, 235u8, 162u8, 160u8, 72u8, 7u8, 35u8, 194u8, 3u8, 37u8, + ], + ) + } + + #[doc = " Maximum number of block number to block hash mappings to keep (oldest pruned first)."] + pub fn block_hash_count( + &self, + ) -> ::subxt::constants::Address<::core::primitive::u32> { + ::subxt::constants::Address::new_static( + "System", + "BlockHashCount", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + + #[doc = " The weight of runtime database operations the runtime can invoke."] + pub fn db_weight( + &self, + ) -> ::subxt::constants::Address { + ::subxt::constants::Address::new_static( + "System", + "DbWeight", + [ + 42u8, 43u8, 178u8, 142u8, 243u8, 203u8, 60u8, 173u8, 118u8, 111u8, + 200u8, 170u8, 102u8, 70u8, 237u8, 187u8, 198u8, 120u8, 153u8, 232u8, + 183u8, 76u8, 74u8, 10u8, 70u8, 243u8, 14u8, 218u8, 213u8, 126u8, 29u8, + 177u8, + ], + ) + } + + #[doc = " Get the chain's current version."] + pub fn version( + &self, + ) -> ::subxt::constants::Address { + ::subxt::constants::Address::new_static( + "System", + "Version", + [ + 219u8, 45u8, 162u8, 245u8, 177u8, 246u8, 48u8, 126u8, 191u8, 157u8, + 228u8, 83u8, 111u8, 133u8, 183u8, 13u8, 148u8, 108u8, 92u8, 102u8, + 72u8, 205u8, 74u8, 242u8, 233u8, 79u8, 20u8, 170u8, 72u8, 202u8, 158u8, + 165u8, + ], + ) + } + + #[doc = " The designated SS58 prefix of this chain."] + #[doc = ""] + #[doc = " This replaces the \"ss58Format\" property declared in the chain spec. Reason is"] + #[doc = " that the runtime should know about the prefix in order to make use of it as"] + #[doc = " an identifier of the chain."] + pub fn ss58_prefix(&self) -> ::subxt::constants::Address<::core::primitive::u16> { + ::subxt::constants::Address::new_static( + "System", + "SS58Prefix", + [ + 116u8, 33u8, 2u8, 170u8, 181u8, 147u8, 171u8, 169u8, 167u8, 227u8, + 41u8, 144u8, 11u8, 236u8, 82u8, 100u8, 74u8, 60u8, 184u8, 72u8, 169u8, + 90u8, 208u8, 135u8, 15u8, 117u8, 10u8, 123u8, 128u8, 193u8, 29u8, 70u8, + ], + ) + } + } + } + } + + pub mod timestamp { + use super::{root_mod, runtime_types}; + + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub type Call = runtime_types::pallet_timestamp::pallet::Call; + + pub mod calls { + use super::{root_mod, runtime_types}; + + type DispatchError = runtime_types::sp_runtime::DispatchError; + + pub mod types { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::set`]."] + pub struct Set { + #[codec(compact)] + pub now: set::Now, + } + + pub mod set { + use super::runtime_types; + + pub type Now = ::core::primitive::u64; + } + + impl ::subxt::blocks::StaticExtrinsic for Set { + const CALL: &'static str = "set"; + const PALLET: &'static str = "Timestamp"; + } + } + + pub struct TransactionApi; + + impl TransactionApi { + #[doc = "See [`Pallet::set`]."] + pub fn set(&self, now: types::set::Now) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "Timestamp", + "set", + types::Set { now }, + [ + 37u8, 95u8, 49u8, 218u8, 24u8, 22u8, 0u8, 95u8, 72u8, 35u8, 155u8, + 199u8, 213u8, 54u8, 207u8, 22u8, 185u8, 193u8, 221u8, 70u8, 18u8, + 200u8, 4u8, 231u8, 195u8, 173u8, 6u8, 122u8, 11u8, 203u8, 231u8, 227u8, + ], + ) + } + } + } + + pub mod storage { + use super::runtime_types; + + pub mod types { + use super::runtime_types; + + pub mod now { + use super::runtime_types; + + pub type Now = ::core::primitive::u64; + } + + pub mod did_update { + use super::runtime_types; + + pub type DidUpdate = ::core::primitive::bool; + } + } + + pub struct StorageApi; + + impl StorageApi { + #[doc = " The current time for the current block."] + pub fn now( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::now::Now, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "Timestamp", + "Now", + vec![], + [ + 44u8, 50u8, 80u8, 30u8, 195u8, 146u8, 123u8, 238u8, 8u8, 163u8, 187u8, + 92u8, 61u8, 39u8, 51u8, 29u8, 173u8, 169u8, 217u8, 158u8, 85u8, 187u8, + 141u8, 26u8, 12u8, 115u8, 51u8, 11u8, 200u8, 244u8, 138u8, 152u8, + ], + ) + } + + #[doc = " Whether the timestamp has been updated in this block."] + #[doc = ""] + #[doc = " This value is updated to `true` upon successful submission of a timestamp by a node."] + #[doc = " It is then checked at the end of each block execution in the `on_finalize` hook."] + pub fn did_update( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::did_update::DidUpdate, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "Timestamp", + "DidUpdate", + vec![], + [ + 229u8, 175u8, 246u8, 102u8, 237u8, 158u8, 212u8, 229u8, 238u8, 214u8, + 205u8, 160u8, 164u8, 252u8, 195u8, 75u8, 139u8, 110u8, 22u8, 34u8, + 248u8, 204u8, 107u8, 46u8, 20u8, 200u8, 238u8, 167u8, 71u8, 41u8, + 214u8, 140u8, + ], + ) + } + } + } + + pub mod constants { + use super::runtime_types; + + pub struct ConstantsApi; + + impl ConstantsApi { + #[doc = " The minimum period between blocks."] + #[doc = ""] + #[doc = " Be aware that this is different to the *expected* period that the block production"] + #[doc = " apparatus provides. Your chosen consensus system will generally work with this to"] + #[doc = " determine a sensible block time. For example, in the Aura pallet it will be double this"] + #[doc = " period on default settings."] + pub fn minimum_period( + &self, + ) -> ::subxt::constants::Address<::core::primitive::u64> { + ::subxt::constants::Address::new_static( + "Timestamp", + "MinimumPeriod", + [ + 128u8, 214u8, 205u8, 242u8, 181u8, 142u8, 124u8, 231u8, 190u8, 146u8, + 59u8, 226u8, 157u8, 101u8, 103u8, 117u8, 249u8, 65u8, 18u8, 191u8, + 103u8, 119u8, 53u8, 85u8, 81u8, 96u8, 220u8, 42u8, 184u8, 239u8, 42u8, + 246u8, + ], + ) + } + } + } + } + + pub mod aura { + use super::{root_mod, runtime_types}; + + pub mod storage { + use super::runtime_types; + + pub mod types { + use super::runtime_types; + + pub mod authorities { + use super::runtime_types; + + pub type Authorities = + runtime_types::bounded_collections::bounded_vec::BoundedVec< + runtime_types::sp_consensus_aura::sr25519::app_sr25519::Public, + >; + } + + pub mod current_slot { + use super::runtime_types; + + pub type CurrentSlot = runtime_types::sp_consensus_slots::Slot; + } + } + + pub struct StorageApi; + + impl StorageApi { + #[doc = " The current authority set."] + pub fn authorities( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::authorities::Authorities, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "Aura", + "Authorities", + vec![], + [ + 232u8, 129u8, 167u8, 104u8, 47u8, 188u8, 238u8, 164u8, 6u8, 29u8, + 129u8, 45u8, 64u8, 182u8, 194u8, 47u8, 0u8, 73u8, 63u8, 102u8, 204u8, + 94u8, 111u8, 96u8, 137u8, 7u8, 141u8, 110u8, 180u8, 80u8, 228u8, 16u8, + ], + ) + } + + #[doc = " The current slot of this block."] + #[doc = ""] + #[doc = " This will be set in `on_initialize`."] + pub fn current_slot( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::current_slot::CurrentSlot, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "Aura", + "CurrentSlot", + vec![], + [ + 112u8, 199u8, 115u8, 248u8, 217u8, 242u8, 45u8, 231u8, 178u8, 53u8, + 236u8, 167u8, 219u8, 238u8, 81u8, 243u8, 39u8, 140u8, 68u8, 19u8, + 201u8, 169u8, 211u8, 133u8, 135u8, 213u8, 150u8, 105u8, 60u8, 252u8, + 43u8, 57u8, + ], + ) + } + } + } + } + + pub mod grandpa { + use super::{root_mod, runtime_types}; + + #[doc = "The `Error` enum of this pallet."] + pub type Error = runtime_types::pallet_grandpa::pallet::Error; + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub type Call = runtime_types::pallet_grandpa::pallet::Call; + + pub mod calls { + use super::{root_mod, runtime_types}; + + type DispatchError = runtime_types::sp_runtime::DispatchError; + + pub mod types { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::report_equivocation`]."] + pub struct ReportEquivocation { + pub equivocation_proof: + ::std::boxed::Box, + pub key_owner_proof: report_equivocation::KeyOwnerProof, + } + + pub mod report_equivocation { + use super::runtime_types; + + pub type EquivocationProof = + runtime_types::sp_consensus_grandpa::EquivocationProof< + ::subxt::utils::H256, + ::core::primitive::u32, + >; + pub type KeyOwnerProof = runtime_types::sp_core::Void; + } + + impl ::subxt::blocks::StaticExtrinsic for ReportEquivocation { + const CALL: &'static str = "report_equivocation"; + const PALLET: &'static str = "Grandpa"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::report_equivocation_unsigned`]."] + pub struct ReportEquivocationUnsigned { + pub equivocation_proof: + ::std::boxed::Box, + pub key_owner_proof: report_equivocation_unsigned::KeyOwnerProof, + } + + pub mod report_equivocation_unsigned { + use super::runtime_types; + + pub type EquivocationProof = + runtime_types::sp_consensus_grandpa::EquivocationProof< + ::subxt::utils::H256, + ::core::primitive::u32, + >; + pub type KeyOwnerProof = runtime_types::sp_core::Void; + } + + impl ::subxt::blocks::StaticExtrinsic for ReportEquivocationUnsigned { + const CALL: &'static str = "report_equivocation_unsigned"; + const PALLET: &'static str = "Grandpa"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::note_stalled`]."] + pub struct NoteStalled { + pub delay: note_stalled::Delay, + pub best_finalized_block_number: note_stalled::BestFinalizedBlockNumber, + } + + pub mod note_stalled { + use super::runtime_types; + + pub type Delay = ::core::primitive::u32; + pub type BestFinalizedBlockNumber = ::core::primitive::u32; + } + + impl ::subxt::blocks::StaticExtrinsic for NoteStalled { + const CALL: &'static str = "note_stalled"; + const PALLET: &'static str = "Grandpa"; + } + } + + pub struct TransactionApi; + + impl TransactionApi { + #[doc = "See [`Pallet::report_equivocation`]."] + pub fn report_equivocation( + &self, + equivocation_proof: types::report_equivocation::EquivocationProof, + key_owner_proof: types::report_equivocation::KeyOwnerProof, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "Grandpa", + "report_equivocation", + types::ReportEquivocation { + equivocation_proof: ::std::boxed::Box::new(equivocation_proof), + key_owner_proof, + }, + [ + 158u8, 70u8, 189u8, 51u8, 231u8, 191u8, 199u8, 33u8, 64u8, 156u8, 71u8, + 243u8, 122u8, 199u8, 216u8, 10u8, 45u8, 73u8, 198u8, 141u8, 31u8, + 209u8, 58u8, 164u8, 219u8, 124u8, 242u8, 26u8, 114u8, 52u8, 65u8, + 106u8, + ], + ) + } + + #[doc = "See [`Pallet::report_equivocation_unsigned`]."] + pub fn report_equivocation_unsigned( + &self, + equivocation_proof: types::report_equivocation_unsigned::EquivocationProof, + key_owner_proof: types::report_equivocation_unsigned::KeyOwnerProof, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "Grandpa", + "report_equivocation_unsigned", + types::ReportEquivocationUnsigned { + equivocation_proof: ::std::boxed::Box::new(equivocation_proof), + key_owner_proof, + }, + [ + 53u8, 23u8, 255u8, 215u8, 105u8, 11u8, 67u8, 177u8, 234u8, 248u8, + 183u8, 57u8, 230u8, 239u8, 54u8, 238u8, 115u8, 170u8, 153u8, 18u8, + 55u8, 195u8, 85u8, 98u8, 109u8, 194u8, 57u8, 225u8, 139u8, 237u8, + 171u8, 152u8, + ], + ) + } + + #[doc = "See [`Pallet::note_stalled`]."] + pub fn note_stalled( + &self, + delay: types::note_stalled::Delay, + best_finalized_block_number: types::note_stalled::BestFinalizedBlockNumber, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "Grandpa", + "note_stalled", + types::NoteStalled { delay, best_finalized_block_number }, + [ + 158u8, 25u8, 64u8, 114u8, 131u8, 139u8, 227u8, 132u8, 42u8, 107u8, + 40u8, 249u8, 18u8, 93u8, 254u8, 86u8, 37u8, 67u8, 250u8, 35u8, 241u8, + 194u8, 209u8, 20u8, 39u8, 75u8, 186u8, 21u8, 48u8, 124u8, 151u8, 31u8, + ], + ) + } + } + } + + #[doc = "The `Event` enum of this pallet"] + pub type Event = runtime_types::pallet_grandpa::pallet::Event; + + pub mod events { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "New authority set has been applied."] + pub struct NewAuthorities { + pub authority_set: new_authorities::AuthoritySet, + } + + pub mod new_authorities { + use super::runtime_types; + + pub type AuthoritySet = ::std::vec::Vec<( + runtime_types::sp_consensus_grandpa::app::Public, + ::core::primitive::u64, + )>; + } + + impl ::subxt::events::StaticEvent for NewAuthorities { + const EVENT: &'static str = "NewAuthorities"; + const PALLET: &'static str = "Grandpa"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "Current authority set has been paused."] + pub struct Paused; + + impl ::subxt::events::StaticEvent for Paused { + const EVENT: &'static str = "Paused"; + const PALLET: &'static str = "Grandpa"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "Current authority set has been resumed."] + pub struct Resumed; + + impl ::subxt::events::StaticEvent for Resumed { + const EVENT: &'static str = "Resumed"; + const PALLET: &'static str = "Grandpa"; + } + } + + pub mod storage { + use super::runtime_types; + + pub mod types { + use super::runtime_types; + + pub mod state { + use super::runtime_types; + + pub type State = + runtime_types::pallet_grandpa::StoredState<::core::primitive::u32>; + } + + pub mod pending_change { + use super::runtime_types; + + pub type PendingChange = + runtime_types::pallet_grandpa::StoredPendingChange<::core::primitive::u32>; + } + + pub mod next_forced { + use super::runtime_types; + + pub type NextForced = ::core::primitive::u32; + } + + pub mod stalled { + use super::runtime_types; + + pub type Stalled = (::core::primitive::u32, ::core::primitive::u32); + } + + pub mod current_set_id { + use super::runtime_types; + + pub type CurrentSetId = ::core::primitive::u64; + } + + pub mod set_id_session { + use super::runtime_types; + + pub type SetIdSession = ::core::primitive::u32; + pub type Param0 = ::core::primitive::u64; + } + } + + pub struct StorageApi; + + impl StorageApi { + #[doc = " State of the current authority set."] + pub fn state( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::state::State, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "Grandpa", + "State", + vec![], + [ + 73u8, 71u8, 112u8, 83u8, 238u8, 75u8, 44u8, 9u8, 180u8, 33u8, 30u8, + 121u8, 98u8, 96u8, 61u8, 133u8, 16u8, 70u8, 30u8, 249u8, 34u8, 148u8, + 15u8, 239u8, 164u8, 157u8, 52u8, 27u8, 144u8, 52u8, 223u8, 109u8, + ], + ) + } + + #[doc = " Pending change: (signaled at, scheduled change)."] + pub fn pending_change( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::pending_change::PendingChange, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "Grandpa", + "PendingChange", + vec![], + [ + 150u8, 194u8, 185u8, 248u8, 239u8, 43u8, 141u8, 253u8, 61u8, 106u8, + 74u8, 164u8, 209u8, 204u8, 206u8, 200u8, 32u8, 38u8, 11u8, 78u8, 84u8, + 243u8, 181u8, 142u8, 179u8, 151u8, 81u8, 204u8, 244u8, 150u8, 137u8, + 250u8, + ], + ) + } + + #[doc = " next block number where we can force a change."] + pub fn next_forced( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::next_forced::NextForced, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "Grandpa", + "NextForced", + vec![], + [ + 3u8, 231u8, 56u8, 18u8, 87u8, 112u8, 227u8, 126u8, 180u8, 131u8, 255u8, + 141u8, 82u8, 34u8, 61u8, 47u8, 234u8, 37u8, 95u8, 62u8, 33u8, 235u8, + 231u8, 122u8, 125u8, 8u8, 223u8, 95u8, 255u8, 204u8, 40u8, 97u8, + ], + ) + } + + #[doc = " `true` if we are currently stalled."] + pub fn stalled( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::stalled::Stalled, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "Grandpa", + "Stalled", + vec![], + [ + 6u8, 81u8, 205u8, 142u8, 195u8, 48u8, 0u8, 247u8, 108u8, 170u8, 10u8, + 249u8, 72u8, 206u8, 32u8, 103u8, 109u8, 57u8, 51u8, 21u8, 144u8, 204u8, + 79u8, 8u8, 191u8, 185u8, 38u8, 34u8, 118u8, 223u8, 75u8, 241u8, + ], + ) + } + + #[doc = " The number of changes (both in terms of keys and underlying economic responsibilities)"] + #[doc = " in the \"set\" of Grandpa validators from genesis."] + pub fn current_set_id( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::current_set_id::CurrentSetId, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::Address::new_static( + "Grandpa", + "CurrentSetId", + vec![], + [ + 234u8, 215u8, 218u8, 42u8, 30u8, 76u8, 129u8, 40u8, 125u8, 137u8, + 207u8, 47u8, 46u8, 213u8, 159u8, 50u8, 175u8, 81u8, 155u8, 123u8, + 246u8, 175u8, 156u8, 68u8, 22u8, 113u8, 135u8, 137u8, 163u8, 18u8, + 115u8, 73u8, + ], + ) + } + + #[doc = " A mapping from grandpa set ID to the index of the *most recent* session for which its"] + #[doc = " members were responsible."] + #[doc = ""] + #[doc = " This is only used for validating equivocation proofs. An equivocation proof must"] + #[doc = " contains a key-ownership proof for a given session, therefore we need a way to tie"] + #[doc = " together sessions and GRANDPA set ids, i.e. we need to validate that a validator"] + #[doc = " was the owner of a given key on a given session, and what the active set ID was"] + #[doc = " during that session."] + #[doc = ""] + #[doc = " TWOX-NOTE: `SetId` is not under user control."] + pub fn set_id_session_iter( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::set_id_session::SetIdSession, + (), + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::Address::new_static( + "Grandpa", + "SetIdSession", + vec![], + [ + 47u8, 0u8, 239u8, 121u8, 187u8, 213u8, 254u8, 50u8, 238u8, 10u8, 162u8, + 65u8, 189u8, 166u8, 37u8, 74u8, 82u8, 81u8, 160u8, 20u8, 180u8, 253u8, + 238u8, 18u8, 209u8, 203u8, 38u8, 148u8, 16u8, 105u8, 72u8, 169u8, + ], + ) + } + + #[doc = " A mapping from grandpa set ID to the index of the *most recent* session for which its"] + #[doc = " members were responsible."] + #[doc = ""] + #[doc = " This is only used for validating equivocation proofs. An equivocation proof must"] + #[doc = " contains a key-ownership proof for a given session, therefore we need a way to tie"] + #[doc = " together sessions and GRANDPA set ids, i.e. we need to validate that a validator"] + #[doc = " was the owner of a given key on a given session, and what the active set ID was"] + #[doc = " during that session."] + #[doc = ""] + #[doc = " TWOX-NOTE: `SetId` is not under user control."] + pub fn set_id_session( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::set_id_session::SetIdSession, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "Grandpa", + "SetIdSession", + vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], + [ + 47u8, 0u8, 239u8, 121u8, 187u8, 213u8, 254u8, 50u8, 238u8, 10u8, 162u8, + 65u8, 189u8, 166u8, 37u8, 74u8, 82u8, 81u8, 160u8, 20u8, 180u8, 253u8, + 238u8, 18u8, 209u8, 203u8, 38u8, 148u8, 16u8, 105u8, 72u8, 169u8, + ], + ) + } + } + } + + pub mod constants { + use super::runtime_types; + + pub struct ConstantsApi; + + impl ConstantsApi { + #[doc = " Max Authorities in use"] + pub fn max_authorities( + &self, + ) -> ::subxt::constants::Address<::core::primitive::u32> { + ::subxt::constants::Address::new_static( + "Grandpa", + "MaxAuthorities", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + + #[doc = " The maximum number of nominators for each validator."] + pub fn max_nominators( + &self, + ) -> ::subxt::constants::Address<::core::primitive::u32> { + ::subxt::constants::Address::new_static( + "Grandpa", + "MaxNominators", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + + #[doc = " The maximum number of entries to keep in the set id to session index mapping."] + #[doc = ""] + #[doc = " Since the `SetIdSession` map is only used for validating equivocations this"] + #[doc = " value should relate to the bonding duration of whatever staking system is"] + #[doc = " being used (if any). If equivocation handling is not enabled then this value"] + #[doc = " can be zero."] + pub fn max_set_id_session_entries( + &self, + ) -> ::subxt::constants::Address<::core::primitive::u64> { + ::subxt::constants::Address::new_static( + "Grandpa", + "MaxSetIdSessionEntries", + [ + 128u8, 214u8, 205u8, 242u8, 181u8, 142u8, 124u8, 231u8, 190u8, 146u8, + 59u8, 226u8, 157u8, 101u8, 103u8, 117u8, 249u8, 65u8, 18u8, 191u8, + 103u8, 119u8, 53u8, 85u8, 81u8, 96u8, 220u8, 42u8, 184u8, 239u8, 42u8, + 246u8, + ], + ) + } + } + } + } + + pub mod sudo { + use super::{root_mod, runtime_types}; + + #[doc = "Error for the Sudo pallet"] + pub type Error = runtime_types::pallet_sudo::pallet::Error; + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub type Call = runtime_types::pallet_sudo::pallet::Call; + + pub mod calls { + use super::{root_mod, runtime_types}; + + type DispatchError = runtime_types::sp_runtime::DispatchError; + + pub mod types { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::sudo`]."] + pub struct Sudo { + pub call: ::std::boxed::Box, + } + + pub mod sudo { + use super::runtime_types; + + pub type Call = runtime_types::runtime_chronicle::RuntimeCall; + } + + impl ::subxt::blocks::StaticExtrinsic for Sudo { + const CALL: &'static str = "sudo"; + const PALLET: &'static str = "Sudo"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::sudo_unchecked_weight`]."] + pub struct SudoUncheckedWeight { + pub call: ::std::boxed::Box, + pub weight: sudo_unchecked_weight::Weight, + } + + pub mod sudo_unchecked_weight { + use super::runtime_types; + + pub type Call = runtime_types::runtime_chronicle::RuntimeCall; + pub type Weight = runtime_types::sp_weights::weight_v2::Weight; + } + + impl ::subxt::blocks::StaticExtrinsic for SudoUncheckedWeight { + const CALL: &'static str = "sudo_unchecked_weight"; + const PALLET: &'static str = "Sudo"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::set_key`]."] + pub struct SetKey { + pub new: set_key::New, + } + + pub mod set_key { + use super::runtime_types; + + pub type New = ::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()>; + } + + impl ::subxt::blocks::StaticExtrinsic for SetKey { + const CALL: &'static str = "set_key"; + const PALLET: &'static str = "Sudo"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::sudo_as`]."] + pub struct SudoAs { + pub who: sudo_as::Who, + pub call: ::std::boxed::Box, + } + + pub mod sudo_as { + use super::runtime_types; + + pub type Who = ::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()>; + pub type Call = runtime_types::runtime_chronicle::RuntimeCall; + } + + impl ::subxt::blocks::StaticExtrinsic for SudoAs { + const CALL: &'static str = "sudo_as"; + const PALLET: &'static str = "Sudo"; + } + } + + pub struct TransactionApi; + + impl TransactionApi { + #[doc = "See [`Pallet::sudo`]."] + pub fn sudo(&self, call: types::sudo::Call) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "Sudo", + "sudo", + types::Sudo { call: ::std::boxed::Box::new(call) }, + [ + 237u8, 167u8, 188u8, 42u8, 53u8, 81u8, 128u8, 15u8, 168u8, 39u8, 8u8, + 134u8, 49u8, 136u8, 251u8, 162u8, 141u8, 66u8, 243u8, 169u8, 44u8, + 68u8, 82u8, 232u8, 87u8, 62u8, 193u8, 74u8, 68u8, 123u8, 241u8, 151u8, + ], + ) + } + + #[doc = "See [`Pallet::sudo_unchecked_weight`]."] + pub fn sudo_unchecked_weight( + &self, + call: types::sudo_unchecked_weight::Call, + weight: types::sudo_unchecked_weight::Weight, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "Sudo", + "sudo_unchecked_weight", + types::SudoUncheckedWeight { call: ::std::boxed::Box::new(call), weight }, + [ + 191u8, 162u8, 221u8, 59u8, 231u8, 212u8, 11u8, 144u8, 158u8, 138u8, + 158u8, 143u8, 73u8, 173u8, 231u8, 102u8, 250u8, 172u8, 214u8, 16u8, + 184u8, 159u8, 182u8, 106u8, 161u8, 61u8, 28u8, 251u8, 117u8, 159u8, + 255u8, 124u8, + ], + ) + } + + #[doc = "See [`Pallet::set_key`]."] + pub fn set_key( + &self, + new: types::set_key::New, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "Sudo", + "set_key", + types::SetKey { new }, + [ + 9u8, 73u8, 39u8, 205u8, 188u8, 127u8, 143u8, 54u8, 128u8, 94u8, 8u8, + 227u8, 197u8, 44u8, 70u8, 93u8, 228u8, 196u8, 64u8, 165u8, 226u8, + 158u8, 101u8, 192u8, 22u8, 193u8, 102u8, 84u8, 21u8, 35u8, 92u8, 198u8, + ], + ) + } + + #[doc = "See [`Pallet::sudo_as`]."] + pub fn sudo_as( + &self, + who: types::sudo_as::Who, + call: types::sudo_as::Call, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "Sudo", + "sudo_as", + types::SudoAs { who, call: ::std::boxed::Box::new(call) }, + [ + 230u8, 21u8, 191u8, 185u8, 54u8, 39u8, 134u8, 240u8, 51u8, 145u8, + 105u8, 151u8, 191u8, 224u8, 205u8, 96u8, 71u8, 3u8, 149u8, 212u8, 92u8, + 9u8, 75u8, 107u8, 144u8, 158u8, 151u8, 129u8, 2u8, 45u8, 228u8, 118u8, + ], + ) + } + } + } + + #[doc = "The `Event` enum of this pallet"] + pub type Event = runtime_types::pallet_sudo::pallet::Event; + + pub mod events { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "A sudo call just took place."] + pub struct Sudid { + pub sudo_result: sudid::SudoResult, + } + + pub mod sudid { + use super::runtime_types; + + pub type SudoResult = + ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>; + } + + impl ::subxt::events::StaticEvent for Sudid { + const EVENT: &'static str = "Sudid"; + const PALLET: &'static str = "Sudo"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "The sudo key has been updated."] + pub struct KeyChanged { + pub old_sudoer: key_changed::OldSudoer, + } + + pub mod key_changed { + use super::runtime_types; + + pub type OldSudoer = ::core::option::Option<::subxt::utils::AccountId32>; + } + + impl ::subxt::events::StaticEvent for KeyChanged { + const EVENT: &'static str = "KeyChanged"; + const PALLET: &'static str = "Sudo"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "A [sudo_as](Pallet::sudo_as) call just took place."] + pub struct SudoAsDone { + pub sudo_result: sudo_as_done::SudoResult, + } + + pub mod sudo_as_done { + use super::runtime_types; + + pub type SudoResult = + ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>; + } + + impl ::subxt::events::StaticEvent for SudoAsDone { + const EVENT: &'static str = "SudoAsDone"; + const PALLET: &'static str = "Sudo"; + } + } + + pub mod storage { + use super::runtime_types; + + pub mod types { + use super::runtime_types; + + pub mod key { + use super::runtime_types; + + pub type Key = ::subxt::utils::AccountId32; + } + } + + pub struct StorageApi; + + impl StorageApi { + #[doc = " The `AccountId` of the sudo key."] + pub fn key( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::key::Key, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "Sudo", + "Key", + vec![], + [ + 72u8, 14u8, 225u8, 162u8, 205u8, 247u8, 227u8, 105u8, 116u8, 57u8, 4u8, + 31u8, 84u8, 137u8, 227u8, 228u8, 133u8, 245u8, 206u8, 227u8, 117u8, + 36u8, 252u8, 151u8, 107u8, 15u8, 180u8, 4u8, 4u8, 152u8, 195u8, 144u8, + ], + ) + } + } + } + } + + pub mod chronicle { + use super::{root_mod, runtime_types}; + + #[doc = "The `Error` enum of this pallet."] + pub type Error = runtime_types::pallet_chronicle::pallet::Error; + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub type Call = runtime_types::pallet_chronicle::pallet::Call; + + pub mod calls { + use super::{root_mod, runtime_types}; + + type DispatchError = runtime_types::sp_runtime::DispatchError; + + pub mod types { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::apply`]."] + pub struct Apply { + pub operations: apply::Operations, + } + + pub mod apply { + use super::runtime_types; + + pub type Operations = runtime_types::common::ledger::OperationSubmission; + } + + impl ::subxt::blocks::StaticExtrinsic for Apply { + const CALL: &'static str = "apply"; + const PALLET: &'static str = "Chronicle"; + } + } + + pub struct TransactionApi; + + impl TransactionApi { + #[doc = "See [`Pallet::apply`]."] + pub fn apply( + &self, + operations: types::apply::Operations, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "Chronicle", + "apply", + types::Apply { operations }, + [ + 155u8, 52u8, 231u8, 240u8, 97u8, 198u8, 219u8, 89u8, 101u8, 93u8, 60u8, + 206u8, 9u8, 244u8, 58u8, 69u8, 176u8, 61u8, 109u8, 126u8, 75u8, 178u8, + 195u8, 2u8, 158u8, 67u8, 158u8, 143u8, 9u8, 252u8, 61u8, 139u8, + ], + ) + } + } + } + + #[doc = "The `Event` enum of this pallet"] + pub type Event = runtime_types::pallet_chronicle::pallet::Event; + + pub mod events { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Applied(pub applied::Field0, pub applied::Field1, pub applied::Field2); + + pub mod applied { + use super::runtime_types; + + pub type Field0 = runtime_types::common::prov::model::ProvModel; + pub type Field1 = runtime_types::common::identity::SignedIdentity; + pub type Field2 = [::core::primitive::u8; 16usize]; + } + + impl ::subxt::events::StaticEvent for Applied { + const EVENT: &'static str = "Applied"; + const PALLET: &'static str = "Chronicle"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Contradiction( + pub contradiction::Field0, + pub contradiction::Field1, + pub contradiction::Field2, + ); + + pub mod contradiction { + use super::runtime_types; + + pub type Field0 = runtime_types::common::prov::model::contradiction::Contradiction; + pub type Field1 = runtime_types::common::identity::SignedIdentity; + pub type Field2 = [::core::primitive::u8; 16usize]; + } + + impl ::subxt::events::StaticEvent for Contradiction { + const EVENT: &'static str = "Contradiction"; + const PALLET: &'static str = "Chronicle"; + } + } + + pub mod storage { + use super::runtime_types; + + pub mod types { + use super::runtime_types; + + pub mod provenance { + use super::runtime_types; + + pub type Provenance = runtime_types::common::prov::model::ProvModel; + pub type Param0 = runtime_types::common::ledger::ChronicleAddress; + } + + pub mod opa_settings { + use super::runtime_types; + + pub type OpaSettings = + ::core::option::Option; + } + } + + pub struct StorageApi; + + impl StorageApi { + pub fn provenance_iter( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::provenance::Provenance, + (), + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::Address::new_static( + "Chronicle", + "Provenance", + vec![], + [ + 89u8, 248u8, 19u8, 1u8, 96u8, 148u8, 157u8, 57u8, 205u8, 85u8, 157u8, + 10u8, 226u8, 22u8, 253u8, 189u8, 239u8, 95u8, 193u8, 72u8, 200u8, 4u8, + 236u8, 165u8, 80u8, 97u8, 150u8, 137u8, 142u8, 46u8, 37u8, 37u8, + ], + ) + } + + pub fn provenance( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::provenance::Provenance, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "Chronicle", + "Provenance", + vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], + [ + 89u8, 248u8, 19u8, 1u8, 96u8, 148u8, 157u8, 57u8, 205u8, 85u8, 157u8, + 10u8, 226u8, 22u8, 253u8, 189u8, 239u8, 95u8, 193u8, 72u8, 200u8, 4u8, + 236u8, 165u8, 80u8, 97u8, 150u8, 137u8, 142u8, 46u8, 37u8, 37u8, + ], + ) + } + + pub fn opa_settings( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::opa_settings::OpaSettings, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "Chronicle", + "OpaSettings", + vec![], + [ + 147u8, 57u8, 197u8, 174u8, 245u8, 128u8, 185u8, 25u8, 59u8, 211u8, + 103u8, 144u8, 133u8, 65u8, 135u8, 26u8, 249u8, 122u8, 98u8, 119u8, + 113u8, 203u8, 8u8, 216u8, 144u8, 203u8, 28u8, 152u8, 76u8, 108u8, 17u8, + 149u8, + ], + ) + } + } + } + } + + pub mod opa { + use super::{root_mod, runtime_types}; + + #[doc = "The `Error` enum of this pallet."] + pub type Error = runtime_types::pallet_opa::pallet::Error; + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub type Call = runtime_types::pallet_opa::pallet::Call; + + pub mod calls { + use super::{root_mod, runtime_types}; + + type DispatchError = runtime_types::sp_runtime::DispatchError; + + pub mod types { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "See [`Pallet::apply`]."] + pub struct Apply { + pub submission: apply::Submission, + } + + pub mod apply { + use super::runtime_types; + + pub type Submission = runtime_types::common::opa::core::codec::OpaSubmissionV1; + } + + impl ::subxt::blocks::StaticExtrinsic for Apply { + const CALL: &'static str = "apply"; + const PALLET: &'static str = "Opa"; + } + } + + pub struct TransactionApi; + + impl TransactionApi { + #[doc = "See [`Pallet::apply`]."] + pub fn apply( + &self, + submission: types::apply::Submission, + ) -> ::subxt::tx::Payload { + ::subxt::tx::Payload::new_static( + "Opa", + "apply", + types::Apply { submission }, + [ + 234u8, 194u8, 237u8, 194u8, 37u8, 84u8, 219u8, 67u8, 228u8, 177u8, + 34u8, 4u8, 100u8, 5u8, 196u8, 246u8, 3u8, 28u8, 65u8, 188u8, 66u8, + 227u8, 204u8, 143u8, 143u8, 230u8, 11u8, 229u8, 77u8, 61u8, 108u8, + 19u8, + ], + ) + } + } + } + + #[doc = "The `Event` enum of this pallet"] + pub type Event = runtime_types::pallet_opa::pallet::Event; + + pub mod events { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct PolicyUpdate(pub policy_update::Field0, pub policy_update::Field1); + + pub mod policy_update { + use super::runtime_types; + + pub type Field0 = runtime_types::common::opa::core::codec::PolicyMetaV1; + pub type Field1 = runtime_types::common::prov::model::ChronicleTransactionId; + } + + impl ::subxt::events::StaticEvent for PolicyUpdate { + const EVENT: &'static str = "PolicyUpdate"; + const PALLET: &'static str = "Opa"; + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct KeyUpdate(pub key_update::Field0, pub key_update::Field1); + + pub mod key_update { + use super::runtime_types; + + pub type Field0 = runtime_types::common::opa::core::codec::KeysV1; + pub type Field1 = runtime_types::common::prov::model::ChronicleTransactionId; + } + + impl ::subxt::events::StaticEvent for KeyUpdate { + const EVENT: &'static str = "KeyUpdate"; + const PALLET: &'static str = "Opa"; + } + } + + pub mod storage { + use super::runtime_types; + + pub mod types { + use super::runtime_types; + + pub mod policy_store { + use super::runtime_types; + + pub type PolicyStore = runtime_types::common::opa::core::codec::PolicyV1; + pub type Param0 = runtime_types::common::opa::core::PolicyAddress; + } + + pub mod policy_meta_store { + use super::runtime_types; + + pub type PolicyMetaStore = + runtime_types::common::opa::core::codec::PolicyMetaV1; + pub type Param0 = runtime_types::common::opa::core::PolicyMetaAddress; + } + + pub mod key_store { + use super::runtime_types; + + pub type KeyStore = runtime_types::common::opa::core::codec::KeysV1; + pub type Param0 = runtime_types::common::opa::core::KeyAddress; + } + } + + pub struct StorageApi; + + impl StorageApi { + pub fn policy_store_iter( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::policy_store::PolicyStore, + (), + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::Address::new_static( + "Opa", + "PolicyStore", + vec![], + [ + 196u8, 59u8, 202u8, 150u8, 122u8, 101u8, 78u8, 223u8, 11u8, 18u8, + 183u8, 27u8, 146u8, 220u8, 7u8, 187u8, 13u8, 188u8, 251u8, 24u8, 81u8, + 227u8, 248u8, 52u8, 162u8, 245u8, 38u8, 136u8, 20u8, 90u8, 197u8, + 181u8, + ], + ) + } + + pub fn policy_store( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::policy_store::PolicyStore, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "Opa", + "PolicyStore", + vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], + [ + 196u8, 59u8, 202u8, 150u8, 122u8, 101u8, 78u8, 223u8, 11u8, 18u8, + 183u8, 27u8, 146u8, 220u8, 7u8, 187u8, 13u8, 188u8, 251u8, 24u8, 81u8, + 227u8, 248u8, 52u8, 162u8, 245u8, 38u8, 136u8, 20u8, 90u8, 197u8, + 181u8, + ], + ) + } + + pub fn policy_meta_store_iter( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::policy_meta_store::PolicyMetaStore, + (), + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::Address::new_static( + "Opa", + "PolicyMetaStore", + vec![], + [ + 189u8, 108u8, 84u8, 44u8, 122u8, 229u8, 34u8, 242u8, 101u8, 92u8, + 113u8, 242u8, 103u8, 46u8, 77u8, 145u8, 102u8, 172u8, 41u8, 9u8, 189u8, + 102u8, 178u8, 31u8, 0u8, 164u8, 222u8, 220u8, 240u8, 91u8, 126u8, + 249u8, + ], + ) + } + + pub fn policy_meta_store( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::policy_meta_store::PolicyMetaStore, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "Opa", + "PolicyMetaStore", + vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], + [ + 189u8, 108u8, 84u8, 44u8, 122u8, 229u8, 34u8, 242u8, 101u8, 92u8, + 113u8, 242u8, 103u8, 46u8, 77u8, 145u8, 102u8, 172u8, 41u8, 9u8, 189u8, + 102u8, 178u8, 31u8, 0u8, 164u8, 222u8, 220u8, 240u8, 91u8, 126u8, + 249u8, + ], + ) + } + + pub fn key_store_iter( + &self, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::key_store::KeyStore, + (), + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::Address::new_static( + "Opa", + "KeyStore", + vec![], + [ + 169u8, 58u8, 57u8, 223u8, 245u8, 168u8, 156u8, 245u8, 216u8, 144u8, + 41u8, 29u8, 118u8, 241u8, 23u8, 231u8, 77u8, 178u8, 178u8, 237u8, 99u8, + 240u8, 13u8, 53u8, 27u8, 166u8, 232u8, 13u8, 61u8, 138u8, 218u8, 67u8, + ], + ) + } + + pub fn key_store( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::Address< + ::subxt::storage::address::StaticStorageMapKey, + types::key_store::KeyStore, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::Address::new_static( + "Opa", + "KeyStore", + vec![::subxt::storage::address::make_static_storage_map_key(_0.borrow())], + [ + 169u8, 58u8, 57u8, 223u8, 245u8, 168u8, 156u8, 245u8, 216u8, 144u8, + 41u8, 29u8, 118u8, 241u8, 23u8, 231u8, 77u8, 178u8, 178u8, 237u8, 99u8, + 240u8, 13u8, 53u8, 27u8, 166u8, 232u8, 13u8, 61u8, 138u8, 218u8, 67u8, + ], + ) + } + } + } + } + + pub mod runtime_types { + use super::runtime_types; + + pub mod bounded_collections { + use super::runtime_types; + + pub mod bounded_vec { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct BoundedVec<_0>(pub ::std::vec::Vec<_0>); + } + + pub mod weak_bounded_vec { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct WeakBoundedVec<_0>(pub ::std::vec::Vec<_0>); + } + } + + pub mod common { + use super::runtime_types; + + pub mod attributes { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Attribute { + pub typ: ::std::string::String, + pub value: runtime_types::common::attributes::SerdeWrapper, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Attributes { + pub typ: ::core::option::Option, + pub items: ::subxt::utils::KeyedVec< + ::std::string::String, + runtime_types::common::attributes::Attribute, + >, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct SerdeWrapper(pub ::std::string::String); + } + + pub mod identity { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct SignedIdentity { + pub identity: ::std::string::String, + pub signature: ::core::option::Option<::std::vec::Vec<::core::primitive::u8>>, + pub verifying_key: + ::core::option::Option<::std::vec::Vec<::core::primitive::u8>>, + } + } + + pub mod ledger { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ChronicleAddress { + pub namespace: + ::core::option::Option, + pub resource: runtime_types::common::prov::id::ChronicleIri, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct OperationSubmission { + pub correlation_id: [::core::primitive::u8; 16usize], + pub items: ::std::vec::Vec< + runtime_types::common::prov::operations::ChronicleOperation, + >, + pub identity: runtime_types::common::identity::SignedIdentity, + } + } + + pub mod opa { + use super::runtime_types; + + pub mod core { + use super::runtime_types; + + pub mod codec { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct BootstrapRootV1 { + pub public_key: runtime_types::common::opa::core::PemEncoded, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct KeyRegistrationV1 { + pub key: runtime_types::common::opa::core::PemEncoded, + pub version: ::core::primitive::u64, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct KeysV1 { + pub id: ::std::string::String, + pub current: runtime_types::common::opa::core::codec::KeyRegistrationV1, + pub expired: ::core::option::Option< + runtime_types::common::opa::core::codec::KeyRegistrationV1, + >, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct NewPublicKeyV1 { + pub public_key: runtime_types::common::opa::core::PemEncoded, + pub id: ::std::string::String, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct OpaSubmissionV1 { + pub version: ::std::string::String, + pub correlation_id: [::core::primitive::u8; 16usize], + pub span_id: ::core::primitive::u64, + pub payload: runtime_types::common::opa::core::codec::PayloadV1, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum OperationV1 { + #[codec(index = 0)] + RegisterKey(runtime_types::common::opa::core::codec::RegisterKeyV1), + #[codec(index = 1)] + RotateKey(runtime_types::common::opa::core::codec::RotateKeyV1), + #[codec(index = 2)] + SetPolicy(runtime_types::common::opa::core::codec::SetPolicyV1), + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum PayloadV1 { + #[codec(index = 0)] + BootstrapRoot(runtime_types::common::opa::core::codec::BootstrapRootV1), + #[codec(index = 1)] + SignedOperation( + runtime_types::common::opa::core::codec::SignedOperationV1, + ), + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct PolicyMetaV1 { + pub id: ::std::string::String, + pub hash: runtime_types::common::opa::core::H128, + pub policy_address: runtime_types::common::opa::core::PolicyAddress, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct PolicyV1(pub ::std::vec::Vec<::core::primitive::u8>); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct RegisterKeyV1 { + pub public_key: runtime_types::common::opa::core::PemEncoded, + pub id: ::std::string::String, + pub overwrite_existing: ::core::primitive::bool, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct RotateKeyV1 { + pub payload: runtime_types::common::opa::core::codec::NewPublicKeyV1, + pub previous_signing_key: runtime_types::common::opa::core::PemEncoded, + pub previous_signature: ::std::vec::Vec<::core::primitive::u8>, + pub new_signing_key: runtime_types::common::opa::core::PemEncoded, + pub new_signature: ::std::vec::Vec<::core::primitive::u8>, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct SetPolicyV1 { + pub id: ::std::string::String, + pub policy: runtime_types::common::opa::core::Policy, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct SignedOperationPayloadV1 { + pub operation: runtime_types::common::opa::core::codec::OperationV1, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct SignedOperationV1 { + pub payload: + runtime_types::common::opa::core::codec::SignedOperationPayloadV1, + pub verifying_key: runtime_types::common::opa::core::PemEncoded, + pub signature: ::std::vec::Vec<::core::primitive::u8>, + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct H128(pub [::core::primitive::u8; 16usize]); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct KeyAddress(pub runtime_types::common::opa::core::H128); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct OpaSettings { + pub policy_address: runtime_types::common::opa::core::PolicyAddress, + pub policy_name: ::std::string::String, + pub entrypoint: ::std::string::String, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct PemEncoded(pub ::std::string::String); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Policy(pub ::std::vec::Vec<::core::primitive::u8>); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct PolicyAddress(pub runtime_types::common::opa::core::H128); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct PolicyMetaAddress(pub runtime_types::common::opa::core::H128); + } + } + + pub mod prov { + use super::runtime_types; + + pub mod id { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ActivityId(pub runtime_types::common::prov::id::ExternalId); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct AgentId(pub runtime_types::common::prov::id::ExternalId); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct AssociationId { + pub agent: runtime_types::common::prov::id::ExternalId, + pub activity: runtime_types::common::prov::id::ExternalId, + pub role: ::core::option::Option, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct AttributionId { + pub agent: runtime_types::common::prov::id::ExternalId, + pub entity: runtime_types::common::prov::id::ExternalId, + pub role: ::core::option::Option, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum ChronicleIri { + #[codec(index = 0)] + Namespace(runtime_types::common::prov::id::NamespaceId), + #[codec(index = 1)] + Domaintype(runtime_types::common::prov::id::DomaintypeId), + #[codec(index = 2)] + Entity(runtime_types::common::prov::id::EntityId), + #[codec(index = 3)] + Agent(runtime_types::common::prov::id::AgentId), + #[codec(index = 4)] + Activity(runtime_types::common::prov::id::ActivityId), + #[codec(index = 5)] + Association(runtime_types::common::prov::id::AssociationId), + #[codec(index = 6)] + Attribution(runtime_types::common::prov::id::AttributionId), + #[codec(index = 7)] + Delegation(runtime_types::common::prov::id::DelegationId), + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct DelegationId { + pub delegate: runtime_types::common::prov::id::ExternalId, + pub responsible: runtime_types::common::prov::id::ExternalId, + pub activity: + ::core::option::Option, + pub role: ::core::option::Option, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct DomaintypeId(pub runtime_types::common::prov::id::ExternalId); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct EntityId(pub runtime_types::common::prov::id::ExternalId); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ExternalId(pub ::std::string::String); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct NamespaceId { + pub external_id: runtime_types::common::prov::id::ExternalId, + pub uuid: [::core::primitive::u8; 16usize], + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Role(pub ::std::string::String); + } + + pub mod model { + use super::runtime_types; + + pub mod contradiction { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Contradiction { + pub id: runtime_types::common::prov::id::ChronicleIri, + pub namespace: runtime_types::common::prov::id::NamespaceId, + pub contradiction: ::std::vec::Vec, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum ContradictionDetail { + #[codec(index = 0)] + AttributeValueChange { + name: ::std::string::String, + value: runtime_types::common::attributes::Attribute, + attempted: runtime_types::common::attributes::Attribute, + }, + #[codec(index = 1)] + StartAlteration { + value: runtime_types::common::prov::operations::TimeWrapper, + attempted: runtime_types::common::prov::operations::TimeWrapper, + }, + #[codec(index = 2)] + EndAlteration { + value: runtime_types::common::prov::operations::TimeWrapper, + attempted: runtime_types::common::prov::operations::TimeWrapper, + }, + #[codec(index = 3)] + InvalidRange { + start: runtime_types::common::prov::operations::TimeWrapper, + end: runtime_types::common::prov::operations::TimeWrapper, + }, + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Activity { + pub id: runtime_types::common::prov::id::ActivityId, + pub namespace_id: runtime_types::common::prov::id::NamespaceId, + pub external_id: runtime_types::common::prov::id::ExternalId, + pub domaintype_id: + ::core::option::Option, + pub attributes: ::subxt::utils::KeyedVec< + ::std::string::String, + runtime_types::common::attributes::Attribute, + >, + pub started: ::core::option::Option< + runtime_types::common::prov::operations::TimeWrapper, + >, + pub ended: ::core::option::Option< + runtime_types::common::prov::operations::TimeWrapper, + >, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Agent { + pub id: runtime_types::common::prov::id::AgentId, + pub namespaceid: runtime_types::common::prov::id::NamespaceId, + pub external_id: runtime_types::common::prov::id::ExternalId, + pub domaintypeid: + ::core::option::Option, + pub attributes: ::subxt::utils::KeyedVec< + ::std::string::String, + runtime_types::common::attributes::Attribute, + >, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Association { + pub namespace_id: runtime_types::common::prov::id::NamespaceId, + pub id: runtime_types::common::prov::id::AssociationId, + pub agent_id: runtime_types::common::prov::id::AgentId, + pub activity_id: runtime_types::common::prov::id::ActivityId, + pub role: ::core::option::Option, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Attribution { + pub namespace_id: runtime_types::common::prov::id::NamespaceId, + pub id: runtime_types::common::prov::id::AttributionId, + pub agent_id: runtime_types::common::prov::id::AgentId, + pub entity_id: runtime_types::common::prov::id::EntityId, + pub role: ::core::option::Option, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ChronicleTransactionId(pub [::core::primitive::u8; 16usize]); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Delegation { + pub namespace_id: runtime_types::common::prov::id::NamespaceId, + pub id: runtime_types::common::prov::id::DelegationId, + pub delegate_id: runtime_types::common::prov::id::AgentId, + pub responsible_id: runtime_types::common::prov::id::AgentId, + pub activity_id: + ::core::option::Option, + pub role: ::core::option::Option, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Derivation { + pub generated_id: runtime_types::common::prov::id::EntityId, + pub used_id: runtime_types::common::prov::id::EntityId, + pub activity_id: + ::core::option::Option, + pub typ: runtime_types::common::prov::operations::DerivationType, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Entity { + pub id: runtime_types::common::prov::id::EntityId, + pub namespace_id: runtime_types::common::prov::id::NamespaceId, + pub external_id: runtime_types::common::prov::id::ExternalId, + pub domaintypeid: + ::core::option::Option, + pub attributes: ::subxt::utils::KeyedVec< + ::std::string::String, + runtime_types::common::attributes::Attribute, + >, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct GeneratedEntity { + pub entity_id: runtime_types::common::prov::id::EntityId, + pub generated_id: runtime_types::common::prov::id::ActivityId, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Generation { + pub activity_id: runtime_types::common::prov::id::ActivityId, + pub generated_id: runtime_types::common::prov::id::EntityId, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Namespace { + pub id: runtime_types::common::prov::id::NamespaceId, + pub uuid: [::core::primitive::u8; 16usize], + pub external_id: runtime_types::common::prov::id::ExternalId, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ProvModel { + pub namespaces: ::subxt::utils::KeyedVec< + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::model::Namespace, + >, + pub agents: ::subxt::utils::KeyedVec< + ( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::AgentId, + ), + runtime_types::common::prov::model::Agent, + >, + pub acted_on_behalf_of: ::subxt::utils::KeyedVec< + ( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::AgentId, + ), + ::std::vec::Vec, + >, + pub delegation: ::subxt::utils::KeyedVec< + ( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::AgentId, + ), + ::std::vec::Vec, + >, + pub entities: ::subxt::utils::KeyedVec< + ( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::EntityId, + ), + runtime_types::common::prov::model::Entity, + >, + pub derivation: ::subxt::utils::KeyedVec< + ( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::EntityId, + ), + ::std::vec::Vec, + >, + pub generation: ::subxt::utils::KeyedVec< + ( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::EntityId, + ), + ::std::vec::Vec, + >, + pub attribution: ::subxt::utils::KeyedVec< + ( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::EntityId, + ), + ::std::vec::Vec, + >, + pub activities: ::subxt::utils::KeyedVec< + ( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::ActivityId, + ), + runtime_types::common::prov::model::Activity, + >, + pub was_informed_by: ::subxt::utils::KeyedVec< + ( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::ActivityId, + ), + ::std::vec::Vec<( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::ActivityId, + )>, + >, + pub generated: ::subxt::utils::KeyedVec< + ( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::ActivityId, + ), + ::std::vec::Vec, + >, + pub association: ::subxt::utils::KeyedVec< + ( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::ActivityId, + ), + ::std::vec::Vec, + >, + pub usage: ::subxt::utils::KeyedVec< + ( + runtime_types::common::prov::id::NamespaceId, + runtime_types::common::prov::id::ActivityId, + ), + ::std::vec::Vec, + >, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Usage { + pub activity_id: runtime_types::common::prov::id::ActivityId, + pub entity_id: runtime_types::common::prov::id::EntityId, + } + } + + pub mod operations { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ActivityExists { + pub namespace: runtime_types::common::prov::id::NamespaceId, + pub external_id: runtime_types::common::prov::id::ExternalId, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ActivityUses { + pub namespace: runtime_types::common::prov::id::NamespaceId, + pub id: runtime_types::common::prov::id::EntityId, + pub activity: runtime_types::common::prov::id::ActivityId, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ActsOnBehalfOf { + pub id: runtime_types::common::prov::id::DelegationId, + pub role: ::core::option::Option, + pub activity_id: + ::core::option::Option, + pub responsible_id: runtime_types::common::prov::id::AgentId, + pub delegate_id: runtime_types::common::prov::id::AgentId, + pub namespace: runtime_types::common::prov::id::NamespaceId, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct AgentExists { + pub namespace: runtime_types::common::prov::id::NamespaceId, + pub external_id: runtime_types::common::prov::id::ExternalId, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum ChronicleOperation { + #[codec(index = 0)] + CreateNamespace(runtime_types::common::prov::operations::CreateNamespace), + #[codec(index = 1)] + AgentExists(runtime_types::common::prov::operations::AgentExists), + #[codec(index = 2)] + AgentActsOnBehalfOf( + runtime_types::common::prov::operations::ActsOnBehalfOf, + ), + #[codec(index = 3)] + ActivityExists(runtime_types::common::prov::operations::ActivityExists), + #[codec(index = 4)] + StartActivity(runtime_types::common::prov::operations::StartActivity), + #[codec(index = 5)] + EndActivity(runtime_types::common::prov::operations::EndActivity), + #[codec(index = 6)] + ActivityUses(runtime_types::common::prov::operations::ActivityUses), + #[codec(index = 7)] + EntityExists(runtime_types::common::prov::operations::EntityExists), + #[codec(index = 8)] + WasGeneratedBy(runtime_types::common::prov::operations::WasGeneratedBy), + #[codec(index = 9)] + EntityDerive(runtime_types::common::prov::operations::EntityDerive), + #[codec(index = 10)] + SetAttributes(runtime_types::common::prov::operations::SetAttributes), + #[codec(index = 11)] + WasAssociatedWith( + runtime_types::common::prov::operations::WasAssociatedWith, + ), + #[codec(index = 12)] + WasAttributedTo(runtime_types::common::prov::operations::WasAttributedTo), + #[codec(index = 13)] + WasInformedBy(runtime_types::common::prov::operations::WasInformedBy), + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct CreateNamespace { + pub id: runtime_types::common::prov::id::NamespaceId, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum DerivationType { + #[codec(index = 0)] + None, + #[codec(index = 1)] + Revision, + #[codec(index = 2)] + Quotation, + #[codec(index = 3)] + PrimarySource, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct EndActivity { + pub namespace: runtime_types::common::prov::id::NamespaceId, + pub id: runtime_types::common::prov::id::ActivityId, + pub time: runtime_types::common::prov::operations::TimeWrapper, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct EntityDerive { + pub namespace: runtime_types::common::prov::id::NamespaceId, + pub id: runtime_types::common::prov::id::EntityId, + pub used_id: runtime_types::common::prov::id::EntityId, + pub activity_id: + ::core::option::Option, + pub typ: runtime_types::common::prov::operations::DerivationType, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct EntityExists { + pub namespace: runtime_types::common::prov::id::NamespaceId, + pub external_id: runtime_types::common::prov::id::ExternalId, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum SetAttributes { + #[codec(index = 0)] + Entity { + namespace: runtime_types::common::prov::id::NamespaceId, + id: runtime_types::common::prov::id::EntityId, + attributes: runtime_types::common::attributes::Attributes, + }, + #[codec(index = 1)] + Agent { + namespace: runtime_types::common::prov::id::NamespaceId, + id: runtime_types::common::prov::id::AgentId, + attributes: runtime_types::common::attributes::Attributes, + }, + #[codec(index = 2)] + Activity { + namespace: runtime_types::common::prov::id::NamespaceId, + id: runtime_types::common::prov::id::ActivityId, + attributes: runtime_types::common::attributes::Attributes, + }, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct StartActivity { + pub namespace: runtime_types::common::prov::id::NamespaceId, + pub id: runtime_types::common::prov::id::ActivityId, + pub time: runtime_types::common::prov::operations::TimeWrapper, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct TimeWrapper(pub ::core::primitive::i64, pub ::core::primitive::u32); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct WasAssociatedWith { + pub id: runtime_types::common::prov::id::AssociationId, + pub role: ::core::option::Option, + pub namespace: runtime_types::common::prov::id::NamespaceId, + pub activity_id: runtime_types::common::prov::id::ActivityId, + pub agent_id: runtime_types::common::prov::id::AgentId, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct WasAttributedTo { + pub id: runtime_types::common::prov::id::AttributionId, + pub role: ::core::option::Option, + pub namespace: runtime_types::common::prov::id::NamespaceId, + pub entity_id: runtime_types::common::prov::id::EntityId, + pub agent_id: runtime_types::common::prov::id::AgentId, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct WasGeneratedBy { + pub namespace: runtime_types::common::prov::id::NamespaceId, + pub id: runtime_types::common::prov::id::EntityId, + pub activity: runtime_types::common::prov::id::ActivityId, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct WasInformedBy { + pub namespace: runtime_types::common::prov::id::NamespaceId, + pub activity: runtime_types::common::prov::id::ActivityId, + pub informing_activity: runtime_types::common::prov::id::ActivityId, + } + } + } + } + + pub mod finality_grandpa { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Equivocation<_0, _1, _2> { + pub round_number: ::core::primitive::u64, + pub identity: _0, + pub first: (_1, _2), + pub second: (_1, _2), + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Precommit<_0, _1> { + pub target_hash: _0, + pub target_number: _1, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Prevote<_0, _1> { + pub target_hash: _0, + pub target_number: _1, + } + } + + pub mod frame_support { + use super::runtime_types; + + pub mod dispatch { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum DispatchClass { + #[codec(index = 0)] + Normal, + #[codec(index = 1)] + Operational, + #[codec(index = 2)] + Mandatory, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct DispatchInfo { + pub weight: runtime_types::sp_weights::weight_v2::Weight, + pub class: runtime_types::frame_support::dispatch::DispatchClass, + pub pays_fee: runtime_types::frame_support::dispatch::Pays, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum Pays { + #[codec(index = 0)] + Yes, + #[codec(index = 1)] + No, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct PerDispatchClass<_0> { + pub normal: _0, + pub operational: _0, + pub mandatory: _0, + } + } + } + + pub mod frame_system { + use super::runtime_types; + + pub mod extensions { + use super::runtime_types; + + pub mod check_genesis { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct CheckGenesis; + } + + pub mod check_mortality { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct CheckMortality(pub runtime_types::sp_runtime::generic::era::Era); + } + + pub mod check_non_zero_sender { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct CheckNonZeroSender; + } + + pub mod check_spec_version { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct CheckSpecVersion; + } + + pub mod check_tx_version { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct CheckTxVersion; + } + + pub mod check_weight { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct CheckWeight; + } + } + + pub mod limits { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct BlockLength { + pub max: runtime_types::frame_support::dispatch::PerDispatchClass< + ::core::primitive::u32, + >, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct BlockWeights { + pub base_block: runtime_types::sp_weights::weight_v2::Weight, + pub max_block: runtime_types::sp_weights::weight_v2::Weight, + pub per_class: runtime_types::frame_support::dispatch::PerDispatchClass< + runtime_types::frame_system::limits::WeightsPerClass, + >, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct WeightsPerClass { + pub base_extrinsic: runtime_types::sp_weights::weight_v2::Weight, + pub max_extrinsic: + ::core::option::Option, + pub max_total: + ::core::option::Option, + pub reserved: + ::core::option::Option, + } + } + + pub mod pallet { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub enum Call { + #[codec(index = 0)] + #[doc = "See [`Pallet::remark`]."] + remark { remark: ::std::vec::Vec<::core::primitive::u8> }, + #[codec(index = 1)] + #[doc = "See [`Pallet::set_heap_pages`]."] + set_heap_pages { pages: ::core::primitive::u64 }, + #[codec(index = 2)] + #[doc = "See [`Pallet::set_code`]."] + set_code { code: ::std::vec::Vec<::core::primitive::u8> }, + #[codec(index = 3)] + #[doc = "See [`Pallet::set_code_without_checks`]."] + set_code_without_checks { code: ::std::vec::Vec<::core::primitive::u8> }, + #[codec(index = 4)] + #[doc = "See [`Pallet::set_storage`]."] + set_storage { + items: ::std::vec::Vec<( + ::std::vec::Vec<::core::primitive::u8>, + ::std::vec::Vec<::core::primitive::u8>, + )>, + }, + #[codec(index = 5)] + #[doc = "See [`Pallet::kill_storage`]."] + kill_storage { keys: ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>> }, + #[codec(index = 6)] + #[doc = "See [`Pallet::kill_prefix`]."] + kill_prefix { + prefix: ::std::vec::Vec<::core::primitive::u8>, + subkeys: ::core::primitive::u32, + }, + #[codec(index = 7)] + #[doc = "See [`Pallet::remark_with_event`]."] + remark_with_event { remark: ::std::vec::Vec<::core::primitive::u8> }, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "Error for the System pallet"] + pub enum Error { + #[codec(index = 0)] + #[doc = "The name of specification does not match between the current runtime"] + #[doc = "and the new runtime."] + InvalidSpecName, + #[codec(index = 1)] + #[doc = "The specification version is not allowed to decrease between the current runtime"] + #[doc = "and the new runtime."] + SpecVersionNeedsToIncrease, + #[codec(index = 2)] + #[doc = "Failed to extract the runtime version from the new runtime."] + #[doc = ""] + #[doc = "Either calling `Core_version` or decoding `RuntimeVersion` failed."] + FailedToExtractRuntimeVersion, + #[codec(index = 3)] + #[doc = "Suicide called when the account has non-default composite data."] + NonDefaultComposite, + #[codec(index = 4)] + #[doc = "There is a non-zero reference count preventing the account from being purged."] + NonZeroRefCount, + #[codec(index = 5)] + #[doc = "The origin filter prevent the call to be dispatched."] + CallFiltered, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "Event for the System pallet."] + pub enum Event { + #[codec(index = 0)] + #[doc = "An extrinsic completed successfully."] + ExtrinsicSuccess { + dispatch_info: runtime_types::frame_support::dispatch::DispatchInfo, + }, + #[codec(index = 1)] + #[doc = "An extrinsic failed."] + ExtrinsicFailed { + dispatch_error: runtime_types::sp_runtime::DispatchError, + dispatch_info: runtime_types::frame_support::dispatch::DispatchInfo, + }, + #[codec(index = 2)] + #[doc = "`:code` was updated."] + CodeUpdated, + #[codec(index = 3)] + #[doc = "A new account was created."] + NewAccount { account: ::subxt::utils::AccountId32 }, + #[codec(index = 4)] + #[doc = "An account was reaped."] + KilledAccount { account: ::subxt::utils::AccountId32 }, + #[codec(index = 5)] + #[doc = "On on-chain remark happened."] + Remarked { sender: ::subxt::utils::AccountId32, hash: ::subxt::utils::H256 }, + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct AccountInfo<_0, _1> { + pub nonce: _0, + pub consumers: ::core::primitive::u32, + pub providers: ::core::primitive::u32, + pub sufficients: ::core::primitive::u32, + pub data: _1, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct EventRecord<_0, _1> { + pub phase: runtime_types::frame_system::Phase, + pub event: _0, + pub topics: ::std::vec::Vec<_1>, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct LastRuntimeUpgradeInfo { + #[codec(compact)] + pub spec_version: ::core::primitive::u32, + pub spec_name: ::std::string::String, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum Phase { + #[codec(index = 0)] + ApplyExtrinsic(::core::primitive::u32), + #[codec(index = 1)] + Finalization, + #[codec(index = 2)] + Initialization, + } + } + + pub mod pallet_chronicle { + use super::runtime_types; + + pub mod pallet { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub enum Call { + #[codec(index = 0)] + #[doc = "See [`Pallet::apply`]."] + apply { operations: runtime_types::common::ledger::OperationSubmission }, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "The `Error` enum of this pallet."] + pub enum Error { + #[codec(index = 0)] + Address, + #[codec(index = 1)] + Contradiction, + #[codec(index = 2)] + Compaction, + #[codec(index = 3)] + Expansion, + #[codec(index = 4)] + Identity, + #[codec(index = 5)] + IRef, + #[codec(index = 6)] + NotAChronicleIri, + #[codec(index = 7)] + MissingId, + #[codec(index = 8)] + MissingProperty, + #[codec(index = 9)] + NotANode, + #[codec(index = 10)] + NotAnObject, + #[codec(index = 11)] + OpaExecutor, + #[codec(index = 12)] + SerdeJson, + #[codec(index = 13)] + SubmissionFormat, + #[codec(index = 14)] + Time, + #[codec(index = 15)] + Tokio, + #[codec(index = 16)] + Utf8, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "The `Event` enum of this pallet"] + pub enum Event { + #[codec(index = 0)] + Applied( + runtime_types::common::prov::model::ProvModel, + runtime_types::common::identity::SignedIdentity, + [::core::primitive::u8; 16usize], + ), + #[codec(index = 1)] + Contradiction( + runtime_types::common::prov::model::contradiction::Contradiction, + runtime_types::common::identity::SignedIdentity, + [::core::primitive::u8; 16usize], + ), + } + } + } + + pub mod pallet_grandpa { + use super::runtime_types; + + pub mod pallet { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub enum Call { + #[codec(index = 0)] + #[doc = "See [`Pallet::report_equivocation`]."] + report_equivocation { + equivocation_proof: ::std::boxed::Box< + runtime_types::sp_consensus_grandpa::EquivocationProof< + ::subxt::utils::H256, + ::core::primitive::u32, + >, + >, + key_owner_proof: runtime_types::sp_core::Void, + }, + #[codec(index = 1)] + #[doc = "See [`Pallet::report_equivocation_unsigned`]."] + report_equivocation_unsigned { + equivocation_proof: ::std::boxed::Box< + runtime_types::sp_consensus_grandpa::EquivocationProof< + ::subxt::utils::H256, + ::core::primitive::u32, + >, + >, + key_owner_proof: runtime_types::sp_core::Void, + }, + #[codec(index = 2)] + #[doc = "See [`Pallet::note_stalled`]."] + note_stalled { + delay: ::core::primitive::u32, + best_finalized_block_number: ::core::primitive::u32, + }, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "The `Error` enum of this pallet."] + pub enum Error { + #[codec(index = 0)] + #[doc = "Attempt to signal GRANDPA pause when the authority set isn't live"] + #[doc = "(either paused or already pending pause)."] + PauseFailed, + #[codec(index = 1)] + #[doc = "Attempt to signal GRANDPA resume when the authority set isn't paused"] + #[doc = "(either live or already pending resume)."] + ResumeFailed, + #[codec(index = 2)] + #[doc = "Attempt to signal GRANDPA change with one already pending."] + ChangePending, + #[codec(index = 3)] + #[doc = "Cannot signal forced change so soon after last."] + TooSoon, + #[codec(index = 4)] + #[doc = "A key ownership proof provided as part of an equivocation report is invalid."] + InvalidKeyOwnershipProof, + #[codec(index = 5)] + #[doc = "An equivocation proof provided as part of an equivocation report is invalid."] + InvalidEquivocationProof, + #[codec(index = 6)] + #[doc = "A given equivocation report is valid but already previously reported."] + DuplicateOffenceReport, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "The `Event` enum of this pallet"] + pub enum Event { + #[codec(index = 0)] + #[doc = "New authority set has been applied."] + NewAuthorities { + authority_set: ::std::vec::Vec<( + runtime_types::sp_consensus_grandpa::app::Public, + ::core::primitive::u64, + )>, + }, + #[codec(index = 1)] + #[doc = "Current authority set has been paused."] + Paused, + #[codec(index = 2)] + #[doc = "Current authority set has been resumed."] + Resumed, + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct StoredPendingChange<_0> { + pub scheduled_at: _0, + pub delay: _0, + pub next_authorities: + runtime_types::bounded_collections::weak_bounded_vec::WeakBoundedVec<( + runtime_types::sp_consensus_grandpa::app::Public, + ::core::primitive::u64, + )>, + pub forced: ::core::option::Option<_0>, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum StoredState<_0> { + #[codec(index = 0)] + Live, + #[codec(index = 1)] + PendingPause { scheduled_at: _0, delay: _0 }, + #[codec(index = 2)] + Paused, + #[codec(index = 3)] + PendingResume { scheduled_at: _0, delay: _0 }, + } + } + + pub mod pallet_opa { + use super::runtime_types; + + pub mod pallet { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub enum Call { + #[codec(index = 0)] + #[doc = "See [`Pallet::apply`]."] + apply { submission: runtime_types::common::opa::core::codec::OpaSubmissionV1 }, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "The `Error` enum of this pallet."] + pub enum Error { + #[codec(index = 0)] + OperationSignatureVerification, + #[codec(index = 1)] + InvalidSigningKey, + #[codec(index = 2)] + JsonSerialize, + #[codec(index = 3)] + InvalidOperation, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "The `Event` enum of this pallet"] + pub enum Event { + #[codec(index = 0)] + PolicyUpdate( + runtime_types::common::opa::core::codec::PolicyMetaV1, + runtime_types::common::prov::model::ChronicleTransactionId, + ), + #[codec(index = 1)] + KeyUpdate( + runtime_types::common::opa::core::codec::KeysV1, + runtime_types::common::prov::model::ChronicleTransactionId, + ), + } + } + } + + pub mod pallet_sudo { + use super::runtime_types; + + pub mod pallet { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub enum Call { + #[codec(index = 0)] + #[doc = "See [`Pallet::sudo`]."] + sudo { call: ::std::boxed::Box }, + #[codec(index = 1)] + #[doc = "See [`Pallet::sudo_unchecked_weight`]."] + sudo_unchecked_weight { + call: ::std::boxed::Box, + weight: runtime_types::sp_weights::weight_v2::Weight, + }, + #[codec(index = 2)] + #[doc = "See [`Pallet::set_key`]."] + set_key { new: ::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()> }, + #[codec(index = 3)] + #[doc = "See [`Pallet::sudo_as`]."] + sudo_as { + who: ::subxt::utils::MultiAddress<::subxt::utils::AccountId32, ()>, + call: ::std::boxed::Box, + }, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "Error for the Sudo pallet"] + pub enum Error { + #[codec(index = 0)] + #[doc = "Sender must be the Sudo account"] + RequireSudo, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "The `Event` enum of this pallet"] + pub enum Event { + #[codec(index = 0)] + #[doc = "A sudo call just took place."] + Sudid { + sudo_result: + ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>, + }, + #[codec(index = 1)] + #[doc = "The sudo key has been updated."] + KeyChanged { old_sudoer: ::core::option::Option<::subxt::utils::AccountId32> }, + #[codec(index = 2)] + #[doc = "A [sudo_as](Pallet::sudo_as) call just took place."] + SudoAsDone { + sudo_result: + ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>, + }, + } + } + } + + pub mod pallet_timestamp { + use super::runtime_types; + + pub mod pallet { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub enum Call { + #[codec(index = 0)] + #[doc = "See [`Pallet::set`]."] + set { + #[codec(compact)] + now: ::core::primitive::u64, + }, + } + } + } + + pub mod runtime_chronicle { + use super::runtime_types; + + pub mod no_nonce_fees { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct CheckNonce(#[codec(compact)] pub ::core::primitive::u32); + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Runtime; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum RuntimeCall { + #[codec(index = 0)] + System(runtime_types::frame_system::pallet::Call), + #[codec(index = 1)] + Timestamp(runtime_types::pallet_timestamp::pallet::Call), + #[codec(index = 3)] + Grandpa(runtime_types::pallet_grandpa::pallet::Call), + #[codec(index = 4)] + Sudo(runtime_types::pallet_sudo::pallet::Call), + #[codec(index = 5)] + Chronicle(runtime_types::pallet_chronicle::pallet::Call), + #[codec(index = 6)] + Opa(runtime_types::pallet_opa::pallet::Call), + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum RuntimeError { + #[codec(index = 0)] + System(runtime_types::frame_system::pallet::Error), + #[codec(index = 3)] + Grandpa(runtime_types::pallet_grandpa::pallet::Error), + #[codec(index = 4)] + Sudo(runtime_types::pallet_sudo::pallet::Error), + #[codec(index = 5)] + Chronicle(runtime_types::pallet_chronicle::pallet::Error), + #[codec(index = 6)] + Opa(runtime_types::pallet_opa::pallet::Error), + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum RuntimeEvent { + #[codec(index = 0)] + System(runtime_types::frame_system::pallet::Event), + #[codec(index = 3)] + Grandpa(runtime_types::pallet_grandpa::pallet::Event), + #[codec(index = 4)] + Sudo(runtime_types::pallet_sudo::pallet::Event), + #[codec(index = 5)] + Chronicle(runtime_types::pallet_chronicle::pallet::Event), + #[codec(index = 6)] + Opa(runtime_types::pallet_opa::pallet::Event), + } + } + + pub mod sp_arithmetic { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum ArithmeticError { + #[codec(index = 0)] + Underflow, + #[codec(index = 1)] + Overflow, + #[codec(index = 2)] + DivisionByZero, + } + } + + pub mod sp_consensus_aura { + use super::runtime_types; + + pub mod sr25519 { + use super::runtime_types; + + pub mod app_sr25519 { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Public(pub runtime_types::sp_core::sr25519::Public); + } + } + } + + pub mod sp_consensus_grandpa { + use super::runtime_types; + + pub mod app { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Public(pub runtime_types::sp_core::ed25519::Public); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Signature(pub runtime_types::sp_core::ed25519::Signature); + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum Equivocation<_0, _1> { + #[codec(index = 0)] + Prevote( + runtime_types::finality_grandpa::Equivocation< + runtime_types::sp_consensus_grandpa::app::Public, + runtime_types::finality_grandpa::Prevote<_0, _1>, + runtime_types::sp_consensus_grandpa::app::Signature, + >, + ), + #[codec(index = 1)] + Precommit( + runtime_types::finality_grandpa::Equivocation< + runtime_types::sp_consensus_grandpa::app::Public, + runtime_types::finality_grandpa::Precommit<_0, _1>, + runtime_types::sp_consensus_grandpa::app::Signature, + >, + ), + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct EquivocationProof<_0, _1> { + pub set_id: ::core::primitive::u64, + pub equivocation: runtime_types::sp_consensus_grandpa::Equivocation<_0, _1>, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct OpaqueKeyOwnershipProof(pub ::std::vec::Vec<::core::primitive::u8>); + } + + pub mod sp_consensus_slots { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::CompactAs, + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Slot(pub ::core::primitive::u64); + + #[derive( + ::subxt::ext::codec::CompactAs, + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct SlotDuration(pub ::core::primitive::u64); + } + + pub mod sp_core { + use super::runtime_types; + + pub mod crypto { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct KeyTypeId(pub [::core::primitive::u8; 4usize]); + } + + pub mod ecdsa { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Signature(pub [::core::primitive::u8; 65usize]); + } + + pub mod ed25519 { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Public(pub [::core::primitive::u8; 32usize]); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Signature(pub [::core::primitive::u8; 64usize]); + } + + pub mod sr25519 { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Public(pub [::core::primitive::u8; 32usize]); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Signature(pub [::core::primitive::u8; 64usize]); + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct OpaqueMetadata(pub ::std::vec::Vec<::core::primitive::u8>); + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum Void {} + } + + pub mod sp_inherents { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct CheckInherentsResult { + pub okay: ::core::primitive::bool, + pub fatal_error: ::core::primitive::bool, + pub errors: runtime_types::sp_inherents::InherentData, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct InherentData { + pub data: ::subxt::utils::KeyedVec< + [::core::primitive::u8; 8usize], + ::std::vec::Vec<::core::primitive::u8>, + >, + } + } + + pub mod sp_runtime { + use super::runtime_types; + + pub mod generic { + use super::runtime_types; + + pub mod block { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Block<_0, _1> { + pub header: _0, + pub extrinsics: ::std::vec::Vec<_1>, + } + } + + pub mod digest { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Digest { + pub logs: + ::std::vec::Vec, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum DigestItem { + #[codec(index = 6)] + PreRuntime( + [::core::primitive::u8; 4usize], + ::std::vec::Vec<::core::primitive::u8>, + ), + #[codec(index = 4)] + Consensus( + [::core::primitive::u8; 4usize], + ::std::vec::Vec<::core::primitive::u8>, + ), + #[codec(index = 5)] + Seal( + [::core::primitive::u8; 4usize], + ::std::vec::Vec<::core::primitive::u8>, + ), + #[codec(index = 0)] + Other(::std::vec::Vec<::core::primitive::u8>), + #[codec(index = 8)] + RuntimeEnvironmentUpdated, + } + } + + pub mod era { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum Era { + #[codec(index = 0)] + Immortal, + #[codec(index = 1)] + Mortal1(::core::primitive::u8), + #[codec(index = 2)] + Mortal2(::core::primitive::u8), + #[codec(index = 3)] + Mortal3(::core::primitive::u8), + #[codec(index = 4)] + Mortal4(::core::primitive::u8), + #[codec(index = 5)] + Mortal5(::core::primitive::u8), + #[codec(index = 6)] + Mortal6(::core::primitive::u8), + #[codec(index = 7)] + Mortal7(::core::primitive::u8), + #[codec(index = 8)] + Mortal8(::core::primitive::u8), + #[codec(index = 9)] + Mortal9(::core::primitive::u8), + #[codec(index = 10)] + Mortal10(::core::primitive::u8), + #[codec(index = 11)] + Mortal11(::core::primitive::u8), + #[codec(index = 12)] + Mortal12(::core::primitive::u8), + #[codec(index = 13)] + Mortal13(::core::primitive::u8), + #[codec(index = 14)] + Mortal14(::core::primitive::u8), + #[codec(index = 15)] + Mortal15(::core::primitive::u8), + #[codec(index = 16)] + Mortal16(::core::primitive::u8), + #[codec(index = 17)] + Mortal17(::core::primitive::u8), + #[codec(index = 18)] + Mortal18(::core::primitive::u8), + #[codec(index = 19)] + Mortal19(::core::primitive::u8), + #[codec(index = 20)] + Mortal20(::core::primitive::u8), + #[codec(index = 21)] + Mortal21(::core::primitive::u8), + #[codec(index = 22)] + Mortal22(::core::primitive::u8), + #[codec(index = 23)] + Mortal23(::core::primitive::u8), + #[codec(index = 24)] + Mortal24(::core::primitive::u8), + #[codec(index = 25)] + Mortal25(::core::primitive::u8), + #[codec(index = 26)] + Mortal26(::core::primitive::u8), + #[codec(index = 27)] + Mortal27(::core::primitive::u8), + #[codec(index = 28)] + Mortal28(::core::primitive::u8), + #[codec(index = 29)] + Mortal29(::core::primitive::u8), + #[codec(index = 30)] + Mortal30(::core::primitive::u8), + #[codec(index = 31)] + Mortal31(::core::primitive::u8), + #[codec(index = 32)] + Mortal32(::core::primitive::u8), + #[codec(index = 33)] + Mortal33(::core::primitive::u8), + #[codec(index = 34)] + Mortal34(::core::primitive::u8), + #[codec(index = 35)] + Mortal35(::core::primitive::u8), + #[codec(index = 36)] + Mortal36(::core::primitive::u8), + #[codec(index = 37)] + Mortal37(::core::primitive::u8), + #[codec(index = 38)] + Mortal38(::core::primitive::u8), + #[codec(index = 39)] + Mortal39(::core::primitive::u8), + #[codec(index = 40)] + Mortal40(::core::primitive::u8), + #[codec(index = 41)] + Mortal41(::core::primitive::u8), + #[codec(index = 42)] + Mortal42(::core::primitive::u8), + #[codec(index = 43)] + Mortal43(::core::primitive::u8), + #[codec(index = 44)] + Mortal44(::core::primitive::u8), + #[codec(index = 45)] + Mortal45(::core::primitive::u8), + #[codec(index = 46)] + Mortal46(::core::primitive::u8), + #[codec(index = 47)] + Mortal47(::core::primitive::u8), + #[codec(index = 48)] + Mortal48(::core::primitive::u8), + #[codec(index = 49)] + Mortal49(::core::primitive::u8), + #[codec(index = 50)] + Mortal50(::core::primitive::u8), + #[codec(index = 51)] + Mortal51(::core::primitive::u8), + #[codec(index = 52)] + Mortal52(::core::primitive::u8), + #[codec(index = 53)] + Mortal53(::core::primitive::u8), + #[codec(index = 54)] + Mortal54(::core::primitive::u8), + #[codec(index = 55)] + Mortal55(::core::primitive::u8), + #[codec(index = 56)] + Mortal56(::core::primitive::u8), + #[codec(index = 57)] + Mortal57(::core::primitive::u8), + #[codec(index = 58)] + Mortal58(::core::primitive::u8), + #[codec(index = 59)] + Mortal59(::core::primitive::u8), + #[codec(index = 60)] + Mortal60(::core::primitive::u8), + #[codec(index = 61)] + Mortal61(::core::primitive::u8), + #[codec(index = 62)] + Mortal62(::core::primitive::u8), + #[codec(index = 63)] + Mortal63(::core::primitive::u8), + #[codec(index = 64)] + Mortal64(::core::primitive::u8), + #[codec(index = 65)] + Mortal65(::core::primitive::u8), + #[codec(index = 66)] + Mortal66(::core::primitive::u8), + #[codec(index = 67)] + Mortal67(::core::primitive::u8), + #[codec(index = 68)] + Mortal68(::core::primitive::u8), + #[codec(index = 69)] + Mortal69(::core::primitive::u8), + #[codec(index = 70)] + Mortal70(::core::primitive::u8), + #[codec(index = 71)] + Mortal71(::core::primitive::u8), + #[codec(index = 72)] + Mortal72(::core::primitive::u8), + #[codec(index = 73)] + Mortal73(::core::primitive::u8), + #[codec(index = 74)] + Mortal74(::core::primitive::u8), + #[codec(index = 75)] + Mortal75(::core::primitive::u8), + #[codec(index = 76)] + Mortal76(::core::primitive::u8), + #[codec(index = 77)] + Mortal77(::core::primitive::u8), + #[codec(index = 78)] + Mortal78(::core::primitive::u8), + #[codec(index = 79)] + Mortal79(::core::primitive::u8), + #[codec(index = 80)] + Mortal80(::core::primitive::u8), + #[codec(index = 81)] + Mortal81(::core::primitive::u8), + #[codec(index = 82)] + Mortal82(::core::primitive::u8), + #[codec(index = 83)] + Mortal83(::core::primitive::u8), + #[codec(index = 84)] + Mortal84(::core::primitive::u8), + #[codec(index = 85)] + Mortal85(::core::primitive::u8), + #[codec(index = 86)] + Mortal86(::core::primitive::u8), + #[codec(index = 87)] + Mortal87(::core::primitive::u8), + #[codec(index = 88)] + Mortal88(::core::primitive::u8), + #[codec(index = 89)] + Mortal89(::core::primitive::u8), + #[codec(index = 90)] + Mortal90(::core::primitive::u8), + #[codec(index = 91)] + Mortal91(::core::primitive::u8), + #[codec(index = 92)] + Mortal92(::core::primitive::u8), + #[codec(index = 93)] + Mortal93(::core::primitive::u8), + #[codec(index = 94)] + Mortal94(::core::primitive::u8), + #[codec(index = 95)] + Mortal95(::core::primitive::u8), + #[codec(index = 96)] + Mortal96(::core::primitive::u8), + #[codec(index = 97)] + Mortal97(::core::primitive::u8), + #[codec(index = 98)] + Mortal98(::core::primitive::u8), + #[codec(index = 99)] + Mortal99(::core::primitive::u8), + #[codec(index = 100)] + Mortal100(::core::primitive::u8), + #[codec(index = 101)] + Mortal101(::core::primitive::u8), + #[codec(index = 102)] + Mortal102(::core::primitive::u8), + #[codec(index = 103)] + Mortal103(::core::primitive::u8), + #[codec(index = 104)] + Mortal104(::core::primitive::u8), + #[codec(index = 105)] + Mortal105(::core::primitive::u8), + #[codec(index = 106)] + Mortal106(::core::primitive::u8), + #[codec(index = 107)] + Mortal107(::core::primitive::u8), + #[codec(index = 108)] + Mortal108(::core::primitive::u8), + #[codec(index = 109)] + Mortal109(::core::primitive::u8), + #[codec(index = 110)] + Mortal110(::core::primitive::u8), + #[codec(index = 111)] + Mortal111(::core::primitive::u8), + #[codec(index = 112)] + Mortal112(::core::primitive::u8), + #[codec(index = 113)] + Mortal113(::core::primitive::u8), + #[codec(index = 114)] + Mortal114(::core::primitive::u8), + #[codec(index = 115)] + Mortal115(::core::primitive::u8), + #[codec(index = 116)] + Mortal116(::core::primitive::u8), + #[codec(index = 117)] + Mortal117(::core::primitive::u8), + #[codec(index = 118)] + Mortal118(::core::primitive::u8), + #[codec(index = 119)] + Mortal119(::core::primitive::u8), + #[codec(index = 120)] + Mortal120(::core::primitive::u8), + #[codec(index = 121)] + Mortal121(::core::primitive::u8), + #[codec(index = 122)] + Mortal122(::core::primitive::u8), + #[codec(index = 123)] + Mortal123(::core::primitive::u8), + #[codec(index = 124)] + Mortal124(::core::primitive::u8), + #[codec(index = 125)] + Mortal125(::core::primitive::u8), + #[codec(index = 126)] + Mortal126(::core::primitive::u8), + #[codec(index = 127)] + Mortal127(::core::primitive::u8), + #[codec(index = 128)] + Mortal128(::core::primitive::u8), + #[codec(index = 129)] + Mortal129(::core::primitive::u8), + #[codec(index = 130)] + Mortal130(::core::primitive::u8), + #[codec(index = 131)] + Mortal131(::core::primitive::u8), + #[codec(index = 132)] + Mortal132(::core::primitive::u8), + #[codec(index = 133)] + Mortal133(::core::primitive::u8), + #[codec(index = 134)] + Mortal134(::core::primitive::u8), + #[codec(index = 135)] + Mortal135(::core::primitive::u8), + #[codec(index = 136)] + Mortal136(::core::primitive::u8), + #[codec(index = 137)] + Mortal137(::core::primitive::u8), + #[codec(index = 138)] + Mortal138(::core::primitive::u8), + #[codec(index = 139)] + Mortal139(::core::primitive::u8), + #[codec(index = 140)] + Mortal140(::core::primitive::u8), + #[codec(index = 141)] + Mortal141(::core::primitive::u8), + #[codec(index = 142)] + Mortal142(::core::primitive::u8), + #[codec(index = 143)] + Mortal143(::core::primitive::u8), + #[codec(index = 144)] + Mortal144(::core::primitive::u8), + #[codec(index = 145)] + Mortal145(::core::primitive::u8), + #[codec(index = 146)] + Mortal146(::core::primitive::u8), + #[codec(index = 147)] + Mortal147(::core::primitive::u8), + #[codec(index = 148)] + Mortal148(::core::primitive::u8), + #[codec(index = 149)] + Mortal149(::core::primitive::u8), + #[codec(index = 150)] + Mortal150(::core::primitive::u8), + #[codec(index = 151)] + Mortal151(::core::primitive::u8), + #[codec(index = 152)] + Mortal152(::core::primitive::u8), + #[codec(index = 153)] + Mortal153(::core::primitive::u8), + #[codec(index = 154)] + Mortal154(::core::primitive::u8), + #[codec(index = 155)] + Mortal155(::core::primitive::u8), + #[codec(index = 156)] + Mortal156(::core::primitive::u8), + #[codec(index = 157)] + Mortal157(::core::primitive::u8), + #[codec(index = 158)] + Mortal158(::core::primitive::u8), + #[codec(index = 159)] + Mortal159(::core::primitive::u8), + #[codec(index = 160)] + Mortal160(::core::primitive::u8), + #[codec(index = 161)] + Mortal161(::core::primitive::u8), + #[codec(index = 162)] + Mortal162(::core::primitive::u8), + #[codec(index = 163)] + Mortal163(::core::primitive::u8), + #[codec(index = 164)] + Mortal164(::core::primitive::u8), + #[codec(index = 165)] + Mortal165(::core::primitive::u8), + #[codec(index = 166)] + Mortal166(::core::primitive::u8), + #[codec(index = 167)] + Mortal167(::core::primitive::u8), + #[codec(index = 168)] + Mortal168(::core::primitive::u8), + #[codec(index = 169)] + Mortal169(::core::primitive::u8), + #[codec(index = 170)] + Mortal170(::core::primitive::u8), + #[codec(index = 171)] + Mortal171(::core::primitive::u8), + #[codec(index = 172)] + Mortal172(::core::primitive::u8), + #[codec(index = 173)] + Mortal173(::core::primitive::u8), + #[codec(index = 174)] + Mortal174(::core::primitive::u8), + #[codec(index = 175)] + Mortal175(::core::primitive::u8), + #[codec(index = 176)] + Mortal176(::core::primitive::u8), + #[codec(index = 177)] + Mortal177(::core::primitive::u8), + #[codec(index = 178)] + Mortal178(::core::primitive::u8), + #[codec(index = 179)] + Mortal179(::core::primitive::u8), + #[codec(index = 180)] + Mortal180(::core::primitive::u8), + #[codec(index = 181)] + Mortal181(::core::primitive::u8), + #[codec(index = 182)] + Mortal182(::core::primitive::u8), + #[codec(index = 183)] + Mortal183(::core::primitive::u8), + #[codec(index = 184)] + Mortal184(::core::primitive::u8), + #[codec(index = 185)] + Mortal185(::core::primitive::u8), + #[codec(index = 186)] + Mortal186(::core::primitive::u8), + #[codec(index = 187)] + Mortal187(::core::primitive::u8), + #[codec(index = 188)] + Mortal188(::core::primitive::u8), + #[codec(index = 189)] + Mortal189(::core::primitive::u8), + #[codec(index = 190)] + Mortal190(::core::primitive::u8), + #[codec(index = 191)] + Mortal191(::core::primitive::u8), + #[codec(index = 192)] + Mortal192(::core::primitive::u8), + #[codec(index = 193)] + Mortal193(::core::primitive::u8), + #[codec(index = 194)] + Mortal194(::core::primitive::u8), + #[codec(index = 195)] + Mortal195(::core::primitive::u8), + #[codec(index = 196)] + Mortal196(::core::primitive::u8), + #[codec(index = 197)] + Mortal197(::core::primitive::u8), + #[codec(index = 198)] + Mortal198(::core::primitive::u8), + #[codec(index = 199)] + Mortal199(::core::primitive::u8), + #[codec(index = 200)] + Mortal200(::core::primitive::u8), + #[codec(index = 201)] + Mortal201(::core::primitive::u8), + #[codec(index = 202)] + Mortal202(::core::primitive::u8), + #[codec(index = 203)] + Mortal203(::core::primitive::u8), + #[codec(index = 204)] + Mortal204(::core::primitive::u8), + #[codec(index = 205)] + Mortal205(::core::primitive::u8), + #[codec(index = 206)] + Mortal206(::core::primitive::u8), + #[codec(index = 207)] + Mortal207(::core::primitive::u8), + #[codec(index = 208)] + Mortal208(::core::primitive::u8), + #[codec(index = 209)] + Mortal209(::core::primitive::u8), + #[codec(index = 210)] + Mortal210(::core::primitive::u8), + #[codec(index = 211)] + Mortal211(::core::primitive::u8), + #[codec(index = 212)] + Mortal212(::core::primitive::u8), + #[codec(index = 213)] + Mortal213(::core::primitive::u8), + #[codec(index = 214)] + Mortal214(::core::primitive::u8), + #[codec(index = 215)] + Mortal215(::core::primitive::u8), + #[codec(index = 216)] + Mortal216(::core::primitive::u8), + #[codec(index = 217)] + Mortal217(::core::primitive::u8), + #[codec(index = 218)] + Mortal218(::core::primitive::u8), + #[codec(index = 219)] + Mortal219(::core::primitive::u8), + #[codec(index = 220)] + Mortal220(::core::primitive::u8), + #[codec(index = 221)] + Mortal221(::core::primitive::u8), + #[codec(index = 222)] + Mortal222(::core::primitive::u8), + #[codec(index = 223)] + Mortal223(::core::primitive::u8), + #[codec(index = 224)] + Mortal224(::core::primitive::u8), + #[codec(index = 225)] + Mortal225(::core::primitive::u8), + #[codec(index = 226)] + Mortal226(::core::primitive::u8), + #[codec(index = 227)] + Mortal227(::core::primitive::u8), + #[codec(index = 228)] + Mortal228(::core::primitive::u8), + #[codec(index = 229)] + Mortal229(::core::primitive::u8), + #[codec(index = 230)] + Mortal230(::core::primitive::u8), + #[codec(index = 231)] + Mortal231(::core::primitive::u8), + #[codec(index = 232)] + Mortal232(::core::primitive::u8), + #[codec(index = 233)] + Mortal233(::core::primitive::u8), + #[codec(index = 234)] + Mortal234(::core::primitive::u8), + #[codec(index = 235)] + Mortal235(::core::primitive::u8), + #[codec(index = 236)] + Mortal236(::core::primitive::u8), + #[codec(index = 237)] + Mortal237(::core::primitive::u8), + #[codec(index = 238)] + Mortal238(::core::primitive::u8), + #[codec(index = 239)] + Mortal239(::core::primitive::u8), + #[codec(index = 240)] + Mortal240(::core::primitive::u8), + #[codec(index = 241)] + Mortal241(::core::primitive::u8), + #[codec(index = 242)] + Mortal242(::core::primitive::u8), + #[codec(index = 243)] + Mortal243(::core::primitive::u8), + #[codec(index = 244)] + Mortal244(::core::primitive::u8), + #[codec(index = 245)] + Mortal245(::core::primitive::u8), + #[codec(index = 246)] + Mortal246(::core::primitive::u8), + #[codec(index = 247)] + Mortal247(::core::primitive::u8), + #[codec(index = 248)] + Mortal248(::core::primitive::u8), + #[codec(index = 249)] + Mortal249(::core::primitive::u8), + #[codec(index = 250)] + Mortal250(::core::primitive::u8), + #[codec(index = 251)] + Mortal251(::core::primitive::u8), + #[codec(index = 252)] + Mortal252(::core::primitive::u8), + #[codec(index = 253)] + Mortal253(::core::primitive::u8), + #[codec(index = 254)] + Mortal254(::core::primitive::u8), + #[codec(index = 255)] + Mortal255(::core::primitive::u8), + } + } + + pub mod header { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Header<_0> { + pub parent_hash: ::subxt::utils::H256, + #[codec(compact)] + pub number: _0, + pub state_root: ::subxt::utils::H256, + pub extrinsics_root: ::subxt::utils::H256, + pub digest: runtime_types::sp_runtime::generic::digest::Digest, + } + } + } + + pub mod transaction_validity { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum InvalidTransaction { + #[codec(index = 0)] + Call, + #[codec(index = 1)] + Payment, + #[codec(index = 2)] + Future, + #[codec(index = 3)] + Stale, + #[codec(index = 4)] + BadProof, + #[codec(index = 5)] + AncientBirthBlock, + #[codec(index = 6)] + ExhaustsResources, + #[codec(index = 7)] + Custom(::core::primitive::u8), + #[codec(index = 8)] + BadMandatory, + #[codec(index = 9)] + MandatoryValidation, + #[codec(index = 10)] + BadSigner, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum TransactionSource { + #[codec(index = 0)] + InBlock, + #[codec(index = 1)] + Local, + #[codec(index = 2)] + External, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum TransactionValidityError { + #[codec(index = 0)] + Invalid(runtime_types::sp_runtime::transaction_validity::InvalidTransaction), + #[codec(index = 1)] + Unknown(runtime_types::sp_runtime::transaction_validity::UnknownTransaction), + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum UnknownTransaction { + #[codec(index = 0)] + CannotLookup, + #[codec(index = 1)] + NoUnsignedValidator, + #[codec(index = 2)] + Custom(::core::primitive::u8), + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ValidTransaction { + pub priority: ::core::primitive::u64, + pub requires: ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>>, + pub provides: ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>>, + pub longevity: ::core::primitive::u64, + pub propagate: ::core::primitive::bool, + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum DispatchError { + #[codec(index = 0)] + Other, + #[codec(index = 1)] + CannotLookup, + #[codec(index = 2)] + BadOrigin, + #[codec(index = 3)] + Module(runtime_types::sp_runtime::ModuleError), + #[codec(index = 4)] + ConsumerRemaining, + #[codec(index = 5)] + NoProviders, + #[codec(index = 6)] + TooManyConsumers, + #[codec(index = 7)] + Token(runtime_types::sp_runtime::TokenError), + #[codec(index = 8)] + Arithmetic(runtime_types::sp_arithmetic::ArithmeticError), + #[codec(index = 9)] + Transactional(runtime_types::sp_runtime::TransactionalError), + #[codec(index = 10)] + Exhausted, + #[codec(index = 11)] + Corruption, + #[codec(index = 12)] + Unavailable, + #[codec(index = 13)] + RootNotAllowed, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct ModuleError { + pub index: ::core::primitive::u8, + pub error: [::core::primitive::u8; 4usize], + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum MultiSignature { + #[codec(index = 0)] + Ed25519(runtime_types::sp_core::ed25519::Signature), + #[codec(index = 1)] + Sr25519(runtime_types::sp_core::sr25519::Signature), + #[codec(index = 2)] + Ecdsa(runtime_types::sp_core::ecdsa::Signature), + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum TokenError { + #[codec(index = 0)] + FundsUnavailable, + #[codec(index = 1)] + OnlyProvider, + #[codec(index = 2)] + BelowMinimum, + #[codec(index = 3)] + CannotCreate, + #[codec(index = 4)] + UnknownAsset, + #[codec(index = 5)] + Frozen, + #[codec(index = 6)] + Unsupported, + #[codec(index = 7)] + CannotCreateHold, + #[codec(index = 8)] + NotExpendable, + #[codec(index = 9)] + Blocked, + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub enum TransactionalError { + #[codec(index = 0)] + LimitReached, + #[codec(index = 1)] + NoLayer, + } + } + + pub mod sp_version { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct RuntimeVersion { + pub spec_name: ::std::string::String, + pub impl_name: ::std::string::String, + pub authoring_version: ::core::primitive::u32, + pub spec_version: ::core::primitive::u32, + pub impl_version: ::core::primitive::u32, + pub apis: + ::std::vec::Vec<([::core::primitive::u8; 8usize], ::core::primitive::u32)>, + pub transaction_version: ::core::primitive::u32, + pub state_version: ::core::primitive::u8, + } + } + + pub mod sp_weights { + use super::runtime_types; + + pub mod weight_v2 { + use super::runtime_types; + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct Weight { + #[codec(compact)] + pub ref_time: ::core::primitive::u64, + #[codec(compact)] + pub proof_size: ::core::primitive::u64, + } + } + + #[derive( + ::subxt::ext::codec::Decode, + ::subxt::ext::codec::Encode, + ::subxt::ext::scale_decode::DecodeAsType, + ::subxt::ext::scale_encode::EncodeAsType, + Debug, + )] + #[codec(crate =::subxt::ext::codec)] + #[decode_as_type(crate_path = ":: subxt :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: scale_encode")] + pub struct RuntimeDbWeight { + pub read: ::core::primitive::u64, + pub write: ::core::primitive::u64, + } + } + } } diff --git a/crates/embedded-substrate/src/lib.rs b/crates/embedded-substrate/src/lib.rs index fc1b02bb4..2ec3f8443 100644 --- a/crates/embedded-substrate/src/lib.rs +++ b/crates/embedded-substrate/src/lib.rs @@ -3,31 +3,31 @@ use protocol_substrate::SubxtClientError; use protocol_substrate_chronicle::ChronicleSubstrateClient; use sc_cli::{print_node_infos, CliConfiguration, Signals, SubstrateCli}; use subxt::{ - config::ExtrinsicParams, - ext::futures::{pin_mut, FutureExt}, - utils::{AccountId32, MultiAddress, MultiSignature}, + config::ExtrinsicParams, + ext::futures::{pin_mut, FutureExt}, + utils::{AccountId32, MultiAddress, MultiSignature}, }; use tempfile::TempDir; use thiserror::Error; use tokio::{ - select, - sync::oneshot::{channel, Sender}, + select, + sync::oneshot::{channel, Sender}, }; use lazy_static::lazy_static; use std::{ - collections::BTreeMap, - sync::{Arc, Mutex}, - time::Duration, + collections::BTreeMap, + sync::{Arc, Mutex}, + time::Duration, }; use tracing::info; #[derive(Debug, Error)] pub enum Error { - #[error("Substrate invocation error: {source}")] - Cli { source: anyhow::Error }, - #[error("No free ports")] - NoFreePorts, + #[error("Substrate invocation error: {source}")] + Cli { source: anyhow::Error }, + #[error("No free ports")] + NoFreePorts, } // Substrate initialization is costly and includes log configuration, so we need to keep and reuse @@ -38,311 +38,312 @@ lazy_static! { } pub struct EmbeddedSubstrate { - shutdown: Option>, - _state: TempDir, - rpc_port: u16, + shutdown: Option>, + _state: TempDir, + rpc_port: u16, } impl EmbeddedSubstrate { - pub async fn connect_chronicle( - &self, - ) -> Result, SubxtClientError> - where - C: subxt::Config< - Hash = subxt::utils::H256, - Address = MultiAddress, - AccountId = AccountId32, - Signature = MultiSignature, - >, - >::OtherParams: Default, - { - ChronicleSubstrateClient::::connect(format!("ws://127.0.0.1:{}", self.rpc_port)).await - } - - pub fn port(&self) -> u16 { - self.rpc_port - } + pub async fn connect_chronicle( + &self, + ) -> Result, SubxtClientError> + where + C: subxt::Config< + Hash=subxt::utils::H256, + Address=MultiAddress, + AccountId=AccountId32, + Signature=MultiSignature, + >, + >::OtherParams: Default, + { + ChronicleSubstrateClient::::connect(format!("ws://127.0.0.1:{}", self.rpc_port)).await + } + + pub fn port(&self) -> u16 { + self.rpc_port + } } impl Drop for EmbeddedSubstrate { - fn drop(&mut self) { - if let Some(shutdown) = self.shutdown.take() { - if let Err(e) = shutdown.send(()) { - tracing::error!("Failed to send shutdown signal: {:?}", e); - } - } else { - tracing::warn!("Shutdown signal was already taken"); - } - } + fn drop(&mut self) { + if let Some(shutdown) = self.shutdown.take() { + if let Err(e) = shutdown.send(()) { + tracing::error!("Failed to send shutdown signal: {:?}", e); + } + } else { + tracing::warn!("Shutdown signal was already taken"); + } + } } pub async fn shared_dev_node_rpc_on_arbitrary_port() -> Result, Error> { - shared_dev_node_rpc_on_port( - portpicker::pick_unused_port().ok_or_else(|| Error::NoFreePorts)?, - false, - ) - .await + shared_dev_node_rpc_on_port( + portpicker::pick_unused_port().ok_or_else(|| Error::NoFreePorts)?, + false, + ) + .await } + // Utilize the CLI run command to bring up a substrate-chronicle dev mode node with a new runtime // Utilize the CLI run command to bring up a substrate-chronicle dev mode node with a new runtime // thread. Execute node until receipt of a drop channel message or signal pub async fn shared_dev_node_rpc_on_port( - port: u16, - configure_logging: bool, + port: u16, + configure_logging: bool, ) -> Result, Error> { - let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap(); - let handle = rt.handle().clone(); - - if let Some(substrate_instance) = SUBSTRATE_INSTANCES.lock().unwrap().get(&port) { - return Ok(substrate_instance.clone()); - } - - let (live_tx, live_rx) = channel::<()>(); - let (tx, rx) = channel(); - let tmp_dir = tempfile::tempdir().unwrap(); - let tmp_path = format!("{}", tmp_dir.path().to_string_lossy()); - - std::thread::spawn(move || { - let cli = Cli::from_iter([ - "--chain dev", - "--force-authoring", - "--alice", - &*format!("--rpc-port={}", port), - "--rpc-cors=all", - &*format!("-d{}", tmp_path), - ]); - - let signals = handle - .block_on(async { Signals::capture() }) - .map_err(|e| tracing::error!("{}", e)) - .unwrap(); - - let config = cli - .create_configuration(&cli.run, handle.clone()) - .map_err(|e| tracing::error!("{}", e)) - .unwrap(); - - print_node_infos::(&config); - - if configure_logging { - cli.run - .init( - &"https://chronicle.works".to_owned(), - &"2.0.dev".to_owned(), - |_, _| {}, - &config, - ) - .unwrap(); - } - - let mut task_manager = handle - .block_on(async move { service::new_full(config).map_err(sc_cli::Error::Service) }) - .map_err(|e| tracing::error!("{}", e)) - .unwrap(); - - live_tx.send(()).unwrap(); - - let task_manager = handle.block_on(async move { - let signal_exit = signals.future().fuse(); - let task_exit = task_manager.future().fuse(); - let drop_exit = async move { - let _ = rx.await; - tracing::info!("Shutdown message"); - }; - - pin_mut!(signal_exit, drop_exit); - - select! { + let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap(); + let handle = rt.handle().clone(); + + if let Some(substrate_instance) = SUBSTRATE_INSTANCES.lock().unwrap().get(&port) { + return Ok(substrate_instance.clone()); + } + + let (live_tx, live_rx) = channel::<()>(); + let (tx, rx) = channel(); + let tmp_dir = tempfile::tempdir().unwrap(); + let tmp_path = format!("{}", tmp_dir.path().to_string_lossy()); + + std::thread::spawn(move || { + let cli = Cli::from_iter([ + "--chain dev", + "--force-authoring", + "--alice", + &*format!("--rpc-port={}", port), + "--rpc-cors=all", + &*format!("-d{}", tmp_path), + ]); + + let signals = handle + .block_on(async { Signals::capture() }) + .map_err(|e| tracing::error!("{}", e)) + .unwrap(); + + let config = cli + .create_configuration(&cli.run, handle.clone()) + .map_err(|e| tracing::error!("{}", e)) + .unwrap(); + + print_node_infos::(&config); + + if configure_logging { + cli.run + .init( + &"https://chronicle.works".to_owned(), + &"2.0.dev".to_owned(), + |_, _| {}, + &config, + ) + .unwrap(); + } + + let mut task_manager = handle + .block_on(async move { service::new_full(config).map_err(sc_cli::Error::Service) }) + .map_err(|e| tracing::error!("{}", e)) + .unwrap(); + + live_tx.send(()).unwrap(); + + let task_manager = handle.block_on(async move { + let signal_exit = signals.future().fuse(); + let task_exit = task_manager.future().fuse(); + let drop_exit = async move { + let _ = rx.await; + tracing::info!("Shutdown message"); + }; + + pin_mut!(signal_exit, drop_exit); + + select! { _ = signal_exit => {}, _ = drop_exit => {}, _ = task_exit => {}, } - task_manager - }); + task_manager + }); - let task_registry = task_manager.into_task_registry(); - let shutdown_timeout = Duration::from_secs(60); - rt.shutdown_timeout(shutdown_timeout); + let task_registry = task_manager.into_task_registry(); + let shutdown_timeout = Duration::from_secs(60); + rt.shutdown_timeout(shutdown_timeout); - let running_tasks = task_registry.running_tasks(); + let running_tasks = task_registry.running_tasks(); - if !running_tasks.is_empty() { - tracing::error!("Detected running(potentially stalled) tasks on shutdown:"); - running_tasks.iter().for_each(|(task, count)| { - let instances_desc = - if *count > 1 { format!("with {} instances ", count) } else { "".to_string() }; + if !running_tasks.is_empty() { + tracing::error!("Detected running(potentially stalled) tasks on shutdown:"); + running_tasks.iter().for_each(|(task, count)| { + let instances_desc = + if *count > 1 { format!("with {} instances ", count) } else { "".to_string() }; - if task.is_default_group() { - tracing::error!( + if task.is_default_group() { + tracing::error!( "Task \"{}\" was still running {}after waiting {} seconds to finish.", task.name, instances_desc, 60 ); - } else { - tracing::error!( + } else { + tracing::error!( "Task \"{}\" (Group: {}) was still running {}after waiting {} seconds to finish.", task.name, task.group, instances_desc, 60 ); - } - }); - } + } + }); + } - info!("Shut down embedded substrate instance on port {}", port); - }); + info!("Shut down embedded substrate instance on port {}", port); + }); - tracing::info!("Await substrate boot"); - let _ = live_rx.await; - tracing::info!("Substrate booted"); + tracing::info!("Await substrate boot"); + let _ = live_rx.await; + tracing::info!("Substrate booted"); - let instance = - Arc::new(EmbeddedSubstrate { shutdown: tx.into(), rpc_port: port, _state: tmp_dir }); + let instance = + Arc::new(EmbeddedSubstrate { shutdown: tx.into(), rpc_port: port, _state: tmp_dir }); - SUBSTRATE_INSTANCES.lock().unwrap().insert(port, instance.clone()); + SUBSTRATE_INSTANCES.lock().unwrap().insert(port, instance.clone()); - Ok(instance) + Ok(instance) } pub fn remove_shared_substrate_by_port(port: u16) { - let mut instances = SUBSTRATE_INSTANCES.lock().unwrap(); - if let Some(_instance) = instances.get(&port) { - instances.remove(&port); - } else { - tracing::warn!("No running substrate instance found on port {}", port); - } + let mut instances = SUBSTRATE_INSTANCES.lock().unwrap(); + if let Some(_instance) = instances.get(&port) { + instances.remove(&port); + } else { + tracing::warn!("No running substrate instance found on port {}", port); + } } pub fn remove_shared_substrate(substrate: &EmbeddedSubstrate) { - remove_shared_substrate_by_port(substrate.port()) + remove_shared_substrate_by_port(substrate.port()) } #[cfg(test)] pub mod test_runtime { - use chronicle_signing::{ - chronicle_secret_names, ChronicleSecretsOptions, ChronicleSigning, BATCHER_NAMESPACE, - CHRONICLE_NAMESPACE, - }; - - use protocol_abstract::{LedgerReader, LedgerWriter}; - use protocol_substrate_chronicle::{ - common::{ - attributes::Attributes, - identity::SignedIdentity, - prov::{ - operations::{AgentExists, ChronicleOperation, CreateNamespace, SetAttributes}, - AgentId, DomaintypeId, ExternalId, NamespaceId, - }, - }, - ChronicleEvent, ChronicleTransaction, - }; - use subxt::{ - ext::{ - futures::StreamExt, - sp_core::{Pair, Public}, - }, - PolkadotConfig, - }; - use uuid::Uuid; - - fn get_from_seed(seed: &str) -> [u8; 32] { - let k = TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed"); - let mut buf = [0; 32]; - buf.copy_from_slice(&k.to_raw_vec()); - - buf - } - - #[tokio::test] - pub async fn connect() { - let handle = crate::shared_dev_node_rpc_on_port(2003, true).await.unwrap(); - - let client = handle.connect_chronicle::().await.unwrap(); - - let mut events = - client.state_updates(protocol_abstract::FromBlock::Head, None).await.unwrap(); - - let signing = ChronicleSigning::new( - chronicle_secret_names(), - vec![ - ( - CHRONICLE_NAMESPACE.to_string(), - ChronicleSecretsOptions::seeded( - vec![( - "chronicle-pk".to_string(), - get_from_seed::("Chronicle"), - )] - .into_iter() - .collect(), - ), - ), - ( - BATCHER_NAMESPACE.to_string(), - ChronicleSecretsOptions::seeded( - vec![( - "batcher-pk".to_string(), - get_from_seed::("Chronicle"), - )] - .into_iter() - .collect(), - ), - ), - ], - ) - .await - .unwrap(); - - let (submit, id) = client - .pre_submit( - ChronicleTransaction::new( - &signing, - SignedIdentity::new_no_identity(), - vec![ - ChronicleOperation::CreateNamespace(CreateNamespace::new( - NamespaceId::from_external_id( - &ExternalId::from("test"), - Uuid::default(), - ), - )), - ChronicleOperation::AgentExists(AgentExists::new( - NamespaceId::from_external_id( - &ExternalId::from("test"), - Uuid::default(), - ), - AgentId::from_external_id("test"), - )), - ChronicleOperation::SetAttributes(SetAttributes::agent( - NamespaceId::from_external_id( - &ExternalId::from("test"), - Uuid::default(), - ), - AgentId::from_external_id("test"), - Attributes::type_only(Some(DomaintypeId::from_external_id("test"))), - )), - ], - ) - .await - .unwrap(), - ) - .await - .unwrap(); - - let _res = client - .do_submit(protocol_abstract::WriteConsistency::Strong, submit) - .await - .unwrap(); - - let (ev, _id, _block, _pos, _) = events.next().await.unwrap(); - - match ev { - ChronicleEvent::Committed { diff, .. } => { - tracing::info!("{:?}", diff) - }, - ChronicleEvent::Contradicted { .. } => panic!("Contradicted"), - } - } + use chronicle_signing::{ + chronicle_secret_names, ChronicleSecretsOptions, ChronicleSigning, BATCHER_NAMESPACE, + CHRONICLE_NAMESPACE, + }; + + use protocol_abstract::{LedgerReader, LedgerWriter}; + use protocol_substrate_chronicle::{ + common::{ + attributes::Attributes, + identity::SignedIdentity, + prov::{ + operations::{AgentExists, ChronicleOperation, CreateNamespace, SetAttributes}, + AgentId, DomaintypeId, ExternalId, NamespaceId, + }, + }, + ChronicleEvent, ChronicleTransaction, + }; + use subxt::{ + ext::{ + futures::StreamExt, + sp_core::{Pair, Public}, + }, + PolkadotConfig, + }; + use uuid::Uuid; + + fn get_from_seed(seed: &str) -> [u8; 32] { + let k = TPublic::Pair::from_string(&format!("//{}", seed), None) + .expect("static values are valid; qed"); + let mut buf = [0; 32]; + buf.copy_from_slice(&k.to_raw_vec()); + + buf + } + + #[tokio::test] + pub async fn connect() { + let handle = crate::shared_dev_node_rpc_on_port(2003, true).await.unwrap(); + + let client = handle.connect_chronicle::().await.unwrap(); + + let mut events = + client.state_updates(protocol_abstract::FromBlock::Head, None).await.unwrap(); + + let signing = ChronicleSigning::new( + chronicle_secret_names(), + vec![ + ( + CHRONICLE_NAMESPACE.to_string(), + ChronicleSecretsOptions::seeded( + vec![( + "chronicle-pk".to_string(), + get_from_seed::("Chronicle"), + )] + .into_iter() + .collect(), + ), + ), + ( + BATCHER_NAMESPACE.to_string(), + ChronicleSecretsOptions::seeded( + vec![( + "batcher-pk".to_string(), + get_from_seed::("Chronicle"), + )] + .into_iter() + .collect(), + ), + ), + ], + ) + .await + .unwrap(); + + let (submit, id) = client + .pre_submit( + ChronicleTransaction::new( + &signing, + SignedIdentity::new_no_identity(), + vec![ + ChronicleOperation::CreateNamespace(CreateNamespace::new( + NamespaceId::from_external_id( + &ExternalId::from("test"), + Uuid::default(), + ), + )), + ChronicleOperation::AgentExists(AgentExists::new( + NamespaceId::from_external_id( + &ExternalId::from("test"), + Uuid::default(), + ), + AgentId::from_external_id("test"), + )), + ChronicleOperation::SetAttributes(SetAttributes::agent( + NamespaceId::from_external_id( + &ExternalId::from("test"), + Uuid::default(), + ), + AgentId::from_external_id("test"), + Attributes::type_only(Some(DomaintypeId::from_external_id("test"))), + )), + ], + ) + .await + .unwrap(), + ) + .await + .unwrap(); + + let _res = client + .do_submit(protocol_abstract::WriteConsistency::Strong, submit) + .await + .unwrap(); + + let (ev, _id, _block, _pos, _) = events.next().await.unwrap(); + + match ev { + ChronicleEvent::Committed { diff, .. } => { + tracing::info!("{:?}", diff) + } + ChronicleEvent::Contradicted { .. } => panic!("Contradicted"), + } + } } diff --git a/crates/gq-subscribe/src/main.rs b/crates/gq-subscribe/src/main.rs index 910b28399..2577b66c6 100644 --- a/crates/gq-subscribe/src/main.rs +++ b/crates/gq-subscribe/src/main.rs @@ -1,122 +1,123 @@ +use std::net::{SocketAddr, ToSocketAddrs}; + use clap::{Arg, Command}; use http::{HeaderValue, StatusCode}; -use rand::{distributions::Alphanumeric, thread_rng, Rng}; +use rand::{distributions::Alphanumeric, Rng, thread_rng}; use serde_json::{json, Value}; -use std::net::{SocketAddr, ToSocketAddrs}; use tungstenite::{client::IntoClientRequest, connect, Message}; fn main() -> Result<(), anyhow::Error> { - let args = Command::new("gq-ws") - .author("Blockchain Technology Partners") - .about("Perform GraphQL subscription to a websocket") - .arg( - Arg::new("request") - .long("subscription") - .short('s') - .takes_value(true) - .required(true) - .help("the GraphQL subscription request"), - ) - .arg( - Arg::new("count") - .long("notification-count") - .short('c') - .takes_value(true) - .required(true) - .help("how many responses to report"), - ) - .arg( - Arg::new("address") - .long("chronicle-address") - .short('a') - .takes_value(true) - .default_value("localhost:9982") - .help("the network address of the Chronicle API"), - ) - .arg( - Arg::new("token") - .long("bearer-token") - .short('t') - .takes_value(true) - .help("the bearer token to pass for authorization"), - ) - .get_matches(); + let args = Command::new("gq-ws") + .author("Blockchain Technology Partners") + .about("Perform GraphQL subscription to a websocket") + .arg( + Arg::new("request") + .long("subscription") + .short('s') + .takes_value(true) + .required(true) + .help("the GraphQL subscription request"), + ) + .arg( + Arg::new("count") + .long("notification-count") + .short('c') + .takes_value(true) + .required(true) + .help("how many responses to report"), + ) + .arg( + Arg::new("address") + .long("chronicle-address") + .short('a') + .takes_value(true) + .default_value("localhost:9982") + .help("the network address of the Chronicle API"), + ) + .arg( + Arg::new("token") + .long("bearer-token") + .short('t') + .takes_value(true) + .help("the bearer token to pass for authorization"), + ) + .get_matches(); - let subscription_query = args.value_of("request").unwrap(); - let notification_count: u32 = args.value_of("count").unwrap().parse()?; - let chronicle_address: SocketAddr = args - .value_of("address") - .unwrap() - .to_socket_addrs()? - .next() - .expect("network address required for Chronicle API"); - let bearer_token = args.value_of("token"); + let subscription_query = args.value_of("request").unwrap(); + let notification_count: u32 = args.value_of("count").unwrap().parse()?; + let chronicle_address: SocketAddr = args + .value_of("address") + .unwrap() + .to_socket_addrs()? + .next() + .expect("network address required for Chronicle API"); + let bearer_token = args.value_of("token"); - // generate random ID for subscription - let subscription_id: String = - thread_rng().sample_iter(&Alphanumeric).take(12).map(char::from).collect(); + // generate random ID for subscription + let subscription_id: String = + thread_rng().sample_iter(&Alphanumeric).take(12).map(char::from).collect(); - // prepare websocket request - let mut client_request = format!("ws://{chronicle_address}/ws").into_client_request()?; - let headers = client_request.headers_mut(); - if let Some(token) = bearer_token { - headers.insert("Authorization", HeaderValue::from_str(&format!("Bearer {token}"))?); - } - headers.insert("Sec-WebSocket-Protocol", HeaderValue::from_str("graphql-ws")?); + // prepare websocket request + let mut client_request = format!("ws://{chronicle_address}/ws").into_client_request()?; + let headers = client_request.headers_mut(); + if let Some(token) = bearer_token { + headers.insert("Authorization", HeaderValue::from_str(&format!("Bearer {token}"))?); + } + headers.insert("Sec-WebSocket-Protocol", HeaderValue::from_str("graphql-ws")?); - // connect and upgrade websocket - let (mut socket, response) = connect(client_request)?; - if response.status() != StatusCode::SWITCHING_PROTOCOLS { - panic!("failed connect and upgrade: {response:#?}"); - } + // connect and upgrade websocket + let (mut socket, response) = connect(client_request)?; + if response.status() != StatusCode::SWITCHING_PROTOCOLS { + panic!("failed connect and upgrade: {response:#?}"); + } - // initialize gql connection - let conn_init_json = json!({ + // initialize gql connection + let conn_init_json = json!({ "type": "connection_init" }); - let conn_init_msg = Message::Text(serde_json::to_string(&conn_init_json)?); - socket.send(conn_init_msg)?; - let conn_response = socket.read()?; - if let Value::Object(map) = serde_json::from_str::(&conn_response.clone().into_text()?)? - { - if map.get("type") == Some(&Value::String("connection_ack".to_string())) { - // connection initialized, so subscribe - let subscription_json = json!({ + let conn_init_msg = Message::Text(serde_json::to_string(&conn_init_json)?); + socket.send(conn_init_msg)?; + let conn_response = socket.read()?; + if let Value::Object(map) = serde_json::from_str::(&conn_response.clone().into_text()?)? + { + if map.get("type") == Some(&Value::String("connection_ack".to_string())) { + // connection initialized, so subscribe + let subscription_json = json!({ "type": "start", "id": subscription_id, "payload": { "query": subscription_query } }); - let subscription_msg = Message::Text(serde_json::to_string(&subscription_json)?); - socket.send(subscription_msg)?; + let subscription_msg = Message::Text(serde_json::to_string(&subscription_json)?); + socket.send(subscription_msg)?; - // receive and print notifications - let data_json = Value::String("data".to_string()); - let subscription_id_json = Value::String(subscription_id); - let mut remaining = notification_count; - while remaining > 0 { - remaining -= 1; - let notification_msg = socket.read()?; - let notification_json = - serde_json::from_str::(¬ification_msg.into_text()?)?; + // receive and print notifications + let data_json = Value::String("data".to_string()); + let subscription_id_json = Value::String(subscription_id); + let mut remaining = notification_count; + while remaining > 0 { + remaining -= 1; + let notification_msg = socket.read()?; + let notification_json = + serde_json::from_str::(¬ification_msg.into_text()?)?; - if let Value::Object(map) = notification_json.clone() { - if map.get("type") == Some(&data_json) && - map.get("id") == Some(&subscription_id_json) - { - let notification_pretty = - serde_json::to_string_pretty(map.get("payload").unwrap())?; - println!("{notification_pretty}"); - } else { - panic!("expected a response to subscription, got: {notification_json}"); - } - } else { - panic!("expected a JSON object notification, got: {notification_json}"); - } - } - return Ok(()) - } - } - panic!("expected acknowledgement of connection initialization, got: {conn_response}"); + if let Value::Object(map) = notification_json.clone() { + if map.get("type") == Some(&data_json) && + map.get("id") == Some(&subscription_id_json) + { + let notification_pretty = + serde_json::to_string_pretty(map.get("payload").unwrap())?; + println!("{notification_pretty}"); + } else { + panic!("expected a response to subscription, got: {notification_json}"); + } + } else { + panic!("expected a JSON object notification, got: {notification_json}"); + } + } + return Ok(()); + } + } + panic!("expected acknowledgement of connection initialization, got: {conn_response}"); } diff --git a/crates/id-provider/src/main.rs b/crates/id-provider/src/main.rs index 89c6dab86..919d5f3ba 100644 --- a/crates/id-provider/src/main.rs +++ b/crates/id-provider/src/main.rs @@ -1,68 +1,69 @@ +use std::process::Command; + use oauth2::{ - basic::BasicClient, reqwest::http_client, AuthUrl, AuthorizationCode, ClientId, ClientSecret, - CsrfToken, PkceCodeChallenge, RedirectUrl, Scope, TokenResponse, TokenUrl, + AuthorizationCode, AuthUrl, basic::BasicClient, ClientId, ClientSecret, CsrfToken, + PkceCodeChallenge, RedirectUrl, reqwest::http_client, Scope, TokenResponse, TokenUrl, }; -use std::process::Command; use url::Url; fn main() -> Result<(), anyhow::Error> { - // construct OAuth query: authorization code flow with PKCE + // construct OAuth query: authorization code flow with PKCE - let oauth_client = BasicClient::new( - ClientId::new("client-id".to_string()), - Some(ClientSecret::new("client-secret".to_string())), - AuthUrl::new("http://localhost:8090/authorize".to_string())?, - Some(TokenUrl::new("http://localhost:8090/token".to_string())?), - ) - .set_redirect_uri(RedirectUrl::new("http://example.com/callback".to_string())?); + let oauth_client = BasicClient::new( + ClientId::new("client-id".to_string()), + Some(ClientSecret::new("client-secret".to_string())), + AuthUrl::new("http://localhost:8090/authorize".to_string())?, + Some(TokenUrl::new("http://localhost:8090/token".to_string())?), + ) + .set_redirect_uri(RedirectUrl::new("http://example.com/callback".to_string())?); - let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256(); + let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256(); - let (auth_url, csrf_token) = oauth_client - .authorize_url(CsrfToken::new_random) - .add_scope(Scope::new("openid".to_string())) - .add_scope(Scope::new("profile".to_string())) - .add_scope(Scope::new("email".to_string())) - .set_pkce_challenge(pkce_challenge) - .url(); + let (auth_url, csrf_token) = oauth_client + .authorize_url(CsrfToken::new_random) + .add_scope(Scope::new("openid".to_string())) + .add_scope(Scope::new("profile".to_string())) + .add_scope(Scope::new("email".to_string())) + .set_pkce_challenge(pkce_challenge) + .url(); - // use curl to handle HTTP basic authentication + // use curl to handle HTTP basic authentication - let args = vec![ - "-w".to_string(), - "%{redirect_url}\n".to_string(), - "-u".to_string(), - "rmalina1:test-password".to_string(), - auth_url.to_string(), - ]; + let args = vec![ + "-w".to_string(), + "%{redirect_url}\n".to_string(), + "-u".to_string(), + "rmalina1:test-password".to_string(), + auth_url.to_string(), + ]; - let curl_output = Command::new("curl").args(args).output()?; + let curl_output = Command::new("curl").args(args).output()?; - // parse URL from redirect to callback with authorization code + // parse URL from redirect to callback with authorization code - let url = Url::parse(std::str::from_utf8(&curl_output.stdout)?.trim())?; + let url = Url::parse(std::str::from_utf8(&curl_output.stdout)?.trim())?; - let mut query_state = None; - let mut query_code = None; + let mut query_state = None; + let mut query_code = None; - for (key, value) in url.query_pairs() { - match key.to_string().as_str() { - "state" => query_state = Some(value), - "code" => query_code = Some(value), - _ => {}, - } - } + for (key, value) in url.query_pairs() { + match key.to_string().as_str() { + "state" => query_state = Some(value), + "code" => query_code = Some(value), + _ => {} + } + } - assert_eq!(*csrf_token.secret(), query_state.unwrap().to_string()); + assert_eq!(*csrf_token.secret(), query_state.unwrap().to_string()); - // exchange authorization code for access token + // exchange authorization code for access token - let auth_code = query_code.unwrap(); - let token_response = oauth_client - .exchange_code(AuthorizationCode::new(auth_code.to_string())) - .set_pkce_verifier(pkce_verifier) - .request(http_client)?; + let auth_code = query_code.unwrap(); + let token_response = oauth_client + .exchange_code(AuthorizationCode::new(auth_code.to_string())) + .set_pkce_verifier(pkce_verifier) + .request(http_client)?; - println!("{}", token_response.access_token().secret()); - Ok(()) + println!("{}", token_response.access_token().secret()); + Ok(()) } diff --git a/crates/opactl/Cargo.toml b/crates/opactl/Cargo.toml index fc47d6420..4f62b8757 100644 --- a/crates/opactl/Cargo.toml +++ b/crates/opactl/Cargo.toml @@ -1,36 +1,36 @@ [package] -build = "build.rs" +build = "build.rs" edition = "2021" -name = "opactl" +name = "opactl" version = "0.7.5" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-trait = { workspace = true } -chronicle-signing = { workspace = true } -chronicle-telemetry = { path = "../chronicle-telemetry" } -clap = { version = "4.1.1", features = ["env"] } -common = { path = "../common", features = ["std"] } -const_format = { workspace = true } -futures = { workspace = true } -k256 = { workspace = true } -lazy_static = { workspace = true } -protocol-abstract = { path = "../protocol-abstract" } -protocol-substrate = { path = "../protocol-substrate" } +async-trait = { workspace = true } +chronicle-signing = { workspace = true } +chronicle-telemetry = { path = "../chronicle-telemetry" } +clap = { version = "4.1.1", features = ["env"] } +common = { path = "../common", features = ["std"] } +const_format = { workspace = true } +futures = { workspace = true } +k256 = { workspace = true } +lazy_static = { workspace = true } +protocol-abstract = { path = "../protocol-abstract" } +protocol-substrate = { path = "../protocol-substrate" } protocol-substrate-opa = { path = "../protocol-substrate-opa" } -rand = { workspace = true } -rand_core = { workspace = true } -serde = { workspace = true } -serde_derive = { workspace = true } -serde_json = { workspace = true } -thiserror = { workspace = true } -tokio = { workspace = true } -tokio-stream = { workspace = true } -tracing = { workspace = true } -url = { workspace = true } -user-error = { workspace = true } -uuid = { workspace = true, features = ["v4"] } +rand = { workspace = true } +rand_core = { workspace = true } +serde = { workspace = true } +serde_derive = { workspace = true } +serde_json = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tokio-stream = { workspace = true } +tracing = { workspace = true } +url = { workspace = true } +user-error = { workspace = true } +uuid = { workspace = true, features = ["v4"] } [dev-dependencies] @@ -41,12 +41,12 @@ hex = { workspace = true } insta = { workspace = true, features = ["yaml"] } pallet-opa = { path = "../pallet-opa", features = ["std"] } parity-scale-codec = { version = "3.4.0", default-features = false, features = [ - "derive", + "derive", ] } portpicker = { workspace = true } scale-info = { version = "2.10.0", default-features = false, features = [ - "derive", + "derive", ] } scale-value = { version = "^0.14" } serde_json = { workspace = true } diff --git a/crates/opactl/build.rs b/crates/opactl/build.rs index afb2c9546..5a1d86bbe 100644 --- a/crates/opactl/build.rs +++ b/crates/opactl/build.rs @@ -1,8 +1,8 @@ fn main() { - //Create a .VERSION file containing 'local' if it does not exist + //Create a .VERSION file containing 'local' if it does not exist - let version_file = std::path::Path::new("../../.VERSION"); - if !version_file.exists() { - std::fs::write(version_file, "local").expect("Unable to write file"); - } + let version_file = std::path::Path::new("../../.VERSION"); + if !version_file.exists() { + std::fs::write(version_file, "local").expect("Unable to write file"); + } } diff --git a/crates/opactl/src/cli.rs b/crates/opactl/src/cli.rs index 637a5243d..003bd5f5a 100644 --- a/crates/opactl/src/cli.rs +++ b/crates/opactl/src/cli.rs @@ -1,170 +1,170 @@ use std::path::PathBuf; -use chronicle_signing::{ - opa_secret_names, ChronicleSecretsOptions, ChronicleSigning, SecretError, BATCHER_NAMESPACE, - OPA_NAMESPACE, -}; use clap::{ - builder::{NonEmptyStringValueParser, StringValueParser}, - Arg, ArgAction, ArgMatches, Command, ValueHint, + Arg, + ArgAction, ArgMatches, builder::{NonEmptyStringValueParser, StringValueParser}, Command, ValueHint, }; - use tracing::info; use url::Url; +use chronicle_signing::{ + BATCHER_NAMESPACE, ChronicleSecretsOptions, ChronicleSigning, OPA_NAMESPACE, opa_secret_names, + SecretError, +}; + // Generate an ephemeral key if no key is provided fn batcher_key() -> Arg { - Arg::new( "batcher-key-from-store") - .long("batcher-key-from-store") - .num_args(0) - .help("If specified the key 'batcher-pk' will be used to sign sawtooth transactions, otherwise an ephemeral key will be generated") + Arg::new("batcher-key-from-store") + .long("batcher-key-from-store") + .num_args(0) + .help("If specified the key 'batcher-pk' will be used to sign sawtooth transactions, otherwise an ephemeral key will be generated") } fn wait_args(command: Command) -> Command { - command.arg( - Arg::new("wait") - .long("wait") - .num_args(0..=1) - .value_parser(clap::value_parser!(u32).range(0..)) - .default_value("5") - .default_missing_value("5") - .help("Wait for the specified number of blocks to be committed before exiting"), - ) + command.arg( + Arg::new("wait") + .long("wait") + .num_args(0..=1) + .value_parser(clap::value_parser!(u32).range(0..)) + .default_value("5") + .default_missing_value("5") + .help("Wait for the specified number of blocks to be committed before exiting"), + ) } fn bootstrap() -> Command { - wait_args( - Command::new("bootstrap") - .about("Initialize the OPA transaction processor with a root key from the keystore") - .arg(batcher_key()), - ) + wait_args( + Command::new("bootstrap") + .about("Initialize the OPA transaction processor with a root key from the keystore") + .arg(batcher_key()), + ) } fn generate() -> Command { - Command::new("generate") - .arg(Arg::new("output").short('o').long("output").num_args(0..=1).help( - "The name to write the key to, if not specified then the key is written to stdout", - )) - .about("Generate a new private key and write it to the keystore") + Command::new("generate") + .arg(Arg::new("output").short('o').long("output").num_args(0..=1).help( + "The name to write the key to, if not specified then the key is written to stdout", + )) + .about("Generate a new private key and write it to the keystore") } fn rotate_root() -> Command { - wait_args( - Command::new("rotate-root") - .about("Rotate the root key for the OPA transaction processor") - .arg( - Arg::new("new-root-key") - .short('n') - .long("new-root-key") - .env("NEW_ROOT_KEY") - .required(true) - .num_args(1) - .value_hint(ValueHint::FilePath) - .help("The name of the new key in the keystore to register as the root key"), - ) - .arg(batcher_key()), - ) + wait_args( + Command::new("rotate-root") + .about("Rotate the root key for the OPA transaction processor") + .arg( + Arg::new("new-root-key") + .short('n') + .long("new-root-key") + .env("NEW_ROOT_KEY") + .required(true) + .num_args(1) + .value_hint(ValueHint::FilePath) + .help("The name of the new key in the keystore to register as the root key"), + ) + .arg(batcher_key()), + ) } fn register_key() -> Command { - wait_args( - Command::new("register-key") - .about("Register a new non root key with the OPA transaction processor") - .arg( - Arg::new("new-key") - .long("new-key") - .required(true) - .num_args(1) - .value_hint(ValueHint::FilePath) - .help("The keystore name of a PEM-encoded key to register"), - ) - .arg( - Arg::new("id") - .short('i') - .long("id") - .required(true) - .num_args(1) - .value_hint(ValueHint::Unknown) - .value_parser(NonEmptyStringValueParser::new()) - .help("The id of the key"), - ) - .arg( - Arg::new("overwrite") - .short('o') - .long("overwrite") - .action(ArgAction::SetTrue) - .help("Replace any existing non-root key"), - ) - .arg(batcher_key()), - ) + wait_args( + Command::new("register-key") + .about("Register a new non root key with the OPA transaction processor") + .arg( + Arg::new("new-key") + .long("new-key") + .required(true) + .num_args(1) + .value_hint(ValueHint::FilePath) + .help("The keystore name of a PEM-encoded key to register"), + ) + .arg( + Arg::new("id") + .short('i') + .long("id") + .required(true) + .num_args(1) + .value_hint(ValueHint::Unknown) + .value_parser(NonEmptyStringValueParser::new()) + .help("The id of the key"), + ) + .arg( + Arg::new("overwrite") + .short('o') + .long("overwrite") + .action(ArgAction::SetTrue) + .help("Replace any existing non-root key"), + ) + .arg(batcher_key()), + ) } fn rotate_key() -> Command { - wait_args( - Command::new("rotate-key") - .about("Rotate the key with the specified id for the OPA transaction processor") - .arg( - Arg::new("current-key") - .long("current-key") - .env("CURRENT_KEY") - .required(true) - .num_args(1) - .value_hint(ValueHint::FilePath) - .help("The keystore name of the current registered key"), - ) - .arg( - Arg::new("new-key") - .long("new-key") - .env("NEW_KEY") - .required(true) - .num_args(1) - .value_hint(ValueHint::FilePath) - .help("The keystore name of the new key to register"), - ) - .arg( - Arg::new("id") - .short('i') - .long("id") - .required(true) - .num_args(1) - .value_hint(ValueHint::Unknown) - .value_parser(NonEmptyStringValueParser::new()) - .help("The id of the key"), - ) - .arg(batcher_key()), - ) + wait_args( + Command::new("rotate-key") + .about("Rotate the key with the specified id for the OPA transaction processor") + .arg( + Arg::new("current-key") + .long("current-key") + .env("CURRENT_KEY") + .required(true) + .num_args(1) + .value_hint(ValueHint::FilePath) + .help("The keystore name of the current registered key"), + ) + .arg( + Arg::new("new-key") + .long("new-key") + .env("NEW_KEY") + .required(true) + .num_args(1) + .value_hint(ValueHint::FilePath) + .help("The keystore name of the new key to register"), + ) + .arg( + Arg::new("id") + .short('i') + .long("id") + .required(true) + .num_args(1) + .value_hint(ValueHint::Unknown) + .value_parser(NonEmptyStringValueParser::new()) + .help("The id of the key"), + ) + .arg(batcher_key()), + ) } fn set_policy() -> Command { - wait_args( - Command::new("set-policy") - .about("Set policy with id, requires access to root private key") - .arg( - Arg::new("id") - .short('i') - .long("id") - .num_args(1) - .value_hint(ValueHint::Unknown) - .value_parser(NonEmptyStringValueParser::new()) - .default_value("default") - .help("The id of the new policy"), - ) - .arg( - Arg::new("policy") - .short('p') - .long("policy") - .num_args(1) - .required(true) - .value_hint(ValueHint::Url) - .value_parser(StringValueParser::new()) - .help("A path or url to a policy bundle"), - ) - .arg(batcher_key()), - ) + wait_args( + Command::new("set-policy") + .about("Set policy with id, requires access to root private key") + .arg( + Arg::new("id") + .short('i') + .long("id") + .num_args(1) + .value_hint(ValueHint::Unknown) + .value_parser(NonEmptyStringValueParser::new()) + .default_value("default") + .help("The id of the new policy"), + ) + .arg( + Arg::new("policy") + .short('p') + .long("policy") + .num_args(1) + .required(true) + .value_hint(ValueHint::Url) + .value_parser(StringValueParser::new()) + .help("A path or url to a policy bundle"), + ) + .arg(batcher_key()), + ) } fn get_key() -> Command { - Command::new("get-key") + Command::new("get-key") .about("Get the currently registered public key") .arg( Arg::new("id") @@ -188,28 +188,28 @@ fn get_key() -> Command { } fn get_policy() -> Command { - Command::new("get-policy") - .about("Get the currently registered policy") - .arg( - Arg::new("id") - .short('i') - .long("id") - .num_args(1) - .value_hint(ValueHint::Unknown) - .value_parser(NonEmptyStringValueParser::new()) - .default_value("default") - .help("The id of the policy, if not specified then the default policy is returned"), - ) - .arg( - Arg::new("output") - .short('o') - .long("output") - .num_args(1) - .required(true) - .value_hint(ValueHint::FilePath) - .value_parser(NonEmptyStringValueParser::new()) - .help("The path to write the policy to"), - ) + Command::new("get-policy") + .about("Get the currently registered policy") + .arg( + Arg::new("id") + .short('i') + .long("id") + .num_args(1) + .value_hint(ValueHint::Unknown) + .value_parser(NonEmptyStringValueParser::new()) + .default_value("default") + .help("The id of the policy, if not specified then the default policy is returned"), + ) + .arg( + Arg::new("output") + .short('o') + .long("output") + .num_args(1) + .required(true) + .value_hint(ValueHint::FilePath) + .value_parser(NonEmptyStringValueParser::new()) + .help("The path to write the policy to"), + ) } pub const LONG_VERSION: &str = const_format::formatcp!( @@ -219,167 +219,167 @@ pub const LONG_VERSION: &str = const_format::formatcp!( ); pub fn cli() -> Command { - info!(opa_version = LONG_VERSION); - Command::new("opactl") - .version(LONG_VERSION) - .author("Blockchain Technology Partners") - .about("A command line tool for interacting with the OPA transaction processor") - .arg( - Arg::new("keystore-path") - .long("keystore-path") - .help("The path to a directory containing keys") - .value_parser(clap::value_parser!(PathBuf)) - .value_hint(ValueHint::DirPath) - .env("KEYSTORE_PATH") - .default_value("."), - ) - .arg( - Arg::new("batcher-key-from-path") - .long("batcher-key-from-path") - .action(ArgAction::SetTrue) - .help("Load batcher key from keystore path") - .conflicts_with("batcher-key-from-vault") - .conflicts_with("batcher-key-generated"), - ) - .arg( - Arg::new("batcher-key-from-vault") - .long("batcher-key-from-vault") - .action(ArgAction::SetTrue) - .help("Use Hashicorp Vault to store the batcher key") - .conflicts_with("batcher-key-from-path") - .conflicts_with("batcher-key-generated"), - ) - .arg( - Arg::new("batcher-key-generated") - .long("batcher-key-generated") - .action(ArgAction::SetTrue) - .help("Generate the batcher key in memory") - .conflicts_with("batcher-key-from-path") - .conflicts_with("batcher-key-from-vault"), - ) - .arg( - Arg::new("opa-key-from-path") - .long("opa-key-from-path") - .action(ArgAction::SetTrue) - .help("Use keystore path for the opa key located in 'opa-pk'") - .conflicts_with("opa-key-from-vault"), - ) - .arg( - Arg::new("opa-key-from-vault") - .long("opa-key-from-vault") - .action(ArgAction::SetTrue) - .help("Use Hashicorp Vault to store the Opa key") - .conflicts_with("opa-key-from-path"), - ) - .arg( - Arg::new("vault-address") - .long("vault-address") - .num_args(0..=1) - .value_parser(clap::value_parser!(Url)) - .value_hint(ValueHint::Url) - .help("URL for connecting to Hashicorp Vault") - .env("VAULT_ADDRESS"), - ) - .arg( - Arg::new("vault-token") - .long("vault-token") - .num_args(0..=1) - .help("Token for connecting to Hashicorp Vault") - .env("VAULT_TOKEN"), - ) - .arg( - Arg::new("vault-mount-path") - .long("vault-mount-path") - .num_args(0..=1) - .value_hint(ValueHint::DirPath) - .help("Mount path for vault secrets") - .default_value("/") - .env("VAULT_MOUNT_PATH"), - ) - .arg( - Arg::new("sawtooth-address") - .short('a') - .long("sawtooth-address") - .num_args(0..=1) - .help("The address of the Sawtooth ZMQ api, as zmq://host:port") - .value_parser(clap::value_parser!(Url)) - .env("SAWTOOTH_ADDRESS") - .default_value("tcp://localhost:4004"), - ) - .subcommand(bootstrap()) - .subcommand(generate()) - .subcommand(rotate_root()) - .subcommand(register_key()) - .subcommand(rotate_key()) - .subcommand(set_policy()) - .subcommand(get_key()) - .subcommand(get_policy()) + info!(opa_version = LONG_VERSION); + Command::new("opactl") + .version(LONG_VERSION) + .author("Blockchain Technology Partners") + .about("A command line tool for interacting with the OPA transaction processor") + .arg( + Arg::new("keystore-path") + .long("keystore-path") + .help("The path to a directory containing keys") + .value_parser(clap::value_parser!(PathBuf)) + .value_hint(ValueHint::DirPath) + .env("KEYSTORE_PATH") + .default_value("."), + ) + .arg( + Arg::new("batcher-key-from-path") + .long("batcher-key-from-path") + .action(ArgAction::SetTrue) + .help("Load batcher key from keystore path") + .conflicts_with("batcher-key-from-vault") + .conflicts_with("batcher-key-generated"), + ) + .arg( + Arg::new("batcher-key-from-vault") + .long("batcher-key-from-vault") + .action(ArgAction::SetTrue) + .help("Use Hashicorp Vault to store the batcher key") + .conflicts_with("batcher-key-from-path") + .conflicts_with("batcher-key-generated"), + ) + .arg( + Arg::new("batcher-key-generated") + .long("batcher-key-generated") + .action(ArgAction::SetTrue) + .help("Generate the batcher key in memory") + .conflicts_with("batcher-key-from-path") + .conflicts_with("batcher-key-from-vault"), + ) + .arg( + Arg::new("opa-key-from-path") + .long("opa-key-from-path") + .action(ArgAction::SetTrue) + .help("Use keystore path for the opa key located in 'opa-pk'") + .conflicts_with("opa-key-from-vault"), + ) + .arg( + Arg::new("opa-key-from-vault") + .long("opa-key-from-vault") + .action(ArgAction::SetTrue) + .help("Use Hashicorp Vault to store the Opa key") + .conflicts_with("opa-key-from-path"), + ) + .arg( + Arg::new("vault-address") + .long("vault-address") + .num_args(0..=1) + .value_parser(clap::value_parser!(Url)) + .value_hint(ValueHint::Url) + .help("URL for connecting to Hashicorp Vault") + .env("VAULT_ADDRESS"), + ) + .arg( + Arg::new("vault-token") + .long("vault-token") + .num_args(0..=1) + .help("Token for connecting to Hashicorp Vault") + .env("VAULT_TOKEN"), + ) + .arg( + Arg::new("vault-mount-path") + .long("vault-mount-path") + .num_args(0..=1) + .value_hint(ValueHint::DirPath) + .help("Mount path for vault secrets") + .default_value("/") + .env("VAULT_MOUNT_PATH"), + ) + .arg( + Arg::new("sawtooth-address") + .short('a') + .long("sawtooth-address") + .num_args(0..=1) + .help("The address of the Sawtooth ZMQ api, as zmq://host:port") + .value_parser(clap::value_parser!(Url)) + .env("SAWTOOTH_ADDRESS") + .default_value("tcp://localhost:4004"), + ) + .subcommand(bootstrap()) + .subcommand(generate()) + .subcommand(rotate_root()) + .subcommand(register_key()) + .subcommand(rotate_key()) + .subcommand(set_policy()) + .subcommand(get_key()) + .subcommand(get_policy()) } // Chronicle secret store needs to know what secret names are used in advance, // so extract from potential cli args fn additional_secret_names(expected: Vec<&str>, matches: &ArgMatches) -> Vec { - expected.iter().filter_map(|x| matches.get_one::(x).cloned()).collect() + expected.iter().filter_map(|x| matches.get_one::(x).cloned()).collect() } // Batcher keys may be ephemeral if batcher-key-from-path is not set, also we need to know secret // names in advance, so must inspect the supplied CLI arguments pub(crate) async fn configure_signing( - expected: Vec<&str>, - root_matches: &ArgMatches, - matches: &ArgMatches, + expected: Vec<&str>, + root_matches: &ArgMatches, + matches: &ArgMatches, ) -> Result { - let mut secret_names = opa_secret_names(); - secret_names.append( - &mut additional_secret_names(expected, matches) - .into_iter() - .map(|name| (OPA_NAMESPACE.to_string(), name.to_string())) - .collect(), - ); - let keystore_path = root_matches.get_one::("keystore-path").unwrap(); + let mut secret_names = opa_secret_names(); + secret_names.append( + &mut additional_secret_names(expected, matches) + .into_iter() + .map(|name| (OPA_NAMESPACE.to_string(), name.to_string())) + .collect(), + ); + let keystore_path = root_matches.get_one::("keystore-path").unwrap(); - let opa_key_from_vault = root_matches.get_one("opa-key-from-vault").is_some_and(|x| *x); - let opa_secret_options = if opa_key_from_vault { - ChronicleSecretsOptions::stored_in_vault( - matches.get_one("vault-url").unwrap(), - matches.get_one("vault-token").cloned().unwrap(), - matches.get_one("vault-mount-path").cloned().unwrap(), - ) - } else { - ChronicleSecretsOptions::stored_at_path(keystore_path) - }; - let opa_secret = (OPA_NAMESPACE.to_string(), opa_secret_options); + let opa_key_from_vault = root_matches.get_one("opa-key-from-vault").is_some_and(|x| *x); + let opa_secret_options = if opa_key_from_vault { + ChronicleSecretsOptions::stored_in_vault( + matches.get_one("vault-url").unwrap(), + matches.get_one("vault-token").cloned().unwrap(), + matches.get_one("vault-mount-path").cloned().unwrap(), + ) + } else { + ChronicleSecretsOptions::stored_at_path(keystore_path) + }; + let opa_secret = (OPA_NAMESPACE.to_string(), opa_secret_options); - let batcher_key_from_path = root_matches.get_one("batcher-key-from-path").is_some_and(|x| *x); - let batcher_key_from_vault = root_matches.get_one("batcher-key-from-vault").is_some_and(|x| *x); - let batcher_secret_options = if batcher_key_from_path { - ChronicleSecretsOptions::stored_at_path(keystore_path) - } else if batcher_key_from_vault { - ChronicleSecretsOptions::stored_in_vault( - matches.get_one("vault-url").unwrap(), - matches.get_one("vault-token").cloned().unwrap(), - matches.get_one("vault-mount-path").cloned().unwrap(), - ) - } else { - ChronicleSecretsOptions::generate_in_memory() - }; - let batcher_secret = (BATCHER_NAMESPACE.to_string(), batcher_secret_options); + let batcher_key_from_path = root_matches.get_one("batcher-key-from-path").is_some_and(|x| *x); + let batcher_key_from_vault = root_matches.get_one("batcher-key-from-vault").is_some_and(|x| *x); + let batcher_secret_options = if batcher_key_from_path { + ChronicleSecretsOptions::stored_at_path(keystore_path) + } else if batcher_key_from_vault { + ChronicleSecretsOptions::stored_in_vault( + matches.get_one("vault-url").unwrap(), + matches.get_one("vault-token").cloned().unwrap(), + matches.get_one("vault-mount-path").cloned().unwrap(), + ) + } else { + ChronicleSecretsOptions::generate_in_memory() + }; + let batcher_secret = (BATCHER_NAMESPACE.to_string(), batcher_secret_options); - let secrets = vec![opa_secret, batcher_secret]; - ChronicleSigning::new(secret_names, secrets).await + let secrets = vec![opa_secret, batcher_secret]; + ChronicleSigning::new(secret_names, secrets).await } #[derive(Debug, Clone, Copy)] pub(crate) enum Wait { - NoWait, - NumberOfBlocks(u32), + NoWait, + NumberOfBlocks(u32), } impl Wait { - pub(crate) fn from_matches(matches: &ArgMatches) -> Self { - match matches.get_one::("wait") { - Some(blocks) if *blocks > 0 => Wait::NumberOfBlocks(*blocks), - _ => Wait::NoWait, - } - } + pub(crate) fn from_matches(matches: &ArgMatches) -> Self { + match matches.get_one::("wait") { + Some(blocks) if *blocks > 0 => Wait::NumberOfBlocks(*blocks), + _ => Wait::NoWait, + } + } } diff --git a/crates/opactl/src/main.rs b/crates/opactl/src/main.rs index 24483e64e..98e41df07 100644 --- a/crates/opactl/src/main.rs +++ b/crates/opactl/src/main.rs @@ -1,38 +1,39 @@ -use chronicle_signing::{OpaKnownKeyNamesSigner, SecretError, OPA_PK}; +use std::{convert::Infallible, fs::File, io::Write, path::PathBuf, time::Duration}; + use clap::ArgMatches; +use futures::{channel::oneshot, Future, FutureExt, StreamExt}; +use k256::{ + pkcs8::{EncodePrivateKey, LineEnding}, + SecretKey, +}; +use rand::rngs::StdRng; +use rand_core::SeedableRng; +use serde::Serialize; +use thiserror::Error; +use tokio::runtime::Handle; +use tracing::{debug, error, info, instrument, Instrument, Level, span}; +use url::Url; +use user_error::UFE; +use uuid::Uuid; + +use chronicle_signing::{OPA_PK, OpaKnownKeyNamesSigner, SecretError}; use cli::{configure_signing, Wait}; use common::{ opa::{ codec::{KeysV1, PolicyV1}, - std::{key_address, load_bytes_from_url, FromUrlError}, - Keys, Policy, + Keys, + Policy, std::{FromUrlError, key_address, load_bytes_from_url}, }, prov::ChronicleTransactionId, }; -use futures::{channel::oneshot, Future, FutureExt, StreamExt}; -use k256::{ - pkcs8::{EncodePrivateKey, LineEnding}, - SecretKey, -}; - use protocol_abstract::{FromBlock, LedgerReader, LedgerWriter}; use protocol_substrate::{PolkadotConfig, SubstrateStateReader, SubxtClientError}; use protocol_substrate_opa::{ - submission_builder::SubmissionBuilder, - transaction::{OpaTransaction, TransactionError}, - OpaEvent, OpaSubstrateClient, + OpaEvent, + OpaSubstrateClient, + submission_builder::SubmissionBuilder, transaction::{OpaTransaction, TransactionError}, }; -use serde::Serialize; -use std::{convert::Infallible, fs::File, io::Write, path::PathBuf, time::Duration}; -use thiserror::Error; -use url::Url; -use uuid::Uuid; -use rand::rngs::StdRng; -use rand_core::SeedableRng; -use tokio::runtime::Handle; -use tracing::{debug, error, info, instrument, span, Instrument, Level}; -use user_error::UFE; mod cli; #[cfg(test)] @@ -40,108 +41,108 @@ mod test; #[derive(Error, Debug)] pub enum OpaCtlError { - #[error("Operation cancelled {0}")] - Cancelled(oneshot::Canceled), - - #[error("Communication error: {0}")] - Communication( - #[from] - #[source] - SubxtClientError, - ), - - #[error("IO error: {0}")] - IO( - #[from] - #[source] - std::io::Error, - ), - - #[error("Json error: {0}")] - Json( - #[from] - #[source] - serde_json::Error, - ), - - #[error("Pkcs8 error")] - Pkcs8, - - #[error("Transaction failed: {0}")] - TransactionFailed(String), - - #[error("Transaction not found after wait: {0}")] - TransactionNotFound(ChronicleTransactionId), - - #[error("Error loading from URL: {0}")] - Url( - #[from] - #[source] - FromUrlError, - ), - - #[error("Utf8 error: {0}")] - Utf8( - #[from] - #[source] - std::str::Utf8Error, - ), - - #[error("Signing: {0}")] - Signing( - #[from] - #[source] - SecretError, - ), - - #[error("Missing Argument")] - MissingArgument(String), - - #[error("Not found")] - NotFound, - - #[error("Could not build transaction {0}")] - InvalidTransaction( - #[from] - #[source] - TransactionError, - ), + #[error("Operation cancelled {0}")] + Cancelled(oneshot::Canceled), + + #[error("Communication error: {0}")] + Communication( + #[from] + #[source] + SubxtClientError, + ), + + #[error("IO error: {0}")] + IO( + #[from] + #[source] + std::io::Error, + ), + + #[error("Json error: {0}")] + Json( + #[from] + #[source] + serde_json::Error, + ), + + #[error("Pkcs8 error")] + Pkcs8, + + #[error("Transaction failed: {0}")] + TransactionFailed(String), + + #[error("Transaction not found after wait: {0}")] + TransactionNotFound(ChronicleTransactionId), + + #[error("Error loading from URL: {0}")] + Url( + #[from] + #[source] + FromUrlError, + ), + + #[error("Utf8 error: {0}")] + Utf8( + #[from] + #[source] + std::str::Utf8Error, + ), + + #[error("Signing: {0}")] + Signing( + #[from] + #[source] + SecretError, + ), + + #[error("Missing Argument")] + MissingArgument(String), + + #[error("Not found")] + NotFound, + + #[error("Could not build transaction {0}")] + InvalidTransaction( + #[from] + #[source] + TransactionError, + ), } impl From for OpaCtlError { - fn from(_: Infallible) -> Self { - unreachable!() - } + fn from(_: Infallible) -> Self { + unreachable!() + } } impl UFE for OpaCtlError {} #[derive(Debug, Serialize)] pub enum Waited { - NoWait, - WaitedAndFound(OpaEvent), - WaitedAndDidNotFind, + NoWait, + WaitedAndFound(OpaEvent), + WaitedAndDidNotFind, } // Collect incoming transaction ids before running submission, as there is the /// potential to miss transactions if we do not collect them 'before' submission async fn ambient_transactions< - R: LedgerReader + Send + Sync + Clone + 'static, + R: LedgerReader + Send + Sync + Clone + 'static, >( - client: &R, - goal_tx_id: ChronicleTransactionId, - max_steps: u32, -) -> impl Future> { - let span = span!(Level::DEBUG, "wait_for_opa_transaction"); - let client = client.clone(); - // Set up a oneshot channel to notify the returned task - let (notify_tx, notify_rx) = oneshot::channel::(); - - // And a oneshot channel to ensure we are receiving events from the chain - // before we return - let (receiving_events_tx, receiving_events_rx) = oneshot::channel::<()>(); - - Handle::current().spawn(async move { + client: &R, + goal_tx_id: ChronicleTransactionId, + max_steps: u32, +) -> impl Future> { + let span = span!(Level::DEBUG, "wait_for_opa_transaction"); + let client = client.clone(); + // Set up a oneshot channel to notify the returned task + let (notify_tx, notify_rx) = oneshot::channel::(); + + // And a oneshot channel to ensure we are receiving events from the chain + // before we return + let (receiving_events_tx, receiving_events_rx) = oneshot::channel::<()>(); + + Handle::current().spawn(async move { // We can immediately return if we are not waiting debug!(waiting_for=?goal_tx_id, max_steps=?max_steps); let goal_clone = goal_tx_id; @@ -187,245 +188,245 @@ async fn ambient_transactions< } }.instrument(span)); - // Wait for the task to start receiving events - let _ = receiving_events_rx.await; + // Wait for the task to start receiving events + let _ = receiving_events_rx.await; - notify_rx + notify_rx } #[instrument(skip(client, matches, submission))] async fn handle_wait< - CLIENT: LedgerReader - + LedgerWriter - + Clone - + Send - + Sync - + 'static, + CLIENT: LedgerReader + + LedgerWriter + + Clone + + Send + + Sync + + 'static, >( - matches: &ArgMatches, - client: &CLIENT, - submission: OpaTransaction, + matches: &ArgMatches, + client: &CLIENT, + submission: OpaTransaction, ) -> Result { - let wait = Wait::from_matches(matches); - match wait { - Wait::NoWait => { - let (ext, id) = client.pre_submit(submission).await?; - client - .do_submit(protocol_abstract::WriteConsistency::Weak, ext) - .await - .map_err(|(e, _id)| e)?; - - Ok(Waited::NoWait) - }, - Wait::NumberOfBlocks(blocks) => { - let (ext, tx_id) = client.pre_submit(submission).await?; - let waiter = ambient_transactions(client, tx_id, blocks).await; - client - .do_submit(protocol_abstract::WriteConsistency::Strong, ext) - .await - .map_err(|(e, _id)| e)?; - debug!(awaiting_tx=%tx_id, waiting_blocks=%blocks); - match waiter.await { - Ok(Waited::WaitedAndDidNotFind) => Err(OpaCtlError::TransactionNotFound(tx_id)), - Ok(x) => Ok(x), - Err(e) => Err(OpaCtlError::Cancelled(e)), - } - }, - } + let wait = Wait::from_matches(matches); + match wait { + Wait::NoWait => { + let (ext, _) = client.pre_submit(submission).await?; + client + .do_submit(protocol_abstract::WriteConsistency::Weak, ext) + .await + .map_err(|(e, _id)| e)?; + + Ok(Waited::NoWait) + } + Wait::NumberOfBlocks(blocks) => { + let (ext, tx_id) = client.pre_submit(submission).await?; + let waiter = ambient_transactions(client, tx_id, blocks).await; + client + .do_submit(protocol_abstract::WriteConsistency::Strong, ext) + .await + .map_err(|(e, _id)| e)?; + debug!(awaiting_tx=%tx_id, waiting_blocks=%blocks); + match waiter.await { + Ok(Waited::WaitedAndDidNotFind) => Err(OpaCtlError::TransactionNotFound(tx_id)), + Ok(x) => Ok(x), + Err(e) => Err(OpaCtlError::Cancelled(e)), + } + } + } } async fn dispatch_args< - CLIENT: LedgerWriter - + Send - + Sync - + LedgerReader - + SubstrateStateReader - + Clone - + 'static, + CLIENT: LedgerWriter + + Send + + Sync + + LedgerReader + + SubstrateStateReader + + Clone + + 'static, >( - matches: ArgMatches, - client: &CLIENT, + matches: ArgMatches, + client: &CLIENT, ) -> Result { - let span = span!(Level::TRACE, "dispatch_args"); - let _entered = span.enter(); - let span_id = span.id().map(|x| x.into_u64()).unwrap_or(u64::MAX); - match matches.subcommand() { - Some(("bootstrap", command_matches)) => { - let signing = configure_signing(vec![], &matches, command_matches).await?; - let bootstrap = SubmissionBuilder::bootstrap_root(signing.opa_verifying().await?) - .build(span_id, Uuid::new_v4()); - Ok(handle_wait( - command_matches, - client, - OpaTransaction::bootstrap_root(bootstrap, &signing).await?, - ) - .await?) - }, - Some(("generate", matches)) => { - let key = SecretKey::random(StdRng::from_entropy()); - let key = key.to_pkcs8_pem(LineEnding::CRLF).map_err(|_| OpaCtlError::Pkcs8)?; - - if let Some(path) = matches.get_one::("output") { - let mut file = File::create(path)?; - file.write_all(key.as_bytes())?; - } else { - print!("{}", *key); - } - - Ok(Waited::NoWait) - }, - Some(("rotate-root", command_matches)) => { - let signing = - configure_signing(vec!["new-root-key"], &matches, command_matches).await?; - let rotate_key = SubmissionBuilder::rotate_key( - "root", - &signing, - OPA_PK, - command_matches - .get_one::("new-root-key") - .ok_or_else(|| OpaCtlError::MissingArgument("new-root-key".to_owned()))?, - ) - .await? - .build(span_id, Uuid::new_v4()); - Ok(handle_wait( - command_matches, - client, - OpaTransaction::rotate_root(rotate_key, &signing).await?, - ) - .await?) - }, - Some(("register-key", command_matches)) => { - let signing = configure_signing(vec!["new-key"], &matches, command_matches).await?; - let new_key = &command_matches - .get_one::("new-key") - .ok_or_else(|| OpaCtlError::MissingArgument("new-key".to_owned()))?; - let id = command_matches.get_one::("id").unwrap(); - let overwrite_existing = command_matches.get_flag("overwrite"); - let register_key = - SubmissionBuilder::register_key(id, new_key, &signing, overwrite_existing) - .await? - .build(span_id, Uuid::new_v4()); - Ok(handle_wait( - command_matches, - client, - OpaTransaction::register_key(id, register_key, &signing, overwrite_existing) - .await?, - ) - .await?) - }, - Some(("rotate-key", command_matches)) => { - let signing = - configure_signing(vec!["current-key", "new-key"], &matches, command_matches) - .await?; - - let current_key = &command_matches - .get_one::("current-key") - .ok_or_else(|| OpaCtlError::MissingArgument("new-key".to_owned()))?; - let new_key = &command_matches - .get_one::("new-key") - .ok_or_else(|| OpaCtlError::MissingArgument("new-key".to_owned()))?; - let id = command_matches.get_one::("id").unwrap(); - let rotate_key = SubmissionBuilder::rotate_key(id, &signing, new_key, current_key) - .await? - .build(span_id, Uuid::new_v4()); - Ok(handle_wait( - command_matches, - client, - OpaTransaction::rotate_key(id, rotate_key, &signing).await?, - ) - .await?) - }, - Some(("set-policy", command_matches)) => { - let signing = configure_signing(vec![], &matches, command_matches).await?; - let policy: &String = command_matches.get_one("policy").unwrap(); - - let policy = load_bytes_from_url(policy).await?; - - let id = command_matches.get_one::("id").unwrap(); - - let bootstrap = SubmissionBuilder::set_policy(id, policy, &signing) - .await? - .build(span_id, Uuid::new_v4()); - Ok(handle_wait( - command_matches, - client, - OpaTransaction::set_policy(id, bootstrap, &signing).await?, - ) - .await?) - }, - Some(("get-key", matches)) => { - let key: Result, _> = client - .get_state_entry( - "Opa", - "KeyStore", - key_address(matches.get_one::("id").unwrap()), - ) - .await; - - let key: KeysV1 = key.map_err(OpaCtlError::from)?.ok_or(OpaCtlError::NotFound)?; - let key = Keys::try_from(key)?; - - debug!(loaded_key = ?key); - - let key = key.current.key; - - if let Some(path) = matches.get_one::("output") { - let mut file = File::create(path)?; - file.write_all(key.as_bytes())?; - } else { - print!("{}", key.as_str()); - } - - Ok(Waited::NoWait) - }, - Some(("get-policy", matches)) => { - let policy: Option = client - .get_state_entry( - "Opa", - "PolicyStore", - key_address(matches.get_one::("id").unwrap()), - ) - .await?; - - let policy = policy.ok_or(OpaCtlError::NotFound)?; - - if let Some(path) = matches.get_one::("output") { - let mut file = File::create(path)?; - file.write_all(Policy::try_from(policy)?.as_bytes())?; - } - - Ok(Waited::NoWait) - }, - _ => Ok(Waited::NoWait), - } + let span = span!(Level::TRACE, "dispatch_args"); + let _entered = span.enter(); + let span_id = span.id().map(|x| x.into_u64()).unwrap_or(u64::MAX); + match matches.subcommand() { + Some(("bootstrap", command_matches)) => { + let signing = configure_signing(vec![], &matches, command_matches).await?; + let bootstrap = SubmissionBuilder::bootstrap_root(signing.opa_verifying().await?) + .build(span_id, Uuid::new_v4()); + Ok(handle_wait( + command_matches, + client, + OpaTransaction::bootstrap_root(bootstrap, &signing).await?, + ) + .await?) + } + Some(("generate", matches)) => { + let key = SecretKey::random(StdRng::from_entropy()); + let key = key.to_pkcs8_pem(LineEnding::CRLF).map_err(|_| OpaCtlError::Pkcs8)?; + + if let Some(path) = matches.get_one::("output") { + let mut file = File::create(path)?; + file.write_all(key.as_bytes())?; + } else { + print!("{}", *key); + } + + Ok(Waited::NoWait) + } + Some(("rotate-root", command_matches)) => { + let signing = + configure_signing(vec!["new-root-key"], &matches, command_matches).await?; + let rotate_key = SubmissionBuilder::rotate_key( + "root", + &signing, + OPA_PK, + command_matches + .get_one::("new-root-key") + .ok_or_else(|| OpaCtlError::MissingArgument("new-root-key".to_owned()))?, + ) + .await? + .build(span_id, Uuid::new_v4()); + Ok(handle_wait( + command_matches, + client, + OpaTransaction::rotate_root(rotate_key, &signing).await?, + ) + .await?) + } + Some(("register-key", command_matches)) => { + let signing = configure_signing(vec!["new-key"], &matches, command_matches).await?; + let new_key = &command_matches + .get_one::("new-key") + .ok_or_else(|| OpaCtlError::MissingArgument("new-key".to_owned()))?; + let id = command_matches.get_one::("id").unwrap(); + let overwrite_existing = command_matches.get_flag("overwrite"); + let register_key = + SubmissionBuilder::register_key(id, new_key, &signing, overwrite_existing) + .await? + .build(span_id, Uuid::new_v4()); + Ok(handle_wait( + command_matches, + client, + OpaTransaction::register_key(id, register_key, &signing, overwrite_existing) + .await?, + ) + .await?) + } + Some(("rotate-key", command_matches)) => { + let signing = + configure_signing(vec!["current-key", "new-key"], &matches, command_matches) + .await?; + + let current_key = &command_matches + .get_one::("current-key") + .ok_or_else(|| OpaCtlError::MissingArgument("new-key".to_owned()))?; + let new_key = &command_matches + .get_one::("new-key") + .ok_or_else(|| OpaCtlError::MissingArgument("new-key".to_owned()))?; + let id = command_matches.get_one::("id").unwrap(); + let rotate_key = SubmissionBuilder::rotate_key(id, &signing, new_key, current_key) + .await? + .build(span_id, Uuid::new_v4()); + Ok(handle_wait( + command_matches, + client, + OpaTransaction::rotate_key(id, rotate_key, &signing).await?, + ) + .await?) + } + Some(("set-policy", command_matches)) => { + let signing = configure_signing(vec![], &matches, command_matches).await?; + let policy: &String = command_matches.get_one("policy").unwrap(); + + let policy = load_bytes_from_url(policy).await?; + + let id = command_matches.get_one::("id").unwrap(); + + let bootstrap = SubmissionBuilder::set_policy(id, policy, &signing) + .await? + .build(span_id, Uuid::new_v4()); + Ok(handle_wait( + command_matches, + client, + OpaTransaction::set_policy(id, bootstrap, &signing).await?, + ) + .await?) + } + Some(("get-key", matches)) => { + let key: Result, _> = client + .get_state_entry( + "Opa", + "KeyStore", + key_address(matches.get_one::("id").unwrap()), + ) + .await; + + let key: KeysV1 = key.map_err(OpaCtlError::from)?.ok_or(OpaCtlError::NotFound)?; + let key = Keys::try_from(key)?; + + debug!(loaded_key = ?key); + + let key = key.current.key; + + if let Some(path) = matches.get_one::("output") { + let mut file = File::create(path)?; + file.write_all(key.as_bytes())?; + } else { + print!("{}", key.as_str()); + } + + Ok(Waited::NoWait) + } + Some(("get-policy", matches)) => { + let policy: Option = client + .get_state_entry( + "Opa", + "PolicyStore", + key_address(matches.get_one::("id").unwrap()), + ) + .await?; + + let policy = policy.ok_or(OpaCtlError::NotFound)?; + + if let Some(path) = matches.get_one::("output") { + let mut file = File::create(path)?; + file.write_all(Policy::try_from(policy)?.as_bytes())?; + } + + Ok(Waited::NoWait) + } + _ => Ok(Waited::NoWait), + } } #[tokio::main] async fn main() { - chronicle_telemetry::telemetry(None, chronicle_telemetry::ConsoleLogging::Pretty); - let args = cli::cli().get_matches(); - let address: &Url = args.get_one("sawtooth-address").unwrap(); - let client = match OpaSubstrateClient::::connect(address).await { - Ok(client) => client, - Err(e) => { - error!("Failed to connect to the OPA Substrate Client: {:?}", e); - std::process::exit(-1); - }, - }; - dispatch_args(args, &client) - .await - .map_err(|opactl| { - error!(?opactl); - opactl.into_ufe().print(); - std::process::exit(1); - }) - .map(|waited| { - if let Waited::WaitedAndFound(op) = waited { - println!( - "{}", - serde_json::to_string_pretty(&serde_json::to_value(op).unwrap()).unwrap() - ); - } - }) - .ok(); + chronicle_telemetry::telemetry(false, chronicle_telemetry::ConsoleLogging::Pretty); + let args = cli::cli().get_matches(); + let address: &Url = args.get_one("sawtooth-address").unwrap(); + let client = match OpaSubstrateClient::::connect(address).await { + Ok(client) => client, + Err(e) => { + error!("Failed to connect to the OPA Substrate Client: {:?}", e); + std::process::exit(-1); + } + }; + dispatch_args(args, &client) + .await + .map_err(|opactl| { + error!(?opactl); + opactl.into_ufe().print(); + std::process::exit(1); + }) + .map(|waited| { + if let Waited::WaitedAndFound(op) = waited { + println!( + "{}", + serde_json::to_string_pretty(&serde_json::to_value(op).unwrap()).unwrap() + ); + } + }) + .ok(); } diff --git a/crates/opactl/src/test/mockchain.rs b/crates/opactl/src/test/mockchain.rs index 96e107509..a29dfd4d8 100644 --- a/crates/opactl/src/test/mockchain.rs +++ b/crates/opactl/src/test/mockchain.rs @@ -1,8 +1,8 @@ use frame_support::traits::{ConstU16, ConstU64}; use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, + BuildStorage, + traits::{BlakeTwo256, IdentityLookup}, }; type Block = frame_system::mocking::MockBlock; @@ -17,38 +17,38 @@ frame_support::construct_runtime!( ); impl frame_system::Config for Test { - type AccountData = (); - type AccountId = u64; - type BaseCallFilter = frame_support::traits::Everything; - type Block = Block; - type BlockHashCount = ConstU64<250>; - type BlockLength = (); - type BlockWeights = (); - type DbWeight = (); - type Hash = H256; - type Hashing = BlakeTwo256; - type Lookup = IdentityLookup; - type MaxConsumers = frame_support::traits::ConstU32<16>; - type Nonce = u64; - type OnKilledAccount = (); - type OnNewAccount = (); - type OnSetCode = (); - type PalletInfo = PalletInfo; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type RuntimeOrigin = RuntimeOrigin; - type SS58Prefix = ConstU16<42>; - type SystemWeightInfo = (); - type Version = (); + type AccountData = (); + type AccountId = u64; + type BaseCallFilter = frame_support::traits::Everything; + type Block = Block; + type BlockHashCount = ConstU64<250>; + type BlockLength = (); + type BlockWeights = (); + type DbWeight = (); + type Hash = H256; + type Hashing = BlakeTwo256; + type Lookup = IdentityLookup; + type MaxConsumers = frame_support::traits::ConstU32<16>; + type Nonce = u64; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = (); + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = ConstU16<42>; + type SystemWeightInfo = (); + type Version = (); } impl pallet_opa::Config for Test { - type OpaSubmission = common::opa::codec::OpaSubmissionV1; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); + type OpaSubmission = common::opa::codec::OpaSubmissionV1; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } // Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - frame_system::GenesisConfig::::default().build_storage().unwrap().into() + frame_system::GenesisConfig::::default().build_storage().unwrap().into() } diff --git a/crates/opactl/src/test/mod.rs b/crates/opactl/src/test/mod.rs index e703d3ec5..971f32fa0 100644 --- a/crates/opactl/src/test/mod.rs +++ b/crates/opactl/src/test/mod.rs @@ -1,53 +1,51 @@ -mod mockchain; -mod stubstrate; +use std::io::Write; use clap::ArgMatches; - use k256::{ - pkcs8::{EncodePrivateKey, LineEnding}, - SecretKey, + pkcs8::{EncodePrivateKey, LineEnding}, + SecretKey, }; - use rand::rngs::StdRng; use rand_core::SeedableRng; - -use std::io::Write; use tempfile::{NamedTempFile, TempDir}; use crate::{cli, dispatch_args}; use self::stubstrate::Stubstrate; +mod mockchain; +mod stubstrate; + fn get_opactl_cmd(command_line: &str) -> ArgMatches { - let cli = cli::cli(); - cli.get_matches_from(command_line.split_whitespace()) + let cli = cli::cli(); + cli.get_matches_from(command_line.split_whitespace()) } fn key_from_seed(seed: u8) -> String { - let secret: SecretKey = SecretKey::random(StdRng::from_seed([seed; 32])); - secret.to_pkcs8_pem(LineEnding::CRLF).unwrap().to_string() + let secret: SecretKey = SecretKey::random(StdRng::from_seed([seed; 32])); + secret.to_pkcs8_pem(LineEnding::CRLF).unwrap().to_string() } // Cli should automatically create ephemeral batcher keys, but we need to supply named keyfiles // in a temp directory async fn bootstrap_root_state() -> (String, Stubstrate, TempDir) { - let root_key = key_from_seed(0); + let root_key = key_from_seed(0); - let keystore = tempfile::tempdir().unwrap(); - let keyfile_path = keystore.path().join("./opa-pk"); - std::fs::write(&keyfile_path, root_key.as_bytes()).unwrap(); + let keystore = tempfile::tempdir().unwrap(); + let keyfile_path = keystore.path().join("./opa-pk"); + std::fs::write(&keyfile_path, root_key.as_bytes()).unwrap(); - let matches = get_opactl_cmd(&format!( - "opactl --batcher-key-generated --keystore-path {} bootstrap", - keystore.path().display() - )); + let matches = get_opactl_cmd(&format!( + "opactl --batcher-key-generated --keystore-path {} bootstrap", + keystore.path().display() + )); - let stubstrate = Stubstrate::new(); + let stubstrate = Stubstrate::new(); - tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; - dispatch_args(matches, &stubstrate).await.unwrap(); + tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; + dispatch_args(matches, &stubstrate).await.unwrap(); - (root_key, stubstrate, keystore) + (root_key, stubstrate, keystore) } @@ -55,9 +53,9 @@ async fn bootstrap_root_state() -> (String, Stubstrate, TempDir) { #[tokio::test] #[ignore] async fn bootstrap_root_and_get_key() { - let (_root_key, opa_tp, _keystore) = bootstrap_root_state().await; - //Generate a key pem and set env vars - insta::assert_yaml_snapshot!(opa_tp.stored_keys(), { + let (_root_key, opa_tp, _keystore) = bootstrap_root_state().await; + //Generate a key pem and set env vars + insta::assert_yaml_snapshot!(opa_tp.stored_keys(), { ".**.date" => "[date]", ".**.key" => "[pem]", } ,@r###" @@ -69,15 +67,15 @@ async fn bootstrap_root_and_get_key() { expired: ~ "###); - tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; + tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; - let out_keyfile = NamedTempFile::new().unwrap(); + let out_keyfile = NamedTempFile::new().unwrap(); - let matches = get_opactl_cmd( - format!("opactl get-key --output {}", out_keyfile.path().display(),).as_str(), - ); + let matches = get_opactl_cmd( + format!("opactl get-key --output {}", out_keyfile.path().display(), ).as_str(), + ); - insta::assert_yaml_snapshot!( + insta::assert_yaml_snapshot!( dispatch_args(matches, &opa_tp) .await .unwrap(), @r###" @@ -88,22 +86,22 @@ async fn bootstrap_root_and_get_key() { #[tokio::test] async fn rotate_root() { - let (_root_key, opa_tp, keystore) = bootstrap_root_state().await; + let (_root_key, opa_tp, keystore) = bootstrap_root_state().await; - let new_root_key = key_from_seed(1); + let new_root_key = key_from_seed(1); - let keyfile_path = keystore.path().join("./new-root-1"); - std::fs::write(&keyfile_path, new_root_key.as_bytes()).unwrap(); + let keyfile_path = keystore.path().join("./new-root-1"); + std::fs::write(&keyfile_path, new_root_key.as_bytes()).unwrap(); - let matches = get_opactl_cmd( - format!( - "opactl --batcher-key-generated --opa-key-from-path --keystore-path {} rotate-root --new-root-key new-root-1", - keystore.path().display(), - ) + let matches = get_opactl_cmd( + format!( + "opactl --batcher-key-generated --opa-key-from-path --keystore-path {} rotate-root --new-root-key new-root-1", + keystore.path().display(), + ) .as_str(), - ); + ); - insta::assert_yaml_snapshot!( + insta::assert_yaml_snapshot!( dispatch_args(matches, &opa_tp) .await .unwrap(), { @@ -125,7 +123,7 @@ async fn rotate_root() { correlation_id: "[correlation_id]" "###); - insta::assert_yaml_snapshot!(opa_tp.stored_keys(),{ + insta::assert_yaml_snapshot!(opa_tp.stored_keys(),{ ".**.date" => "[date]", ".**.key" => "[pem]", ".**.correlation_id" => "[correlation_id]" @@ -143,22 +141,22 @@ async fn rotate_root() { #[tokio::test] async fn register_and_rotate_key() { - let (_root_key, opa_tp, keystore) = bootstrap_root_state().await; + let (_root_key, opa_tp, keystore) = bootstrap_root_state().await; - let new_key = key_from_seed(1); + let new_key = key_from_seed(1); - let keyfile_path = keystore.path().join("./new-key-1"); - std::fs::write(&keyfile_path, new_key.as_bytes()).unwrap(); + let keyfile_path = keystore.path().join("./new-key-1"); + std::fs::write(&keyfile_path, new_key.as_bytes()).unwrap(); - let matches = get_opactl_cmd( - format!( - "opactl --batcher-key-generated --keystore-path {} register-key --new-key new-key-1 --id test", - keystore.path().display(), - ) + let matches = get_opactl_cmd( + format!( + "opactl --batcher-key-generated --keystore-path {} register-key --new-key new-key-1 --id test", + keystore.path().display(), + ) .as_str(), - ); + ); - insta::assert_yaml_snapshot!( + insta::assert_yaml_snapshot!( dispatch_args(matches,&opa_tp) .await .unwrap(), { @@ -178,7 +176,7 @@ async fn register_and_rotate_key() { correlation_id: "[correlation_id]" "###); - insta::assert_yaml_snapshot!(opa_tp.stored_keys(), { + insta::assert_yaml_snapshot!(opa_tp.stored_keys(), { ".**.date" => "[date]", ".**.key" => "[pem]", ".**.correlation_id" => "[correlation_id]" @@ -196,20 +194,20 @@ async fn register_and_rotate_key() { expired: ~ "###); - let new_key_2 = key_from_seed(1); + let new_key_2 = key_from_seed(1); - let keyfile_path = keystore.path().join("./new-key-2"); - std::fs::write(&keyfile_path, new_key_2.as_bytes()).unwrap(); + let keyfile_path = keystore.path().join("./new-key-2"); + std::fs::write(&keyfile_path, new_key_2.as_bytes()).unwrap(); - let matches = get_opactl_cmd( - format!( - "opactl --batcher-key-generated --keystore-path {} rotate-key --current-key new-key-1 --new-key new-key-2 --id test", - keystore.path().display(), - ) + let matches = get_opactl_cmd( + format!( + "opactl --batcher-key-generated --keystore-path {} rotate-key --current-key new-key-1 --new-key new-key-2 --id test", + keystore.path().display(), + ) .as_str(), - ); + ); - insta::assert_yaml_snapshot!( + insta::assert_yaml_snapshot!( dispatch_args(matches, &opa_tp) .await .unwrap(), { @@ -231,7 +229,7 @@ async fn register_and_rotate_key() { correlation_id: "[correlation_id]" "###); - insta::assert_yaml_snapshot!(opa_tp.stored_keys(), { + insta::assert_yaml_snapshot!(opa_tp.stored_keys(), { ".**.date" => "[date]", ".**.key" => "[pem]", ".**.correlation_id" => "[correlation_id]" @@ -254,24 +252,24 @@ async fn register_and_rotate_key() { #[tokio::test] async fn set_and_update_policy() { - let (root_key, opa_tp, keystore) = bootstrap_root_state().await; + let (root_key, opa_tp, keystore) = bootstrap_root_state().await; - let mut root_keyfile = NamedTempFile::new().unwrap(); - root_keyfile.write_all(root_key.as_bytes()).unwrap(); + let mut root_keyfile = NamedTempFile::new().unwrap(); + root_keyfile.write_all(root_key.as_bytes()).unwrap(); - let mut policy = NamedTempFile::new().unwrap(); - policy.write_all(&[0]).unwrap(); + let mut policy = NamedTempFile::new().unwrap(); + policy.write_all(&[0]).unwrap(); - let matches = get_opactl_cmd( - format!( - "opactl --batcher-key-generated --keystore-path {} set-policy --id test --policy {}", - keystore.path().display(), - policy.path().display() - ) - .as_str(), - ); + let matches = get_opactl_cmd( + format!( + "opactl --batcher-key-generated --keystore-path {} set-policy --id test --policy {}", + keystore.path().display(), + policy.path().display() + ) + .as_str(), + ); - insta::assert_yaml_snapshot!(dispatch_args( + insta::assert_yaml_snapshot!(dispatch_args( matches, &opa_tp, ) @@ -322,7 +320,7 @@ async fn set_and_update_policy() { correlation_id: "[correlation_id]" "###); - insta::assert_yaml_snapshot!(opa_tp.stored_policy(), { + insta::assert_yaml_snapshot!(opa_tp.stored_policy(), { ".**.date" => "[date]", ".**.key" => "[pem]", ".**.correlation_id" => "[correlation_id]", @@ -365,18 +363,18 @@ async fn set_and_update_policy() { - 230 "###); - policy.write_all(&[1]).unwrap(); + policy.write_all(&[1]).unwrap(); - let matches = get_opactl_cmd( - format!( - "opactl --batcher-key-generated --keystore-path {} set-policy --id test --policy {}", - keystore.path().display(), - policy.path().display() - ) - .as_str(), - ); + let matches = get_opactl_cmd( + format!( + "opactl --batcher-key-generated --keystore-path {} set-policy --id test --policy {}", + keystore.path().display(), + policy.path().display() + ) + .as_str(), + ); - insta::assert_yaml_snapshot!(dispatch_args(matches, &opa_tp) + insta::assert_yaml_snapshot!(dispatch_args(matches, &opa_tp) .await .unwrap(), { ".**.date" => "[date]", @@ -424,7 +422,7 @@ async fn set_and_update_policy() { correlation_id: "[correlation_id]" "### ); - insta::assert_yaml_snapshot!(opa_tp.stored_policy(), { + insta::assert_yaml_snapshot!(opa_tp.stored_policy(), { ".**.date" => "[date]", ".**.key" => "[pem]", } ,@r###" diff --git a/crates/opactl/src/test/stubstrate.rs b/crates/opactl/src/test/stubstrate.rs index eeb7dfaf6..93617e6c5 100644 --- a/crates/opactl/src/test/stubstrate.rs +++ b/crates/opactl/src/test/stubstrate.rs @@ -1,16 +1,17 @@ -use common::opa::{codec::OpaSubmissionV1, Keys, PolicyMeta}; +use std::sync::{Arc, Mutex}; + use frame_support::StoragePrefixedMap; use futures::{stream::BoxStream, StreamExt}; -use pallet_opa::{ChronicleTransactionId, Event}; +use subxt::metadata::{DecodeWithMetadata, EncodeWithMetadata}; +use common::opa::{codec::OpaSubmissionV1, Keys, PolicyMeta}; +use pallet_opa::{ChronicleTransactionId, Event}; use protocol_abstract::{ - BlockId, FromBlock, LedgerEvent, LedgerEventContext, LedgerReader, LedgerTransaction, - LedgerWriter, Position, Span, WriteConsistency, + BlockId, FromBlock, LedgerEvent, LedgerEventContext, LedgerReader, LedgerTransaction, + LedgerWriter, Position, Span, WriteConsistency, }; use protocol_substrate::{PolkadotConfig, SubstrateStateReader, SubxtClientError}; -use protocol_substrate_opa::{transaction::OpaTransaction, OpaEvent, OpaEventCodec}; -use std::sync::{Arc, Mutex}; -use subxt::metadata::{DecodeWithMetadata, EncodeWithMetadata}; +use protocol_substrate_opa::{OpaEvent, OpaEventCodec, transaction::OpaTransaction}; use crate::test::mockchain::System; @@ -18,144 +19,144 @@ use super::mockchain::{new_test_ext, OpaModule, RuntimeEvent, RuntimeOrigin, Tes #[derive(Clone)] pub struct Stubstrate { - rt: Arc>, - tx: tokio::sync::broadcast::Sender, - events: Arc>>, + rt: Arc>, + tx: tokio::sync::broadcast::Sender, + events: Arc>>, } impl Stubstrate { - pub fn new() -> Self { - let (tx, rx) = tokio::sync::broadcast::channel(100); - Self { rt: Arc::new(Mutex::new(new_test_ext())), tx, events: Arc::new(Mutex::new(vec![])) } - } - - #[tracing::instrument(skip(self))] - pub fn readable_events(&self) -> Vec { - self.events.lock().unwrap().clone() - } - - pub fn stored_keys(&self) -> Vec { - self.rt.lock().unwrap().execute_with(|| { - pallet_opa::KeyStore::::iter_values() - .map(|k| k.try_into().unwrap()) - .collect() - }) - } - - pub fn stored_policy(&self) -> Vec { - self.rt.lock().unwrap().execute_with(|| { - pallet_opa::PolicyMetaStore::::iter_values() - .map(|k| k.try_into().unwrap()) - .collect() - }) - } + pub fn new() -> Self { + let (tx, rx) = tokio::sync::broadcast::channel(100); + Self { rt: Arc::new(Mutex::new(new_test_ext())), tx, events: Arc::new(Mutex::new(vec![])) } + } + + #[tracing::instrument(skip(self))] + pub fn readable_events(&self) -> Vec { + self.events.lock().unwrap().clone() + } + + pub fn stored_keys(&self) -> Vec { + self.rt.lock().unwrap().execute_with(|| { + pallet_opa::KeyStore::::iter_values() + .map(|k| k.try_into().unwrap()) + .collect() + }) + } + + pub fn stored_policy(&self) -> Vec { + self.rt.lock().unwrap().execute_with(|| { + pallet_opa::PolicyMetaStore::::iter_values() + .map(|k| k.try_into().unwrap()) + .collect() + }) + } } #[async_trait::async_trait] impl LedgerReader for Stubstrate { - type Error = SubxtClientError; - type Event = OpaEvent; - type EventCodec = OpaEventCodec; - - async fn block_height(&self) -> Result<(Position, BlockId), Self::Error> { - unimplemented!(); - } - - /// Subscribe to state updates from this ledger, starting at `offset`, and - /// ending the stream after `number_of_blocks` blocks have been processed. - async fn state_updates( - &self, - // The block to start from - from_block: FromBlock, - // The number of blocks to process before ending the stream - number_of_blocks: Option, - ) -> Result>, Self::Error> { - tracing::debug!("Starting state updates stream from block {:?}", from_block); - let rx = self.tx.subscribe(); - let stream = tokio_stream::wrappers::BroadcastStream::new(rx) - .map(|event| { - let event = event.unwrap(); - let correlation_id = event.correlation_id().into(); - (event, correlation_id, BlockId::Unknown, Position::from(0), Span::NotTraced) - }) - .boxed(); - Ok(stream) - } + type Error = SubxtClientError; + type Event = OpaEvent; + type EventCodec = OpaEventCodec; + + async fn block_height(&self) -> Result<(Position, BlockId), Self::Error> { + unimplemented!(); + } + + /// Subscribe to state updates from this ledger, starting at `offset`, and + /// ending the stream after `number_of_blocks` blocks have been processed. + async fn state_updates( + &self, + // The block to start from + from_block: FromBlock, + // The number of blocks to process before ending the stream + number_of_blocks: Option, + ) -> Result>, Self::Error> { + tracing::debug!("Starting state updates stream from block {:?}", from_block); + let rx = self.tx.subscribe(); + let stream = tokio_stream::wrappers::BroadcastStream::new(rx) + .map(|event| { + let event = event.unwrap(); + let correlation_id = event.correlation_id().into(); + (event, correlation_id, BlockId::Unknown, Position::from(0), Span::NotTraced) + }) + .boxed(); + Ok(stream) + } } #[async_trait::async_trait] impl LedgerWriter for Stubstrate { - type Error = SubxtClientError; - type Submittable = OpaTransaction; - type Transaction = OpaTransaction; - - // Minimally process the transaction offline to get a transaction id and submittable type - async fn pre_submit( - &self, - tx: Self::Transaction, - ) -> Result<(Self::Submittable, ChronicleTransactionId), Self::Error> { - let id = tx.correlation_id().into(); - Ok((tx, id)) - } - - // Submit is used to submit a transaction to the ledger - async fn do_submit( - &self, - _consistency: WriteConsistency, - submittable: Self::Submittable, - ) -> Result { - self.rt.lock().unwrap().execute_with(|| { - System::set_block_number(1); - OpaModule::apply( - RuntimeOrigin::signed(1), - OpaSubmissionV1::from(submittable.submission().clone()), - ) - .unwrap(); - - let ev = System::events().last().unwrap().event.clone(); - - let opa_event = match ev { - RuntimeEvent::OpaModule(event) => match event { - Event::::PolicyUpdate(meta, id) => Some(OpaEvent::PolicyUpdate { - policy: meta.try_into().unwrap(), - correlation_id: id, - }), - Event::::KeyUpdate(keys, id) => Some(OpaEvent::KeyUpdate { - keys: keys.try_into().unwrap(), - correlation_id: id, - }), - _ => None, - }, - _ => None, - }; - - if let Some(event) = opa_event { - self.events.lock().unwrap().push(event.clone()); - self.tx.send(event).unwrap(); - } else { - tracing::warn!("Received an event that is not an OpaEvent"); - } - }); - - Ok(submittable.correlation_id().into()) - } + type Error = SubxtClientError; + type Submittable = OpaTransaction; + type Transaction = OpaTransaction; + + // Minimally process the transaction offline to get a transaction id and submittable type + async fn pre_submit( + &self, + tx: Self::Transaction, + ) -> Result<(Self::Submittable, ChronicleTransactionId), Self::Error> { + let id = tx.correlation_id().into(); + Ok((tx, id)) + } + + // Submit is used to submit a transaction to the ledger + async fn do_submit( + &self, + _consistency: WriteConsistency, + submittable: Self::Submittable, + ) -> Result { + self.rt.lock().unwrap().execute_with(|| { + System::set_block_number(1); + OpaModule::apply( + RuntimeOrigin::signed(1), + OpaSubmissionV1::from(submittable.submission().clone()), + ) + .unwrap(); + + let ev = System::events().last().unwrap().event.clone(); + + let opa_event = match ev { + RuntimeEvent::OpaModule(event) => match event { + Event::::PolicyUpdate(meta, id) => Some(OpaEvent::PolicyUpdate { + policy: meta.try_into().unwrap(), + correlation_id: id, + }), + Event::::KeyUpdate(keys, id) => Some(OpaEvent::KeyUpdate { + keys: keys.try_into().unwrap(), + correlation_id: id, + }), + _ => None, + }, + _ => None, + }; + + if let Some(event) = opa_event { + self.events.lock().unwrap().push(event.clone()); + self.tx.send(event).unwrap(); + } else { + tracing::warn!("Received an event that is not an OpaEvent"); + } + }); + + Ok(submittable.correlation_id().into()) + } } #[async_trait::async_trait] impl SubstrateStateReader for Stubstrate { - type Error = SubxtClientError; - - async fn get_state_entry( - &self, - pallet_name: &str, - entry_name: &str, - address: K, - ) -> Result, Self::Error> { - tracing::info!( + type Error = SubxtClientError; + + async fn get_state_entry( + &self, + pallet_name: &str, + entry_name: &str, + address: K, + ) -> Result, Self::Error> { + tracing::info!( "Attempting to retrieve state entry for pallet: {}, entry: {}", pallet_name, entry_name ); - unimplemented!() - } + unimplemented!() + } } diff --git a/crates/pallet-chronicle/Cargo.toml b/crates/pallet-chronicle/Cargo.toml index 0ab3dd82a..f5b25aeb3 100644 --- a/crates/pallet-chronicle/Cargo.toml +++ b/crates/pallet-chronicle/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "pallet-chronicle" +name = "pallet-chronicle" version = "0.7.5" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -8,7 +8,7 @@ version = "0.7.5" [dependencies] common = { path = "../common", default-features = false, features = [ - "parity-encoding", + "parity-encoding", ] } frame-benchmarking = { version = "25.0.0", default-features = false, optional = true } frame-support = { version = "25.0.0", default-features = false } @@ -16,39 +16,39 @@ frame-system = { version = "25.0.0", default-features = false } macro-attr-2018 = { workspace = true } newtype-derive-2018 = { workspace = true } parity-scale-codec = { version = "^3.4.0", default-features = false, features = [ - "derive", + "derive", ] } scale-info = { version = "^2.10.0", default-features = false, features = [ - "derive", + "derive", ] } serde = { version = "1.0", default-features = false } sp-core = { version = "25.0.0", default-features = false } sp-core-hashing = { version = "14", default-features = false } sp-std = { version = "12.0.0", default-features = false } tracing = { version = "0.1", default-features = false, features = [ - "attributes", + "attributes", ] } uuid = { version = "1.5.0", default-features = false } [dev-dependencies] chronicle-telemetry = { path = "../chronicle-telemetry" } -sp-core = { version = "25.0.0" } -sp-io = { version = "27.0.0" } -sp-runtime = { version = "28.0.0" } -uuid = { version = "1.5.0", default-features = true } +sp-core = { version = "25.0.0" } +sp-io = { version = "27.0.0" } +sp-runtime = { version = "28.0.0" } +uuid = { version = "1.5.0", default-features = true } [features] default = ["std"] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] std = [ - "common/std", - "parity-scale-codec/std", - "uuid/std", - "sp-std/std", - "scale-info/std", - "frame-support/std", - "frame-system/std", - "frame-benchmarking/std", - "tracing/std", + "common/std", + "parity-scale-codec/std", + "uuid/std", + "sp-std/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", + "frame-benchmarking/std", + "tracing/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/crates/pallet-chronicle/src/lib.rs b/crates/pallet-chronicle/src/lib.rs index e3c130290..8a56ee007 100644 --- a/crates/pallet-chronicle/src/lib.rs +++ b/crates/pallet-chronicle/src/lib.rs @@ -20,221 +20,222 @@ mod tests; pub mod weights; pub mod chronicle_core { - pub use common::{ledger::*, prov::*}; + pub use common::{ledger::*, prov::*}; } + pub use weights::*; // A configuration type for opa settings, serializable to JSON etc #[derive(frame_support::Serialize, frame_support::Deserialize)] pub struct OpaConfiguration { - pub policy_name: scale_info::prelude::string::String, - pub entrypoint: scale_info::prelude::string::String, + pub policy_name: scale_info::prelude::string::String, + pub entrypoint: scale_info::prelude::string::String, } #[frame_support::pallet] pub mod pallet { - use super::*; - use common::ledger::OperationSubmission; - use frame_support::{pallet_prelude::*, traits::BuildGenesisConfig}; - use frame_system::pallet_prelude::*; - use sp_std::{collections::btree_set::BTreeSet, vec::Vec}; - - #[pallet::pallet] - pub struct Pallet(_); - - /// Configure the pallet by specifying the parameters and types on which it depends. - #[pallet::config] - pub trait Config: frame_system::Config { - /// Because this pallet emits events, it depends on the runtime's definition of an event. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Type representing the weight of this pallet - type WeightInfo: WeightInfo; - - type OperationSubmission: Parameter + Into + parity_scale_codec::Codec; - } - - /// Genesis configuration, whether or not we need to enforce OPA policies - #[pallet::genesis_config] - pub struct GenesisConfig { - pub opa_settings: Option, - pub _phantom: PhantomData, - } - - impl Default for GenesisConfig { - fn default() -> Self { - Self { opa_settings: None, _phantom: PhantomData } - } - } - - #[pallet::genesis_build] - impl BuildGenesisConfig for GenesisConfig { - fn build(&self) { - tracing::info!("Chronicle: Building genesis configuration."); - if let Some(ref settings) = self.opa_settings { - OpaSettings::::put(Some(common::opa::OpaSettings { - policy_address: common::opa::PolicyAddress::from(sp_core_hashing::blake2_128( - settings.policy_name.as_bytes(), - )), - policy_name: settings.policy_name.clone(), - entrypoint: settings.entrypoint.clone(), - })); - tracing::debug!("Chronicle: OPA settings are set."); - } else { - OpaSettings::::put(None::); - } - } - } - - #[pallet::storage] - #[pallet::getter(fn prov)] - pub type Provenance = StorageMap<_, Twox128, ChronicleAddress, common::prov::ProvModel>; - - #[pallet::storage] - #[pallet::getter(fn get_opa_settings)] - pub type OpaSettings = StorageValue<_, Option>; - - // Pallets use events to inform users when important changes are made. - // https://docs.substrate.io/main-docs/build/events-errors/ - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - Applied(common::prov::ProvModel, common::identity::SignedIdentity, [u8; 16]), - Contradiction(common::prov::Contradiction, common::identity::SignedIdentity, [u8; 16]), - } - - // Errors inform users that something went wrong. - #[pallet::error] - pub enum Error { - Address, - Contradiction, - Compaction, - Expansion, - Identity, - IRef, - NotAChronicleIri, - MissingId, - MissingProperty, - NotANode, - NotAnObject, - OpaExecutor, - SerdeJson, - SubmissionFormat, - Time, - Tokio, - Utf8, - } - - impl From for Error { - fn from(error: common::prov::ProcessorError) -> Self { - match error { - common::prov::ProcessorError::Address => Error::Address, - common::prov::ProcessorError::Contradiction { .. } => Error::Contradiction, - common::prov::ProcessorError::Identity(_) => Error::Identity, - common::prov::ProcessorError::NotAChronicleIri { .. } => Error::NotAChronicleIri, - common::prov::ProcessorError::MissingId { .. } => Error::MissingId, - common::prov::ProcessorError::MissingProperty { .. } => Error::MissingProperty, - common::prov::ProcessorError::NotANode(_) => Error::NotANode, - common::prov::ProcessorError::NotAnObject => Error::NotAnObject, - common::prov::ProcessorError::OpaExecutor(_) => Error::OpaExecutor, - common::prov::ProcessorError::SerdeJson(_) => Error::SerdeJson, - common::prov::ProcessorError::SubmissionFormat(_) => Error::SubmissionFormat, - common::prov::ProcessorError::Time(_) => Error::Time, - common::prov::ProcessorError::Tokio => Error::Tokio, - common::prov::ProcessorError::Utf8(_) => Error::Utf8, - _ => unreachable!(), - } - } - } - - // Dispatchable functions allows users to interact with the pallet and invoke state changes. - // These functions materialize as "extrinsics", which are often compared to transactions. - // Dispatchable functions must be annotated with a weight and must return a DispatchResult. - #[pallet::call] - impl Pallet { - // Apply a vector of chronicle operations, yielding an event that indicates state change or - // contradiction - #[pallet::call_index(0)] - #[pallet::weight({ - let weight = T::WeightInfo::operation_weight(&operations.items); - let dispatch_class = DispatchClass::Normal; - let pays_fee = Pays::No; - (weight, dispatch_class, pays_fee) - })] - pub fn apply(origin: OriginFor, operations: OperationSubmission) -> DispatchResult { - // Check that the extrinsic was signed and get the signer. - // This function will return an error if the extrinsic is not signed. - // https://docs.substrate.io/main-docs/build/origins/ - let _who = ensure_signed(origin)?; - - // Get operations and load tßheir dependencies - let deps = operations - .items - .iter() - .flat_map(|tx| tx.dependencies()) - .collect::>(); - - let initial_input_models: Vec<_> = deps - .into_iter() - .map(|addr| (addr.clone(), Provenance::::get(&addr))) - .collect(); - - let mut state: common::ledger::OperationState = common::ledger::OperationState::new(); - - state.update_state(initial_input_models.into_iter()); - - let mut model = common::prov::ProvModel::default(); - - for op in operations.items.iter() { - let res = op.process(model, state.input()); - match res { - // A contradiction raises an event, not an error and shortcuts processing - - // contradiction attempts are useful provenance and should not be a purely - // operational concern - Err(common::prov::ProcessorError::Contradiction(source)) => { - tracing::info!(contradiction = %source); - - Self::deposit_event(Event::::Contradiction( - source, - (*operations.identity).clone(), - operations.correlation_id, - )); - - return Ok(()); - }, - // Severe errors should be logged - Err(e) => { - tracing::error!(chronicle_prov_failure = %e); - - return Err(Error::::from(e).into()); - }, - Ok((tx_output, updated_model)) => { - state.update_state_from_output(tx_output.into_iter()); - model = updated_model; - }, - } - } - - // Compute delta - let dirty = state.dirty().collect::>(); - - tracing::trace!(dirty = ?dirty); - - let mut delta = common::prov::ProvModel::default(); - for common::ledger::StateOutput { address, data } in dirty { - delta.combine(&data); - - // Update storage. - Provenance::::set(&address, Some(data)); - } - - // Emit an event. - Self::deposit_event(Event::Applied( - delta, - (*operations.identity).clone(), - operations.correlation_id, - )); - // Return a successful DispatchResultWithPostInfo - Ok(()) - } - } + use super::*; + use common::ledger::OperationSubmission; + use frame_support::{pallet_prelude::*, traits::BuildGenesisConfig}; + use frame_system::pallet_prelude::*; + use sp_std::{collections::btree_set::BTreeSet, vec::Vec}; + + #[pallet::pallet] + pub struct Pallet(_); + + /// Configure the pallet by specifying the parameters and types on which it depends. + #[pallet::config] + pub trait Config: frame_system::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// Type representing the weight of this pallet + type WeightInfo: WeightInfo; + + type OperationSubmission: Parameter + Into + parity_scale_codec::Codec; + } + + /// Genesis configuration, whether or not we need to enforce OPA policies + #[pallet::genesis_config] + pub struct GenesisConfig { + pub opa_settings: Option, + pub _phantom: PhantomData, + } + + impl Default for GenesisConfig { + fn default() -> Self { + Self { opa_settings: None, _phantom: PhantomData } + } + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + tracing::info!("Chronicle: Building genesis configuration."); + if let Some(ref settings) = self.opa_settings { + OpaSettings::::put(Some(common::opa::OpaSettings { + policy_address: common::opa::PolicyAddress::from(sp_core_hashing::blake2_128( + settings.policy_name.as_bytes(), + )), + policy_name: settings.policy_name.clone(), + entrypoint: settings.entrypoint.clone(), + })); + tracing::debug!("Chronicle: OPA settings are set."); + } else { + OpaSettings::::put(None::); + } + } + } + + #[pallet::storage] + #[pallet::getter(fn prov)] + pub type Provenance = StorageMap<_, Twox128, ChronicleAddress, common::prov::ProvModel>; + + #[pallet::storage] + #[pallet::getter(fn get_opa_settings)] + pub type OpaSettings = StorageValue<_, Option>; + + // Pallets use events to inform users when important changes are made. + // https://docs.substrate.io/main-docs/build/events-errors/ + #[pallet::event] + #[pallet::generate_deposit(pub (super) fn deposit_event)] + pub enum Event { + Applied(common::prov::ProvModel, common::identity::SignedIdentity, [u8; 16]), + Contradiction(common::prov::Contradiction, common::identity::SignedIdentity, [u8; 16]), + } + + // Errors inform users that something went wrong. + #[pallet::error] + pub enum Error { + Address, + Contradiction, + Compaction, + Expansion, + Identity, + IRef, + NotAChronicleIri, + MissingId, + MissingProperty, + NotANode, + NotAnObject, + OpaExecutor, + SerdeJson, + SubmissionFormat, + Time, + Tokio, + Utf8, + } + + impl From for Error { + fn from(error: common::prov::ProcessorError) -> Self { + match error { + common::prov::ProcessorError::Address => Error::Address, + common::prov::ProcessorError::Contradiction { .. } => Error::Contradiction, + common::prov::ProcessorError::Identity(_) => Error::Identity, + common::prov::ProcessorError::NotAChronicleIri { .. } => Error::NotAChronicleIri, + common::prov::ProcessorError::MissingId { .. } => Error::MissingId, + common::prov::ProcessorError::MissingProperty { .. } => Error::MissingProperty, + common::prov::ProcessorError::NotANode(_) => Error::NotANode, + common::prov::ProcessorError::NotAnObject => Error::NotAnObject, + common::prov::ProcessorError::OpaExecutor(_) => Error::OpaExecutor, + common::prov::ProcessorError::SerdeJson(_) => Error::SerdeJson, + common::prov::ProcessorError::SubmissionFormat(_) => Error::SubmissionFormat, + common::prov::ProcessorError::Time(_) => Error::Time, + common::prov::ProcessorError::Tokio => Error::Tokio, + common::prov::ProcessorError::Utf8(_) => Error::Utf8, + _ => unreachable!(), + } + } + } + + // Dispatchable functions allows users to interact with the pallet and invoke state changes. + // These functions materialize as "extrinsics", which are often compared to transactions. + // Dispatchable functions must be annotated with a weight and must return a DispatchResult. + #[pallet::call] + impl Pallet { + // Apply a vector of chronicle operations, yielding an event that indicates state change or + // contradiction + #[pallet::call_index(0)] + #[pallet::weight({ + let weight = T::WeightInfo::operation_weight(& operations.items); + let dispatch_class = DispatchClass::Normal; + let pays_fee = Pays::No; + (weight, dispatch_class, pays_fee) + })] + pub fn apply(origin: OriginFor, operations: OperationSubmission) -> DispatchResult { + // Check that the extrinsic was signed and get the signer. + // This function will return an error if the extrinsic is not signed. + // https://docs.substrate.io/main-docs/build/origins/ + let _who = ensure_signed(origin)?; + + // Get operations and load tßheir dependencies + let deps = operations + .items + .iter() + .flat_map(|tx| tx.dependencies()) + .collect::>(); + + let initial_input_models: Vec<_> = deps + .into_iter() + .map(|addr| (addr.clone(), Provenance::::get(&addr))) + .collect(); + + let mut state: common::ledger::OperationState = common::ledger::OperationState::new(); + + state.update_state(initial_input_models.into_iter()); + + let mut model = common::prov::ProvModel::default(); + + for op in operations.items.iter() { + let res = op.process(model, state.input()); + match res { + // A contradiction raises an event, not an error and shortcuts processing - + // contradiction attempts are useful provenance and should not be a purely + // operational concern + Err(common::prov::ProcessorError::Contradiction(source)) => { + tracing::info!(contradiction = %source); + + Self::deposit_event(Event::::Contradiction( + source, + (*operations.identity).clone(), + operations.correlation_id, + )); + + return Ok(()); + } + // Severe errors should be logged + Err(e) => { + tracing::error!(chronicle_prov_failure = %e); + + return Err(Error::::from(e).into()); + } + Ok((tx_output, updated_model)) => { + state.update_state_from_output(tx_output.into_iter()); + model = updated_model; + } + } + } + + // Compute delta + let dirty = state.dirty().collect::>(); + + tracing::trace!(dirty = ?dirty); + + let mut delta = common::prov::ProvModel::default(); + for common::ledger::StateOutput { address, data } in dirty { + delta.combine(&data); + + // Update storage. + Provenance::::set(&address, Some(data)); + } + + // Emit an event. + Self::deposit_event(Event::Applied( + delta, + (*operations.identity).clone(), + operations.correlation_id, + )); + // Return a successful DispatchResultWithPostInfo + Ok(()) + } + } } diff --git a/crates/pallet-chronicle/src/mock.rs b/crates/pallet-chronicle/src/mock.rs index 038302859..e06b80987 100644 --- a/crates/pallet-chronicle/src/mock.rs +++ b/crates/pallet-chronicle/src/mock.rs @@ -3,8 +3,8 @@ use common::ledger::OperationSubmission; use frame_support::traits::{ConstU16, ConstU64}; use sp_core::H256; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, }; type Block = frame_system::mocking::MockBlock; @@ -19,38 +19,38 @@ frame_support::construct_runtime!( ); impl frame_system::Config for Test { - type AccountData = (); - type AccountId = u64; - type BaseCallFilter = frame_support::traits::Everything; - type Block = Block; - type BlockHashCount = ConstU64<250>; - type BlockLength = (); - type BlockWeights = (); - type DbWeight = (); - type Hash = H256; - type Hashing = BlakeTwo256; - type Lookup = IdentityLookup; - type MaxConsumers = frame_support::traits::ConstU32<16>; - type Nonce = u64; - type OnKilledAccount = (); - type OnNewAccount = (); - type OnSetCode = (); - type PalletInfo = PalletInfo; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type RuntimeOrigin = RuntimeOrigin; - type SS58Prefix = ConstU16<42>; - type SystemWeightInfo = (); - type Version = (); + type AccountData = (); + type AccountId = u64; + type BaseCallFilter = frame_support::traits::Everything; + type Block = Block; + type BlockHashCount = ConstU64<250>; + type BlockLength = (); + type BlockWeights = (); + type DbWeight = (); + type Hash = H256; + type Hashing = BlakeTwo256; + type Lookup = IdentityLookup; + type MaxConsumers = frame_support::traits::ConstU32<16>; + type Nonce = u64; + type OnKilledAccount = (); + type OnNewAccount = (); + type OnSetCode = (); + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = ConstU16<42>; + type SystemWeightInfo = (); + type Version = (); } impl pallet_template::Config for Test { - type OperationSubmission = OperationSubmission; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); + type OperationSubmission = OperationSubmission; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } // Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - frame_system::GenesisConfig::::default().build_storage().unwrap().into() + frame_system::GenesisConfig::::default().build_storage().unwrap().into() } diff --git a/crates/pallet-chronicle/src/tests.rs b/crates/pallet-chronicle/src/tests.rs index 301c5587e..4c16033f3 100644 --- a/crates/pallet-chronicle/src/tests.rs +++ b/crates/pallet-chronicle/src/tests.rs @@ -1,61 +1,61 @@ use crate::{mock::*, Event}; use common::{ - ledger::OperationSubmission, - prov::{ - operations::{ChronicleOperation, CreateNamespace}, - NamespaceId, - }, + ledger::OperationSubmission, + prov::{ + operations::{ChronicleOperation, CreateNamespace}, + NamespaceId, + }, }; use frame_support::assert_ok; use uuid::Uuid; #[test] fn it_works_for_default_value() { - new_test_ext().execute_with(|| { - // Go past genesis block so events get deposited - System::set_block_number(1); - let op = OperationSubmission::new_anonymous(Uuid::from_bytes([0u8; 16]), vec![]); - // Dispatch a signed extrinsic. - assert_ok!(ChronicleModule::apply(RuntimeOrigin::signed(1), op.clone())); - // Assert that the correct event was deposited - System::assert_last_event( - Event::Applied( - common::prov::ProvModel::default(), - common::identity::SignedIdentity::new_no_identity(), - op.correlation_id, - ) - .into(), - ); - }); + new_test_ext().execute_with(|| { + // Go past genesis block so events get deposited + System::set_block_number(1); + let op = OperationSubmission::new_anonymous(Uuid::from_bytes([0u8; 16]), vec![]); + // Dispatch a signed extrinsic. + assert_ok!(ChronicleModule::apply(RuntimeOrigin::signed(1), op.clone())); + // Assert that the correct event was deposited + System::assert_last_event( + Event::Applied( + common::prov::ProvModel::default(), + common::identity::SignedIdentity::new_no_identity(), + op.correlation_id, + ) + .into(), + ); + }); } #[test] fn single_operation() { - chronicle_telemetry::telemetry(None, chronicle_telemetry::ConsoleLogging::Pretty); - new_test_ext().execute_with(|| { - // Go past genesis block so events get deposited - System::set_block_number(1); - let uuid = Uuid::from_u128(0u128); - let op = ChronicleOperation::CreateNamespace(CreateNamespace { - id: NamespaceId::from_external_id("test", uuid), - }); + chronicle_telemetry::telemetry(false, chronicle_telemetry::ConsoleLogging::Pretty); + new_test_ext().execute_with(|| { + // Go past genesis block so events get deposited + System::set_block_number(1); + let uuid = Uuid::from_u128(0u128); + let op = ChronicleOperation::CreateNamespace(CreateNamespace { + id: NamespaceId::from_external_id("test", uuid), + }); - let sub = OperationSubmission::new_anonymous(Uuid::from_bytes([0u8; 16]), vec![op.clone()]); - // Dispatch our operation - assert_ok!(ChronicleModule::apply(RuntimeOrigin::signed(1), sub.clone(),)); + let sub = OperationSubmission::new_anonymous(Uuid::from_bytes([0u8; 16]), vec![op.clone()]); + // Dispatch our operation + assert_ok!(ChronicleModule::apply(RuntimeOrigin::signed(1), sub.clone(),)); - // Apply that operation to a new prov model for assertion - - // the pallet execution should produce an identical delta - let mut delta_model = common::prov::ProvModel::default(); - delta_model.apply(&op).unwrap(); - // Assert that the delta is correct - System::assert_last_event( - Event::Applied( - delta_model, - common::identity::SignedIdentity::new_no_identity(), - sub.correlation_id, - ) - .into(), - ); - }); + // Apply that operation to a new prov model for assertion - + // the pallet execution should produce an identical delta + let mut delta_model = common::prov::ProvModel::default(); + delta_model.apply(&op).unwrap(); + // Assert that the delta is correct + System::assert_last_event( + Event::Applied( + delta_model, + common::identity::SignedIdentity::new_no_identity(), + sub.correlation_id, + ) + .into(), + ); + }); } diff --git a/crates/pallet-chronicle/src/weights.rs b/crates/pallet-chronicle/src/weights.rs index a77435151..7a7cb971b 100644 --- a/crates/pallet-chronicle/src/weights.rs +++ b/crates/pallet-chronicle/src/weights.rs @@ -34,55 +34,54 @@ use core::marker::PhantomData; /// Weight functions needed for pallet_template. pub trait WeightInfo { - fn apply() -> Weight; + fn apply() -> Weight; - fn operation_weight(ops: &[ChronicleOperation]) -> Weight; + fn operation_weight(ops: &[ChronicleOperation]) -> Weight; } - - /// Weights for pallet_template using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); + impl WeightInfo for SubstrateWeight { - /// Storage: TemplateModule Something (r:0 w:1) - /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn apply() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(9_000_000, 0) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } + /// Storage: TemplateModule Something (r:0 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn apply() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } - /// Calculates the weight of processing a vector of Chronicle operations. - /// Assumes a worst-case scenario where each operation requires one read and one write, - /// plus a base execution time. - fn operation_weight(ops: &[ChronicleOperation]) -> Weight { - let reads_writes = ops.len() as u64 * (T::DbWeight::get().reads(1) + T::DbWeight::get().writes(1)); - Weight::from_parts(9_000_000, 0).saturating_add(reads_writes) - } + /// Calculates the weight of processing a vector of Chronicle operations. + /// Assumes a worst-case scenario where each operation requires one read and one write, + /// plus a base execution time. + fn operation_weight(ops: &[ChronicleOperation]) -> Weight { + let reads_writes = ops.len() as u64 * (T::DbWeight::get().reads(1) + T::DbWeight::get().writes(1)); + Weight::from_parts(9_000_000, 0).saturating_add(reads_writes) + } } // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: TemplateModule Something (r:0 w:1) - /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn apply() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(9_000_000, 0) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } + /// Storage: TemplateModule Something (r:0 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn apply() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } - /// Calculates the weight of processing a vector of Chronicle operations. - /// Assumes a worst-case scenario where each operation requires one read and one write, - /// plus a base execution time. - fn operation_weight(ops: &[ChronicleOperation]) -> Weight { - let reads_writes = ops.len() as u64 * (RocksDbWeight::get().reads(1) + RocksDbWeight::get().writes(1)); - Weight::from_parts(9_000_000, 0).saturating_add(reads_writes) - } + /// Calculates the weight of processing a vector of Chronicle operations. + /// Assumes a worst-case scenario where each operation requires one read and one write, + /// plus a base execution time. + fn operation_weight(ops: &[ChronicleOperation]) -> Weight { + let reads_writes = ops.len() as u64 * (RocksDbWeight::get().reads(1) + RocksDbWeight::get().writes(1)); + Weight::from_parts(9_000_000, 0).saturating_add(reads_writes) + } } diff --git a/crates/pallet-opa/Cargo.toml b/crates/pallet-opa/Cargo.toml index 3ca07c85d..17eb24b7a 100644 --- a/crates/pallet-opa/Cargo.toml +++ b/crates/pallet-opa/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "pallet-opa" +name = "pallet-opa" version = "0.7.5" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -8,24 +8,24 @@ version = "0.7.5" [dependencies] common = { path = "../common", default-features = false, features = [ - "parity-encoding", + "parity-encoding", ] } frame-benchmarking = { version = "25.0.0", default-features = false, optional = true } frame-support = { version = "25.0.0", default-features = false } frame-system = { version = "25.0.0", default-features = false } k256 = { version = "0.11", default-features = false, features = [ - "arithmetic", - "ecdsa", - "pkcs8", - "pem", + "arithmetic", + "ecdsa", + "pkcs8", + "pem", ] } macro-attr-2018 = { workspace = true } newtype-derive-2018 = { workspace = true } parity-scale-codec = { version = "^3.4.0", default-features = false, features = [ - "derive", + "derive", ] } scale-info = { version = "^2.10.0", default-features = false, features = [ - "derive", + "derive", ] } serde = { version = "1", default-features = false } serde_json = { version = "1", default-features = false, features = ["alloc"] } @@ -33,30 +33,30 @@ sp-core = { version = "25", default-features = false } sp-core-hashing = { version = "14", default-features = false } sp-std = { version = "12.0.0", default-features = false } tracing = { version = "0.1", default-features = false, features = [ - "attributes", + "attributes", ] } uuid = { version = "1.5", default-features = false } [dev-dependencies] chronicle-telemetry = { path = "../chronicle-telemetry" } -sp-core = { version = "25.0.0" } -sp-io = { version = "27.0.0" } -sp-runtime = { version = "28.0.0" } -uuid = { version = "1.5.0", default-features = true } +sp-core = { version = "25.0.0" } +sp-io = { version = "27.0.0" } +sp-runtime = { version = "28.0.0" } +uuid = { version = "1.5.0", default-features = true } [features] default = ["std"] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] std = [ - "common/std", - "k256/std", - "parity-scale-codec/std", - "uuid/std", - "sp-std/std", - "scale-info/std", - "frame-support/std", - "frame-system/std", - "frame-benchmarking/std", - "tracing/std", + "common/std", + "k256/std", + "parity-scale-codec/std", + "uuid/std", + "sp-std/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", + "frame-benchmarking/std", + "tracing/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/crates/pallet-opa/src/lib.rs b/crates/pallet-opa/src/lib.rs index ed3e63f5c..1ba6f56be 100644 --- a/crates/pallet-opa/src/lib.rs +++ b/crates/pallet-opa/src/lib.rs @@ -5,28 +5,29 @@ use core::convert::Infallible; /// Re-export types required for runtime pub use common::prov::*; use common::{ - k256::ecdsa::{Signature, VerifyingKey}, - opa::{ - codec::{NewPublicKeyV1, OpaSubmissionV1, PayloadV1, SignedOperationV1}, - BootstrapRoot, KeyAddress, KeyRegistration, Keys, OpaSubmission, Operation, Payload, - PolicyAddress, PolicyMeta, PolicyMetaAddress, RegisterKey, RotateKey, SetPolicy, - SignedOperation, SignedOperationPayload, - }, + k256::ecdsa::{Signature, VerifyingKey}, + opa::{ + codec::{NewPublicKeyV1, OpaSubmissionV1, PayloadV1, SignedOperationV1}, + BootstrapRoot, KeyAddress, KeyRegistration, Keys, OpaSubmission, Operation, Payload, + PolicyAddress, PolicyMeta, PolicyMetaAddress, RegisterKey, RotateKey, SetPolicy, + SignedOperation, SignedOperationPayload, + }, }; use scale_info::prelude::format; pub fn policy_address(id: impl AsRef) -> PolicyAddress { - blake2_128(format!("opa:policy:binary:{}", id.as_ref()).as_bytes()).into() + blake2_128(format!("opa:policy:binary:{}", id.as_ref()).as_bytes()).into() } pub fn policy_meta_address(id: impl AsRef) -> PolicyMetaAddress { - blake2_128(format!("opa:policy:meta:{}", id.as_ref()).as_bytes()).into() + blake2_128(format!("opa:policy:meta:{}", id.as_ref()).as_bytes()).into() } pub fn key_address(id: impl AsRef) -> KeyAddress { - blake2_128(format!("opa:keys:{}", id.as_ref()).as_bytes()).into() + blake2_128(format!("opa:keys:{}", id.as_ref()).as_bytes()).into() } + /// Edit this file to define custom logic or remove it if it is not needed. /// Learn more about FRAME and the core library of Substrate FRAME pallets: /// @@ -37,8 +38,9 @@ pub use pallet::*; pub mod weights; pub mod opa_core { - pub use common::{ledger::*, opa::*}; + pub use common::{ledger::*, opa::*}; } + use parity_scale_codec::Encode; use sp_core_hashing::blake2_128; use tracing::{error, instrument}; @@ -46,15 +48,15 @@ pub use weights::*; #[derive(Debug)] enum OpaError { - OperationSignatureVerification, - InvalidSigningKey, - InvalidOperation, + OperationSignatureVerification, + InvalidSigningKey, + InvalidOperation, } impl From for OpaError { - fn from(_: Infallible) -> Self { - unreachable!() - } + fn from(_: Infallible) -> Self { + unreachable!() + } } // Verifies the submission. @@ -64,328 +66,329 @@ impl From for OpaError { // key of the operation #[instrument(skip(submission, root_keys), ret(Debug))] fn verify_signed_operation( - submission: &OpaSubmissionV1, - root_keys: &Option, + submission: &OpaSubmissionV1, + root_keys: &Option, ) -> Result<(), OpaError> { - use k256::ecdsa::signature::Verifier; - match &submission.payload { - PayloadV1::BootstrapRoot(_) => Ok(()), - PayloadV1::SignedOperation(SignedOperationV1 { payload, verifying_key, signature }) => { - if root_keys.is_none() { - error!("No registered root keys for signature verification"); - return Err(OpaError::OperationSignatureVerification); - } - let payload_bytes = payload.encode(); - let signature: Signature = k256::ecdsa::signature::Signature::from_bytes(signature) - .map_err(|e| { - error!(signature = ?signature, signature_load_error = ?e); - OpaError::OperationSignatureVerification - })?; - let signing_key = ::from_public_key_pem( - verifying_key.as_str(), - ) - .map_err(|e| { - error!(verifying_key = ?verifying_key, key_load_error = ?e); - OpaError::OperationSignatureVerification - })?; - if let Err(e) = signing_key.verify(&payload_bytes, &signature) { - error!(signature = ?signature, verify_error = ?e); - return Err(OpaError::OperationSignatureVerification); - } - - if *verifying_key == root_keys.as_ref().unwrap().current.key { - Ok(()) - } else { - error!(verifying_key = ?verifying_key, current_key = ?root_keys.as_ref().unwrap().current.key, "Invalid signing key"); - Err(OpaError::InvalidSigningKey) - } - }, - } + use k256::ecdsa::signature::Verifier; + match &submission.payload { + PayloadV1::BootstrapRoot(_) => Ok(()), + PayloadV1::SignedOperation(SignedOperationV1 { payload, verifying_key, signature }) => { + if root_keys.is_none() { + error!("No registered root keys for signature verification"); + return Err(OpaError::OperationSignatureVerification); + } + let payload_bytes = payload.encode(); + let signature: Signature = k256::ecdsa::signature::Signature::from_bytes(signature) + .map_err(|e| { + error!(signature = ?signature, signature_load_error = ?e); + OpaError::OperationSignatureVerification + })?; + let signing_key = ::from_public_key_pem( + verifying_key.as_str(), + ) + .map_err(|e| { + error!(verifying_key = ?verifying_key, key_load_error = ?e); + OpaError::OperationSignatureVerification + })?; + if let Err(e) = signing_key.verify(&payload_bytes, &signature) { + error!(signature = ?signature, verify_error = ?e); + return Err(OpaError::OperationSignatureVerification); + } + + if *verifying_key == root_keys.as_ref().unwrap().current.key { + Ok(()) + } else { + error!(verifying_key = ?verifying_key, current_key = ?root_keys.as_ref().unwrap().current.key, "Invalid signing key"); + Err(OpaError::InvalidSigningKey) + } + } + } } // Either apply our bootstrap operation or our signed operation #[instrument(skip(payload), ret(Debug))] fn apply_signed_operation( - correlation_id: ChronicleTransactionId, - payload: Payload, + correlation_id: ChronicleTransactionId, + payload: Payload, ) -> Result<(), OpaError> { - use scale_info::prelude::string::ToString; - match payload { - Payload::BootstrapRoot(BootstrapRoot { public_key }) => { - let existing_key = pallet::KeyStore::::try_get(key_address("root")); - - if existing_key.is_ok() { - error!("OPA TP has already been bootstrapped"); - return Err(OpaError::InvalidOperation); - } - - let keys = Keys { - id: "root".to_string(), - current: KeyRegistration { key: public_key, version: 0 }, - expired: None, - }; - - pallet::KeyStore::::set(key_address("root"), Some(keys.clone().into())); - - pallet::Pallet::::deposit_event(pallet::Event::::KeyUpdate( - keys.into(), - correlation_id, - )); - - Ok(()) - }, - Payload::SignedOperation(SignedOperation { - payload: SignedOperationPayload { operation }, - verifying_key: _, - signature: _, - }) => apply_signed_operation_payload::(correlation_id, operation), - } + use scale_info::prelude::string::ToString; + match payload { + Payload::BootstrapRoot(BootstrapRoot { public_key }) => { + let existing_key = pallet::KeyStore::::try_get(key_address("root")); + + if existing_key.is_ok() { + error!("OPA TP has already been bootstrapped"); + return Err(OpaError::InvalidOperation); + } + + let keys = Keys { + id: "root".to_string(), + current: KeyRegistration { key: public_key, version: 0 }, + expired: None, + }; + + pallet::KeyStore::::set(key_address("root"), Some(keys.clone().into())); + + pallet::Pallet::::deposit_event(pallet::Event::::KeyUpdate( + keys.into(), + correlation_id, + )); + + Ok(()) + } + Payload::SignedOperation(SignedOperation { + payload: SignedOperationPayload { operation }, + verifying_key: _, + signature: _, + }) => apply_signed_operation_payload::(correlation_id, operation), + } } #[instrument(skip(payload), ret(Debug))] fn apply_signed_operation_payload( - correlation_id: ChronicleTransactionId, - payload: Operation, + correlation_id: ChronicleTransactionId, + payload: Operation, ) -> Result<(), OpaError> { - match payload { - Operation::RegisterKey(RegisterKey { public_key, id, overwrite_existing }) => { - if id == "root" { - error!("Cannot register a key with the id 'root'"); - return Err(OpaError::InvalidOperation); - } - - let existing_key = pallet::KeyStore::::try_get(key_address(&id)); - - if existing_key.is_ok() { - if overwrite_existing { - tracing::debug!("Registration replaces existing key"); - } else { - error!("Key already registered"); - return Err(OpaError::InvalidOperation); - } - } - - let keys = Keys { - id, - current: KeyRegistration { key: public_key, version: 0 }, - expired: None, - }; - - pallet::KeyStore::::set(key_address(&keys.id), Some(keys.clone().into())); - - pallet::Pallet::::deposit_event(pallet::Event::::KeyUpdate( - keys.into(), - correlation_id, - )); - - Ok(()) - }, - Operation::RotateKey(RotateKey { - payload, - previous_signing_key, - previous_signature, - new_signing_key, - new_signature, - }) => { - // Get current key registration from state - let existing_key = pallet::KeyStore::::try_get(key_address(&payload.id)); - - if existing_key.is_err() { - error!("No key to rotate"); - return Err(OpaError::InvalidOperation); - } - - let existing_key = existing_key.unwrap(); - - if previous_signing_key != existing_key.current.key { - error!("Key does not match current key"); - return Err(OpaError::InvalidOperation); - } - - let payload_id = payload.id.clone(); - let payload_bytes: NewPublicKeyV1 = payload.into(); - // Verify the previous key and signature - let payload_bytes = payload_bytes.encode(); - let previous_signature = Signature::try_from(&*previous_signature) - .map_err(|_| OpaError::OperationSignatureVerification)?; - let previous_key = ::from_public_key_pem( - previous_signing_key.as_str(), - ) - .map_err(|_| OpaError::OperationSignatureVerification)?; - - k256::ecdsa::signature::Verifier::verify( - &previous_key, - &payload_bytes, - &previous_signature, - ) - .map_err(|_| OpaError::OperationSignatureVerification)?; - - //Verify the new key and signature - let new_signature = Signature::try_from(&*new_signature) - .map_err(|_| OpaError::OperationSignatureVerification)?; - let new_key = ::from_public_key_pem( - new_signing_key.as_str(), - ) - .map_err(|_| OpaError::OperationSignatureVerification)?; - - k256::ecdsa::signature::Verifier::verify(&new_key, &payload_bytes, &new_signature) - .map_err(|_| OpaError::OperationSignatureVerification)?; - - //Store new keys - let keys = Keys { - id: payload_id, - current: KeyRegistration { - key: new_signing_key, - version: existing_key.current.version + 1, - }, - expired: Some(KeyRegistration { - key: previous_signing_key, - version: existing_key.current.version, - }), - }; - - pallet::KeyStore::::set(key_address(&keys.id), Some(keys.clone().into())); - - pallet::Pallet::::deposit_event(pallet::Event::::KeyUpdate( - keys.into(), - correlation_id, - )); - - Ok(()) - }, - Operation::SetPolicy(SetPolicy { policy, id }) => { - let hash = sp_core_hashing::blake2_128(policy.as_bytes()); - - let meta = PolicyMeta { - id: id.clone(), - hash: hash.into(), - policy_address: policy_address(&*id), - }; - - pallet::PolicyMetaStore::::set(policy_meta_address(&*id), Some(meta.clone().into())); - - pallet::PolicyStore::::set(policy_address(&*id), Some(policy.into())); - - pallet::Pallet::::deposit_event(pallet::Event::::PolicyUpdate( - meta.into(), - correlation_id, - )); - - Ok(()) - }, - } + match payload { + Operation::RegisterKey(RegisterKey { public_key, id, overwrite_existing }) => { + if id == "root" { + error!("Cannot register a key with the id 'root'"); + return Err(OpaError::InvalidOperation); + } + + let existing_key = pallet::KeyStore::::try_get(key_address(&id)); + + if existing_key.is_ok() { + if overwrite_existing { + tracing::debug!("Registration replaces existing key"); + } else { + error!("Key already registered"); + return Err(OpaError::InvalidOperation); + } + } + + let keys = Keys { + id, + current: KeyRegistration { key: public_key, version: 0 }, + expired: None, + }; + + pallet::KeyStore::::set(key_address(&keys.id), Some(keys.clone().into())); + + pallet::Pallet::::deposit_event(pallet::Event::::KeyUpdate( + keys.into(), + correlation_id, + )); + + Ok(()) + } + Operation::RotateKey(RotateKey { + payload, + previous_signing_key, + previous_signature, + new_signing_key, + new_signature, + }) => { + // Get current key registration from state + let existing_key = pallet::KeyStore::::try_get(key_address(&payload.id)); + + if existing_key.is_err() { + error!("No key to rotate"); + return Err(OpaError::InvalidOperation); + } + + let existing_key = existing_key.unwrap(); + + if previous_signing_key != existing_key.current.key { + error!("Key does not match current key"); + return Err(OpaError::InvalidOperation); + } + + let payload_id = payload.id.clone(); + let payload_bytes: NewPublicKeyV1 = payload.into(); + // Verify the previous key and signature + let payload_bytes = payload_bytes.encode(); + let previous_signature = Signature::try_from(&*previous_signature) + .map_err(|_| OpaError::OperationSignatureVerification)?; + let previous_key = ::from_public_key_pem( + previous_signing_key.as_str(), + ) + .map_err(|_| OpaError::OperationSignatureVerification)?; + + k256::ecdsa::signature::Verifier::verify( + &previous_key, + &payload_bytes, + &previous_signature, + ) + .map_err(|_| OpaError::OperationSignatureVerification)?; + + //Verify the new key and signature + let new_signature = Signature::try_from(&*new_signature) + .map_err(|_| OpaError::OperationSignatureVerification)?; + let new_key = ::from_public_key_pem( + new_signing_key.as_str(), + ) + .map_err(|_| OpaError::OperationSignatureVerification)?; + + k256::ecdsa::signature::Verifier::verify(&new_key, &payload_bytes, &new_signature) + .map_err(|_| OpaError::OperationSignatureVerification)?; + + //Store new keys + let keys = Keys { + id: payload_id, + current: KeyRegistration { + key: new_signing_key, + version: existing_key.current.version + 1, + }, + expired: Some(KeyRegistration { + key: previous_signing_key, + version: existing_key.current.version, + }), + }; + + pallet::KeyStore::::set(key_address(&keys.id), Some(keys.clone().into())); + + pallet::Pallet::::deposit_event(pallet::Event::::KeyUpdate( + keys.into(), + correlation_id, + )); + + Ok(()) + } + Operation::SetPolicy(SetPolicy { policy, id }) => { + let hash = sp_core_hashing::blake2_128(policy.as_bytes()); + + let meta = PolicyMeta { + id: id.clone(), + hash: hash.into(), + policy_address: policy_address(&*id), + }; + + pallet::PolicyMetaStore::::set(policy_meta_address(&*id), Some(meta.clone().into())); + + pallet::PolicyStore::::set(policy_address(&*id), Some(policy.into())); + + pallet::Pallet::::deposit_event(pallet::Event::::PolicyUpdate( + meta.into(), + correlation_id, + )); + + Ok(()) + } + } } fn root_keys_from_state() -> Result, OpaError> { - let existing_key = pallet::KeyStore::::try_get(key_address("root")); + let existing_key = pallet::KeyStore::::try_get(key_address("root")); - if let Ok(existing_key) = existing_key { - Ok(Some(existing_key.try_into()?)) - } else { - Ok(None) - } + if let Ok(existing_key) = existing_key { + Ok(Some(existing_key.try_into()?)) + } else { + Ok(None) + } } #[frame_support::pallet] pub mod pallet { - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - #[pallet::pallet] - pub struct Pallet(_); - - /// Configure the pallet by specifying the parameters and types on which it depends. - #[pallet::config] - pub trait Config: frame_system::Config { - /// Because this pallet emits events, it depends on the runtime's definition of an event. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Type representing the weight of this pallet - type WeightInfo: WeightInfo; - - type OpaSubmission: Parameter - + Into - + parity_scale_codec::Codec; - } - // The pallet's runtime storage items. - // https://docs.substrate.io/main-docs/build/runtime-storage/ - #[pallet::storage] - #[pallet::getter(fn get_policy)] - // Learn more about declaring storage items: - // https://docs.substrate.io/main-docs/build/runtime-storage/#declaring-storage-items - pub type PolicyStore = - StorageMap<_, Twox128, common::opa::PolicyAddress, common::opa::codec::PolicyV1>; - #[pallet::storage] - #[pallet::getter(fn get_policy_meta)] - pub type PolicyMetaStore = - StorageMap<_, Twox128, common::opa::PolicyMetaAddress, common::opa::codec::PolicyMetaV1>; - #[pallet::storage] - #[pallet::getter(fn get_key)] - pub type KeyStore = - StorageMap<_, Twox128, common::opa::KeyAddress, common::opa::codec::KeysV1>; - - // Pallets use events to inform users when important changes are made. - // https://docs.substrate.io/main-docs/build/events-errors/ - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - PolicyUpdate(common::opa::codec::PolicyMetaV1, ChronicleTransactionId), - KeyUpdate(common::opa::codec::KeysV1, ChronicleTransactionId), - } - - // Errors inform users that something went wrong. - #[pallet::error] - pub enum Error { - OperationSignatureVerification, - InvalidSigningKey, - JsonSerialize, - InvalidOperation, - } - - impl From for Error { - fn from(error: OpaError) -> Self { - match error { - OpaError::OperationSignatureVerification => Error::OperationSignatureVerification, - OpaError::InvalidSigningKey => Error::InvalidSigningKey, - OpaError::InvalidOperation => Error::InvalidOperation, - } - } - } - - // Dispatchable functions allows users to interact with the pallet and invoke state changes. - // These functions materialize as "extrinsics", which are often compared to transactions. - // Dispatchable functions must be annotated with a weight and must return a DispatchResult. - #[pallet::call] - impl Pallet { - // Apply a vector of chronicle operations, yielding an event that indicates state change or - // contradiction - #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::apply())] - pub fn apply(origin: OriginFor, submission: T::OpaSubmission) -> DispatchResult { - // Check that the extrinsic was signed and get the signer. - // This function will return an error if the extrinsic is not signed. - // https://docs.substrate.io/main-docs/build/origins/ - let _who = ensure_signed(origin)?; - - // We need to validate the submission's own internal signatures at the codec level - let submission: OpaSubmissionV1 = submission.into(); - - super::verify_signed_operation::( - &submission, - &super::root_keys_from_state::().map_err(Error::::from)?, - ) - .map_err(Error::::from)?; - - let submission: OpaSubmission = submission.into(); - - super::apply_signed_operation::( - submission.correlation_id.into(), - submission.payload, - ) - .map_err(Error::::from)?; - - // Return a successful DispatchResultWithPostInfo - Ok(()) - } - } + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + /// Configure the pallet by specifying the parameters and types on which it depends. + #[pallet::config] + pub trait Config: frame_system::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// Type representing the weight of this pallet + type WeightInfo: WeightInfo; + + type OpaSubmission: Parameter + + Into + + parity_scale_codec::Codec; + } + + // The pallet's runtime storage items. + // https://docs.substrate.io/main-docs/build/runtime-storage/ + #[pallet::storage] + #[pallet::getter(fn get_policy)] + // Learn more about declaring storage items: + // https://docs.substrate.io/main-docs/build/runtime-storage/#declaring-storage-items + pub type PolicyStore = + StorageMap<_, Twox128, common::opa::PolicyAddress, common::opa::codec::PolicyV1>; + #[pallet::storage] + #[pallet::getter(fn get_policy_meta)] + pub type PolicyMetaStore = + StorageMap<_, Twox128, common::opa::PolicyMetaAddress, common::opa::codec::PolicyMetaV1>; + #[pallet::storage] + #[pallet::getter(fn get_key)] + pub type KeyStore = + StorageMap<_, Twox128, common::opa::KeyAddress, common::opa::codec::KeysV1>; + + // Pallets use events to inform users when important changes are made. + // https://docs.substrate.io/main-docs/build/events-errors/ + #[pallet::event] + #[pallet::generate_deposit(pub (super) fn deposit_event)] + pub enum Event { + PolicyUpdate(common::opa::codec::PolicyMetaV1, ChronicleTransactionId), + KeyUpdate(common::opa::codec::KeysV1, ChronicleTransactionId), + } + + // Errors inform users that something went wrong. + #[pallet::error] + pub enum Error { + OperationSignatureVerification, + InvalidSigningKey, + JsonSerialize, + InvalidOperation, + } + + impl From for Error { + fn from(error: OpaError) -> Self { + match error { + OpaError::OperationSignatureVerification => Error::OperationSignatureVerification, + OpaError::InvalidSigningKey => Error::InvalidSigningKey, + OpaError::InvalidOperation => Error::InvalidOperation, + } + } + } + + // Dispatchable functions allows users to interact with the pallet and invoke state changes. + // These functions materialize as "extrinsics", which are often compared to transactions. + // Dispatchable functions must be annotated with a weight and must return a DispatchResult. + #[pallet::call] + impl Pallet { + // Apply a vector of chronicle operations, yielding an event that indicates state change or + // contradiction + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::apply())] + pub fn apply(origin: OriginFor, submission: T::OpaSubmission) -> DispatchResult { + // Check that the extrinsic was signed and get the signer. + // This function will return an error if the extrinsic is not signed. + // https://docs.substrate.io/main-docs/build/origins/ + let _who = ensure_signed(origin)?; + + // We need to validate the submission's own internal signatures at the codec level + let submission: OpaSubmissionV1 = submission.into(); + + super::verify_signed_operation::( + &submission, + &super::root_keys_from_state::().map_err(Error::::from)?, + ) + .map_err(Error::::from)?; + + let submission: OpaSubmission = submission.into(); + + super::apply_signed_operation::( + submission.correlation_id.into(), + submission.payload, + ) + .map_err(Error::::from)?; + + // Return a successful DispatchResultWithPostInfo + Ok(()) + } + } } diff --git a/crates/pallet-opa/src/weights.rs b/crates/pallet-opa/src/weights.rs index c2b102ef7..f45386714 100644 --- a/crates/pallet-opa/src/weights.rs +++ b/crates/pallet-opa/src/weights.rs @@ -33,34 +33,35 @@ use core::marker::PhantomData; /// Weight functions needed for pallet_template. pub trait WeightInfo { - fn apply() -> Weight; + fn apply() -> Weight; } /// Weights for pallet_template using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); + impl WeightInfo for SubstrateWeight { - /// Storage: TemplateModule Something (r:0 w:1) - /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn apply() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(9_000_000, 0) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } + /// Storage: TemplateModule Something (r:0 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn apply() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: TemplateModule Something (r:0 w:1) - /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn apply() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(9_000_000, 0) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } + /// Storage: TemplateModule Something (r:0 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn apply() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } diff --git a/crates/protocol-abstract/Cargo.toml b/crates/protocol-abstract/Cargo.toml index c78441074..d4fdbe59c 100644 --- a/crates/protocol-abstract/Cargo.toml +++ b/crates/protocol-abstract/Cargo.toml @@ -1,18 +1,18 @@ [package] edition = "2021" -name = "protocol-abstract" +name = "protocol-abstract" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = { workspace = true } -async-trait = { workspace = true } -futures = { workspace = true } -k256 = { workspace = true } +anyhow = { workspace = true } +async-trait = { workspace = true } +futures = { workspace = true } +k256 = { workspace = true } pallet-chronicle = { path = "../pallet-chronicle", features = ["std"] } -serde = { workspace = true } -subxt = { version = "0.34", features = ["substrate-compat"] } -thiserror = { workspace = true } -tokio = { workspace = true } -tracing = { workspace = true } +serde = { workspace = true } +subxt = { version = "0.34", features = ["substrate-compat"] } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } diff --git a/crates/protocol-abstract/src/abstract_ledger.rs b/crates/protocol-abstract/src/abstract_ledger.rs index 9fb9428a9..4d4cac66b 100644 --- a/crates/protocol-abstract/src/abstract_ledger.rs +++ b/crates/protocol-abstract/src/abstract_ledger.rs @@ -11,92 +11,93 @@ use tracing::{instrument, warn}; #[derive(Debug, Error)] pub enum BlockIdError { - #[error("Parse {0}")] - Parse( - #[from] - #[source] - anyhow::Error, - ), + #[error("Parse {0}")] + Parse( + #[from] + #[source] + anyhow::Error, + ), } + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum BlockId { - Unknown, //Block ids can be null, empty string etc - Block(H256), //ToDo - trait + Unknown, //Block ids can be null, empty string etc + Block(H256), //ToDo - trait } impl From for BlockId { - fn from(hash: H256) -> Self { - BlockId::Block(hash) - } + fn from(hash: H256) -> Self { + BlockId::Block(hash) + } } impl TryFrom<&str> for BlockId { - type Error = BlockIdError; + type Error = BlockIdError; - #[instrument(level = "trace", skip(s), err)] - fn try_from(s: &str) -> Result { - let hash = H256::from_str(s).map_err(|e| BlockIdError::Parse(anyhow::Error::new(e)))?; - Ok(BlockId::Block(hash)) - } + #[instrument(level = "trace", skip(s), err)] + fn try_from(s: &str) -> Result { + let hash = H256::from_str(s).map_err(|e| BlockIdError::Parse(anyhow::Error::new(e)))?; + Ok(BlockId::Block(hash)) + } } impl std::fmt::Display for BlockId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - BlockId::Unknown => f.write_str("Unknown"), - BlockId::Block(hash) => f.write_str(&format!("{:?}", hash)), - } - } + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + BlockId::Unknown => f.write_str("Unknown"), + BlockId::Block(hash) => f.write_str(&format!("{:?}", hash)), + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Position(u32); impl From for Position { - fn from(height: u32) -> Self { - Position(height) - } + fn from(height: u32) -> Self { + Position(height) + } } impl PartialOrd for Position { - fn partial_cmp(&self, other: &Self) -> Option { - let (Position(x), Position(y)) = (self, other); - x.partial_cmp(y) - } + fn partial_cmp(&self, other: &Self) -> Option { + let (Position(x), Position(y)) = (self, other); + x.partial_cmp(y) + } } impl Position { - pub fn new(height: u32) -> Self { - Position(height) - } - - pub fn map(&self, f: F) -> T - where - F: FnOnce(&u32) -> T, - { - f(&self.0) - } - - pub fn distance(&self, other: &Self) -> u32 { - let (Position(x), Position(y)) = (self, other); - x.saturating_sub(*y) - } + pub fn new(height: u32) -> Self { + Position(height) + } + + pub fn map(&self, f: F) -> T + where + F: FnOnce(&u32) -> T, + { + f(&self.0) + } + + pub fn distance(&self, other: &Self) -> u32 { + let (Position(x), Position(y)) = (self, other); + x.saturating_sub(*y) + } } impl std::fmt::Display for Position { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Position(x) => f.write_str(&format!("{}", x)), - } - } + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Position(x) => f.write_str(&format!("{}", x)), + } + } } // Type that can contain a distributed tracing span for transaction processors // that support it #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Span { - Span(u64), - NotTraced, + Span(u64), + NotTraced, } // An application specific ledger event with its corresponding transaction id, @@ -105,190 +106,190 @@ pub type LedgerEventContext = (Event, ChronicleTransactionId, BlockId, Po #[async_trait::async_trait] pub trait LedgerEvent { - fn correlation_id(&self) -> [u8; 16]; + fn correlation_id(&self) -> [u8; 16]; } #[async_trait::async_trait] pub trait LedgerEventCodec { - type Source; - type Sink: LedgerEvent + Send + Sync; - type Error: std::error::Error; - // Attempt to deserialize an event, where there may be none present in the source - async fn maybe_deserialize( - source: Self::Source, - ) -> Result, Self::Error> - where - Self: Sized; + type Source; + type Sink: LedgerEvent + Send + Sync; + type Error: std::error::Error; + // Attempt to deserialize an event, where there may be none present in the source + async fn maybe_deserialize( + source: Self::Source, + ) -> Result, Self::Error> + where + Self: Sized; } pub trait MessageBuilder {} #[async_trait::async_trait] pub trait LedgerTransaction { - type Error: std::error::Error + Send + Sync + 'static; - type Payload: Sized + Send + Sync; - async fn as_payload(&self) -> Result; - fn correlation_id(&self) -> [u8; 16]; + type Error: std::error::Error + Send + Sync + 'static; + type Payload: Sized + Send + Sync; + async fn as_payload(&self) -> Result; + fn correlation_id(&self) -> [u8; 16]; } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum WriteConsistency { - Weak, - Strong, + Weak, + Strong, } #[async_trait::async_trait] pub trait LedgerWriter { - type Error: std::error::Error; - type Transaction: LedgerTransaction; - type Submittable: Sized; - - // Minimally process the transaction offline to get a transaction id and submittable type - async fn pre_submit( - &self, - tx: Self::Transaction, - ) -> Result<(Self::Submittable, ChronicleTransactionId), Self::Error>; - - // Submit is used to submit a transaction to the ledger - async fn do_submit( - &self, - consistency: WriteConsistency, - submittable: Self::Submittable, - ) -> Result; + type Error: std::error::Error; + type Transaction: LedgerTransaction; + type Submittable: Sized; + + // Minimally process the transaction offline to get a transaction id and submittable type + async fn pre_submit( + &self, + tx: Self::Transaction, + ) -> Result<(Self::Submittable, ChronicleTransactionId), Self::Error>; + + // Submit is used to submit a transaction to the ledger + async fn do_submit( + &self, + consistency: WriteConsistency, + submittable: Self::Submittable, + ) -> Result; } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum FromBlock { - // Do not attempt to catch up, start from the current head - Head, - // Discover the first useful block and start from there - First, - // Start from the given block - BlockId(BlockId), + // Do not attempt to catch up, start from the current head + Head, + // Discover the first useful block and start from there + First, + // Start from the given block + BlockId(BlockId), } #[async_trait::async_trait] pub trait LedgerReader { - type Event: LedgerEvent; - type EventCodec: LedgerEventCodec; - type Error: std::error::Error; - // Get the block height of the ledger, and the id of the highest block - async fn block_height(&self) -> Result<(Position, BlockId), Self::Error>; - /// Subscribe to state updates from this ledger, starting at `offset`, and - /// ending the stream after `number_of_blocks` blocks have been processed. - async fn state_updates( - &self, - // The block to start from - from_block: FromBlock, - // The number of blocks to process before ending the stream - number_of_blocks: Option, - ) -> Result>, Self::Error>; + type Event: LedgerEvent; + type EventCodec: LedgerEventCodec; + type Error: std::error::Error; + // Get the block height of the ledger, and the id of the highest block + async fn block_height(&self) -> Result<(Position, BlockId), Self::Error>; + /// Subscribe to state updates from this ledger, starting at `offset`, and + /// ending the stream after `number_of_blocks` blocks have been processed. + async fn state_updates( + &self, + // The block to start from + from_block: FromBlock, + // The number of blocks to process before ending the stream + number_of_blocks: Option, + ) -> Result>, Self::Error>; } pub fn retryable_ledger(ledger: L, retry_delay: Duration) -> RetryLedger { - RetryLedger::new(ledger, retry_delay) + RetryLedger::new(ledger, retry_delay) } #[derive(Clone)] pub struct RetryLedger { - inner: L, - retry_delay: Duration, + inner: L, + retry_delay: Duration, } impl RetryLedger { - pub fn new(inner: L, retry_delay: Duration) -> Self { - Self { inner, retry_delay } - } + pub fn new(inner: L, retry_delay: Duration) -> Self { + Self { inner, retry_delay } + } } #[async_trait::async_trait] impl LedgerWriter for RetryLedger -where - L: LedgerReader + LedgerWriter + Send + Sync, - ::Error: Send + Sync + 'static, - ::Transaction: Send + Sync + 'static, - L::Submittable: Send + Sync + 'static + Clone, + where + L: LedgerReader + LedgerWriter + Send + Sync, + ::Error: Send + Sync + 'static, + ::Transaction: Send + Sync + 'static, + L::Submittable: Send + Sync + 'static + Clone, { - type Error = ::Error; - type Submittable = L::Submittable; - type Transaction = L::Transaction; - - async fn pre_submit( - &self, - tx: Self::Transaction, - ) -> Result<(Self::Submittable, ChronicleTransactionId), Self::Error> { - tracing::debug!(target: "ledger_writer", "Pre-submitting transaction"); - let pre_submit_result = self.inner.pre_submit(tx).await; - match pre_submit_result { - Ok(result) => Ok(result), - Err(e) => { - tracing::error!(error = %e, "Failed to pre-submit transaction"); - Err(e) - }, - } - } - - async fn do_submit( - &self, - consistency: WriteConsistency, - submittable: Self::Submittable, - ) -> Result { - let mut attempts = 0; - loop { - match self.inner.do_submit(consistency, submittable.clone()).await { - Ok(result) => { - tracing::info!(target: "ledger_writer", "Successfully submitted transaction"); - return Ok(result); - }, - Err(e) => { - attempts += 1; - tracing::warn!(error = %e.0, attempts, "Failed to submit transaction, retrying after delay"); - tokio::time::sleep(self.retry_delay).await; - }, - } - } - } + type Error = ::Error; + type Submittable = L::Submittable; + type Transaction = L::Transaction; + + async fn pre_submit( + &self, + tx: Self::Transaction, + ) -> Result<(Self::Submittable, ChronicleTransactionId), Self::Error> { + tracing::debug!(target: "ledger_writer", "Pre-submitting transaction"); + let pre_submit_result = self.inner.pre_submit(tx).await; + match pre_submit_result { + Ok(result) => Ok(result), + Err(e) => { + tracing::error!(error = %e, "Failed to pre-submit transaction"); + Err(e) + } + } + } + + async fn do_submit( + &self, + consistency: WriteConsistency, + submittable: Self::Submittable, + ) -> Result { + let mut attempts = 0; + loop { + match self.inner.do_submit(consistency, submittable.clone()).await { + Ok(result) => { + tracing::info!(target: "ledger_writer", "Successfully submitted transaction"); + return Ok(result); + } + Err(e) => { + attempts += 1; + tracing::warn!(error = %e.0, attempts, "Failed to submit transaction, retrying after delay"); + tokio::time::sleep(self.retry_delay).await; + } + } + } + } } #[async_trait] impl LedgerReader for RetryLedger -where - ::Error: Send + Sync, + where + ::Error: Send + Sync, { - type Error = L::Error; - type Event = L::Event; - type EventCodec = L::EventCodec; - - async fn block_height(&self) -> Result<(Position, BlockId), Self::Error> { - let mut attempts = 0; - loop { - match self.inner.block_height().await { - Ok(result) => { - tracing::info!(target: "ledger_reader", "Successfully retrieved block height"); - return Ok(result); - }, - Err(e) => { - attempts += 1; - tracing::warn!(error = %e, attempts, "Failed to get block height, retrying after delay"); - tokio::time::sleep(self.retry_delay).await; - }, - } - } - } - - async fn state_updates( - &self, - from_block: FromBlock, - number_of_blocks: Option, - ) -> Result>, Self::Error> { - loop { - match self.inner.state_updates(from_block, number_of_blocks).await { - Ok(stream) => return Ok(stream), - Err(e) => { - warn!(error = %e, "Failed to subscribe to state updates, retrying after delay"); - sleep(self.retry_delay).await; - }, - } - } - } + type Error = L::Error; + type Event = L::Event; + type EventCodec = L::EventCodec; + + async fn block_height(&self) -> Result<(Position, BlockId), Self::Error> { + let mut attempts = 0; + loop { + match self.inner.block_height().await { + Ok(result) => { + tracing::info!(target: "ledger_reader", "Successfully retrieved block height"); + return Ok(result); + } + Err(e) => { + attempts += 1; + tracing::warn!(error = %e, attempts, "Failed to get block height, retrying after delay"); + tokio::time::sleep(self.retry_delay).await; + } + } + } + } + + async fn state_updates( + &self, + from_block: FromBlock, + number_of_blocks: Option, + ) -> Result>, Self::Error> { + loop { + match self.inner.state_updates(from_block, number_of_blocks).await { + Ok(stream) => return Ok(stream), + Err(e) => { + warn!(error = %e, "Failed to subscribe to state updates, retrying after delay"); + sleep(self.retry_delay).await; + } + } + } + } } diff --git a/crates/protocol-substrate-chronicle/Cargo.toml b/crates/protocol-substrate-chronicle/Cargo.toml index f7178745a..7579fc07d 100644 --- a/crates/protocol-substrate-chronicle/Cargo.toml +++ b/crates/protocol-substrate-chronicle/Cargo.toml @@ -1,43 +1,43 @@ [package] edition = "2021" -name = "protocol-substrate-chronicle" +name = "protocol-substrate-chronicle" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-trait = { workspace = true } +async-trait = { workspace = true } clap_builder = { version = "*" } -futures = { workspace = true } -k256 = { workspace = true } -serde = { workspace = true } -subxt = { version = "0.34", features = ["substrate-compat"] } -thiserror = { workspace = true } -tracing = { workspace = true } -uuid = { workspace = true, features = ["std", "v4"] } +futures = { workspace = true } +k256 = { workspace = true } +serde = { workspace = true } +subxt = { version = "0.34", features = ["substrate-compat"] } +thiserror = { workspace = true } +tracing = { workspace = true } +uuid = { workspace = true, features = ["std", "v4"] } #local dependencies chronicle-signing = { path = "../chronicle-signing" } common = { path = "../common", features = ["parity-encoding", "std"] } hex = { workspace = true } opa = { git = "https://github.com/chronicleworks/opa-rs", rev = "9fa2fbce" } parity-scale-codec = { version = "^3.4.0", default-features = false, features = [ - "derive", - "max-encoded-len", - "std", + "derive", + "max-encoded-len", + "std", ] } protocol-abstract = { path = "../protocol-abstract" } protocol-substrate = { path = "../protocol-substrate" } scale-encode = { version = "^0.5.0", features = [ - "derive", - "primitive-types", - "bits", + "derive", + "primitive-types", + "bits", ] } scale-info = { version = "^2.10.0", features = ["derive", "std"] } tokio = { workspace = true } [dev-dependencies] chronicle-telemetry = { path = "../chronicle-telemetry" } -embedded-substrate = { path = "../embedded-substrate" } +embedded-substrate = { path = "../embedded-substrate" } [features] diff --git a/crates/protocol-substrate-chronicle/src/lib.rs b/crates/protocol-substrate-chronicle/src/lib.rs index 6f1578dc3..56d56bb0c 100644 --- a/crates/protocol-substrate-chronicle/src/lib.rs +++ b/crates/protocol-substrate-chronicle/src/lib.rs @@ -1,11 +1,11 @@ mod subxt_client; pub mod protocol { - pub use protocol_abstract::*; + pub use protocol_abstract::*; } pub mod common { - pub use common::*; + pub use common::*; } pub use subxt_client::*; diff --git a/crates/protocol-substrate-chronicle/src/subxt_client.rs b/crates/protocol-substrate-chronicle/src/subxt_client.rs index 55a0f0593..82dfeb1f4 100644 --- a/crates/protocol-substrate-chronicle/src/subxt_client.rs +++ b/crates/protocol-substrate-chronicle/src/subxt_client.rs @@ -1,23 +1,23 @@ use std::{convert::Infallible, marker::PhantomData, sync::Arc}; use chronicle_signing::{ - ChronicleSigning, OwnedSecret, SecretError, BATCHER_NAMESPACE, BATCHER_PK, + ChronicleSigning, OwnedSecret, SecretError, BATCHER_NAMESPACE, BATCHER_PK, }; use common::{ - identity::SignedIdentity, ledger::OperationSubmission, opa::OpaSettings, - prov::operations::ChronicleOperation, + identity::SignedIdentity, ledger::OperationSubmission, opa::OpaSettings, + prov::operations::ChronicleOperation, }; use protocol_substrate::{SubstrateClient, SubxtClientError}; use subxt::ext::{ - codec::Decode, - scale_value::Composite, - sp_core::{blake2_256, Pair}, + codec::Decode, + scale_value::Composite, + sp_core::{blake2_256, Pair}, }; use subxt::{ - tx::Signer, - utils::{AccountId32, MultiAddress, MultiSignature}, + tx::Signer, + utils::{AccountId32, MultiAddress, MultiSignature}, }; use protocol_abstract::{LedgerEvent, LedgerEventCodec, LedgerTransaction, Span}; @@ -25,218 +25,220 @@ use protocol_abstract::{LedgerEvent, LedgerEventCodec, LedgerTransaction, Span}; //This type must match pallet::Event but we cannot reference it directly #[derive(Debug, Clone)] pub enum ChronicleEvent { - Committed { - diff: common::prov::ProvModel, - identity: SignedIdentity, - correlation_id: [u8; 16], - }, - Contradicted { - contradiction: common::prov::Contradiction, - identity: SignedIdentity, - correlation_id: [u8; 16], - }, + Committed { + diff: common::prov::ProvModel, + identity: SignedIdentity, + correlation_id: [u8; 16], + }, + Contradicted { + contradiction: common::prov::Contradiction, + identity: SignedIdentity, + correlation_id: [u8; 16], + }, } //This type must match pallet::Event but we cannot reference it directly pub struct ChronicleEventCodec -where - C: subxt::Config, + where + C: subxt::Config, { - _p: PhantomData, + _p: PhantomData, } impl ChronicleEvent { - #[tracing::instrument(level = "trace", skip(diff, identity), fields(diff = tracing::field::debug(&diff), identity = tracing::field::debug(&identity), correlation_id = tracing::field::debug(&correlation_id)))] - pub fn new_committed( - diff: common::prov::ProvModel, - identity: SignedIdentity, - correlation_id: [u8; 16], - ) -> Self { - ChronicleEvent::Committed { diff, identity, correlation_id } - } - - pub fn new_contradicted( - contradiction: common::prov::Contradiction, - identity: SignedIdentity, - correlation_id: [u8; 16], - ) -> Self { - ChronicleEvent::Contradicted { contradiction, identity, correlation_id } - } + #[tracing::instrument(level = "trace", skip(diff, identity), fields( + diff = tracing::field::debug(& diff), identity = tracing::field::debug(& identity), correlation_id = tracing::field::debug(& correlation_id) + ))] + pub fn new_committed( + diff: common::prov::ProvModel, + identity: SignedIdentity, + correlation_id: [u8; 16], + ) -> Self { + ChronicleEvent::Committed { diff, identity, correlation_id } + } + + pub fn new_contradicted( + contradiction: common::prov::Contradiction, + identity: SignedIdentity, + correlation_id: [u8; 16], + ) -> Self { + ChronicleEvent::Contradicted { contradiction, identity, correlation_id } + } } fn extract_event( - event: subxt::events::EventDetails, + event: subxt::events::EventDetails, ) -> Result, SubxtClientError> -where - C: subxt::Config, + where + C: subxt::Config, { - type Applied = (common::prov::ProvModel, common::identity::SignedIdentity, [u8; 16]); - type Contradicted = (common::prov::Contradiction, common::identity::SignedIdentity, [u8; 16]); - match (event.pallet_name(), event.variant_name(), event.field_bytes()) { - ("Chronicle", "Applied", mut event_bytes) => match Applied::decode(&mut event_bytes) { - Ok((prov_model, identity, correlation_id)) => - Ok(Some(ChronicleEvent::new_committed(prov_model, identity, correlation_id))), - Err(e) => { - tracing::error!("Failed to decode ProvModel: {}", e); - Err(e.into()) - }, - }, - ("Chronicle", "Contradicted", mut event_bytes) => { - match Contradicted::decode(&mut event_bytes) { - Ok((contradiction, identity, correlation_id)) => - Ok(ChronicleEvent::new_contradicted(contradiction, identity, correlation_id) - .into()), - Err(e) => { - tracing::error!("Failed to decode Contradiction: {}", e); - Err(e.into()) - }, - } - }, - (_pallet, _event, _) => Ok(None), - } + type Applied = (common::prov::ProvModel, common::identity::SignedIdentity, [u8; 16]); + type Contradicted = (common::prov::Contradiction, common::identity::SignedIdentity, [u8; 16]); + match (event.pallet_name(), event.variant_name(), event.field_bytes()) { + ("Chronicle", "Applied", mut event_bytes) => match Applied::decode(&mut event_bytes) { + Ok((prov_model, identity, correlation_id)) => + Ok(Some(ChronicleEvent::new_committed(prov_model, identity, correlation_id))), + Err(e) => { + tracing::error!("Failed to decode ProvModel: {}", e); + Err(e.into()) + } + }, + ("Chronicle", "Contradicted", mut event_bytes) => { + match Contradicted::decode(&mut event_bytes) { + Ok((contradiction, identity, correlation_id)) => + Ok(ChronicleEvent::new_contradicted(contradiction, identity, correlation_id) + .into()), + Err(e) => { + tracing::error!("Failed to decode Contradiction: {}", e); + Err(e.into()) + } + } + } + (_pallet, _event, _) => Ok(None), + } } impl LedgerEvent for ChronicleEvent { - fn correlation_id(&self) -> [u8; 16] { - match self { - Self::Committed { correlation_id, .. } => *correlation_id, - Self::Contradicted { correlation_id, .. } => *correlation_id, - } - } + fn correlation_id(&self) -> [u8; 16] { + match self { + Self::Committed { correlation_id, .. } => *correlation_id, + Self::Contradicted { correlation_id, .. } => *correlation_id, + } + } } #[async_trait::async_trait] impl LedgerEventCodec for ChronicleEventCodec -where - C: subxt::Config, + where + C: subxt::Config, { - type Error = SubxtClientError; - type Sink = ChronicleEvent; - type Source = subxt::events::EventDetails; - - async fn maybe_deserialize( - source: Self::Source, - ) -> Result, Self::Error> - where - Self: Sized, - { - match extract_event(source) { - Ok(Some(ev)) => Ok(Some((ev, Span::NotTraced))), - Ok(None) => Ok(None), - Err(e) => Err(e), - } - } + type Error = SubxtClientError; + type Sink = ChronicleEvent; + type Source = subxt::events::EventDetails; + + async fn maybe_deserialize( + source: Self::Source, + ) -> Result, Self::Error> + where + Self: Sized, + { + match extract_event(source) { + Ok(Some(ev)) => Ok(Some((ev, Span::NotTraced))), + Ok(None) => Ok(None), + Err(e) => Err(e), + } + } } pub struct ChronicleTransaction { - pub correlation_id: uuid::Uuid, - key: subxt::ext::sp_core::ecdsa::Pair, //We need the batcher key to sign transactions - pub identity: Arc, - pub operations: Arc>, + pub correlation_id: uuid::Uuid, + key: subxt::ext::sp_core::ecdsa::Pair, //We need the batcher key to sign transactions + pub identity: Arc, + pub operations: Arc>, } impl ChronicleTransaction { - pub async fn new( - signer: &ChronicleSigning, - identity: SignedIdentity, - operations: impl IntoIterator, - ) -> Result { - Ok(Self { - correlation_id: uuid::Uuid::new_v4(), - key: subxt::ext::sp_core::ecdsa::Pair::from_seed_slice( - &signer.copy_signing_key(BATCHER_NAMESPACE, BATCHER_PK).await?.to_bytes(), - ) - .unwrap(), - identity: identity.into(), - operations: Arc::new(operations.into_iter().collect::>()), - }) - } + pub async fn new( + signer: &ChronicleSigning, + identity: SignedIdentity, + operations: impl IntoIterator, + ) -> Result { + Ok(Self { + correlation_id: uuid::Uuid::new_v4(), + key: subxt::ext::sp_core::ecdsa::Pair::from_seed_slice( + &signer.copy_signing_key(BATCHER_NAMESPACE, BATCHER_PK).await?.to_bytes(), + ) + .unwrap(), + identity: identity.into(), + operations: Arc::new(operations.into_iter().collect::>()), + }) + } } // This type must match the signature of the extrinsic call #[derive( - scale_info::TypeInfo, - scale_encode::EncodeAsType, - parity_scale_codec::Encode, - parity_scale_codec::Decode, + scale_info::TypeInfo, + scale_encode::EncodeAsType, + parity_scale_codec::Encode, + parity_scale_codec::Decode, )] pub struct ApplyArgs { - pub operations: OperationSubmission, + pub operations: OperationSubmission, } #[async_trait::async_trait] impl LedgerTransaction for ChronicleTransaction { - type Error = Infallible; - type Payload = ApplyArgs; - - async fn as_payload(&self) -> Result { - Ok(ApplyArgs { - operations: OperationSubmission { - correlation_id: self.correlation_id.into_bytes(), - identity: self.identity.clone(), - items: self.operations.clone(), - }, - }) - } - - fn correlation_id(&self) -> [u8; 16] { - self.correlation_id.into_bytes() - } + type Error = Infallible; + type Payload = ApplyArgs; + + async fn as_payload(&self) -> Result { + Ok(ApplyArgs { + operations: OperationSubmission { + correlation_id: self.correlation_id.into_bytes(), + identity: self.identity.clone(), + items: self.operations.clone(), + }, + }) + } + + fn correlation_id(&self) -> [u8; 16] { + self.correlation_id.into_bytes() + } } ///Subxt signer needs to be infallible, so we need to keep a copy of key material here impl Signer for ChronicleTransaction -where - C: subxt::Config< - AccountId = AccountId32, - Address = MultiAddress, - Signature = MultiSignature, - >, + where + C: subxt::Config< + AccountId=AccountId32, + Address=MultiAddress, + Signature=MultiSignature, + >, { - // The account id for an ecdsa key is the blake2_256 hash of the compressed public key - fn account_id(&self) -> AccountId32 { - AccountId32::from(blake2_256(&self.key.public().0)) - } - - fn address(&self) -> MultiAddress<::AccountId, ()> { - MultiAddress::Id(>::account_id(self)) - } - - fn sign(&self, signer_payload: &[u8]) -> MultiSignature { - self.key.sign(signer_payload).into() - } + // The account id for an ecdsa key is the blake2_256 hash of the compressed public key + fn account_id(&self) -> AccountId32 { + AccountId32::from(blake2_256(&self.key.public().0)) + } + + fn address(&self) -> MultiAddress<::AccountId, ()> { + MultiAddress::Id(>::account_id(self)) + } + + fn sign(&self, signer_payload: &[u8]) -> MultiSignature { + self.key.sign(signer_payload).into() + } } #[async_trait::async_trait] pub trait SettingsLoader { - async fn load_settings_from_storage(&self) -> Result, SubxtClientError>; + async fn load_settings_from_storage(&self) -> Result, SubxtClientError>; } pub type ChronicleSubstrateClient = - SubstrateClient, ChronicleTransaction>; +SubstrateClient, ChronicleTransaction>; #[async_trait::async_trait] impl SettingsLoader for ChronicleSubstrateClient -where - C: subxt::Config, + where + C: subxt::Config, { - async fn load_settings_from_storage(&self) -> Result, SubxtClientError> { - tracing::debug!("Loading OPA settings from storage."); - let call = subxt::dynamic::runtime_api_call( - "Chronicle", - "get_opa_settings", - Composite::unnamed(vec![]), - ); - let settings: Option = self - .client - .runtime_api() - .at_latest() - .await? - .call(call) - .await - .map_err(SubxtClientError::from) - .and_then(|r| r.as_type::>().map_err(SubxtClientError::from))?; - - Ok(settings) - } + async fn load_settings_from_storage(&self) -> Result, SubxtClientError> { + tracing::debug!("Loading OPA settings from storage."); + let call = subxt::dynamic::runtime_api_call( + "Chronicle", + "get_opa_settings", + Composite::unnamed(vec![]), + ); + let settings: Option = self + .client + .runtime_api() + .at_latest() + .await? + .call(call) + .await + .map_err(SubxtClientError::from) + .and_then(|r| r.as_type::>().map_err(SubxtClientError::from))?; + + Ok(settings) + } } diff --git a/crates/protocol-substrate-opa/Cargo.toml b/crates/protocol-substrate-opa/Cargo.toml index 0859dc650..a1122a8e6 100644 --- a/crates/protocol-substrate-opa/Cargo.toml +++ b/crates/protocol-substrate-opa/Cargo.toml @@ -1,32 +1,32 @@ [package] edition = "2021" -name = "protocol-substrate-opa" +name = "protocol-substrate-opa" version = "0.7.5" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-trait = { workspace = true } +async-trait = { workspace = true } chronicle-signing = { workspace = true } -derivative = { workspace = true } -futures = { workspace = true } -hex = { workspace = true } -lazy_static = { workspace = true } -opa = { git = "https://github.com/chronicleworks/opa-rs", rev = "9fa2fbce" } -rand = { workspace = true } -rand_core = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde_json = { workspace = true } -subxt = { version = "0.34", features = ["substrate-compat"] } -thiserror = { workspace = true } -tokio = { workspace = true } -tracing = { workspace = true } -uuid = { workspace = true } +derivative = { workspace = true } +futures = { workspace = true } +hex = { workspace = true } +lazy_static = { workspace = true } +opa = { git = "https://github.com/chronicleworks/opa-rs", rev = "9fa2fbce" } +rand = { workspace = true } +rand_core = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +subxt = { version = "0.34", features = ["substrate-compat"] } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +uuid = { workspace = true } #Local dependencies -common = { path = "../common", features = ["parity-encoding", "std"] } -pallet-opa = { path = "../pallet-opa", default-features = false } -protocol-abstract = { path = "../protocol-abstract" } +common = { path = "../common", features = ["parity-encoding", "std"] } +pallet-opa = { path = "../pallet-opa", default-features = false } +protocol-abstract = { path = "../protocol-abstract" } protocol-substrate = { path = "../protocol-substrate" } [build-dependencies] diff --git a/crates/protocol-substrate-opa/src/lib.rs b/crates/protocol-substrate-opa/src/lib.rs index f6d3e4511..a486ca23c 100644 --- a/crates/protocol-substrate-opa/src/lib.rs +++ b/crates/protocol-substrate-opa/src/lib.rs @@ -7,14 +7,15 @@ use protocol_abstract::{LedgerEvent, LedgerEventCodec, Span}; use protocol_substrate::{SubstrateClient, SubxtClientError}; use serde::Serialize; use subxt::{ - ext::{ - codec::Decode, - sp_core::{blake2_256, Pair}, - }, - tx::Signer, - utils::{AccountId32, MultiAddress, MultiSignature}, + ext::{ + codec::Decode, + sp_core::{blake2_256, Pair}, + }, + tx::Signer, + utils::{AccountId32, MultiAddress, MultiSignature}, }; use transaction::OpaTransaction; + //pub mod submission; pub mod loader; pub mod submission_builder; @@ -23,113 +24,113 @@ pub mod transaction; pub use subxt::ext::sp_core::blake2_128 as policy_hash; pub struct OpaEventCodec -where - C: subxt::Config, + where + C: subxt::Config, { - _p: PhantomData, + _p: PhantomData, } //This type must match pallet::Event but we cannot reference it directly #[derive(Debug, Clone, Serialize)] pub enum OpaEvent { - PolicyUpdate { policy: common::opa::PolicyMeta, correlation_id: ChronicleTransactionId }, - KeyUpdate { keys: common::opa::Keys, correlation_id: ChronicleTransactionId }, + PolicyUpdate { policy: common::opa::PolicyMeta, correlation_id: ChronicleTransactionId }, + KeyUpdate { keys: common::opa::Keys, correlation_id: ChronicleTransactionId }, } impl OpaEvent { - fn new_policy_update( - policy_meta: common::opa::PolicyMeta, - transaction_id: ChronicleTransactionId, - ) -> Self { - OpaEvent::PolicyUpdate { policy: policy_meta, correlation_id: transaction_id } - } - - fn new_key_update(keys: common::opa::Keys, correlation_id: ChronicleTransactionId) -> Self { - OpaEvent::KeyUpdate { keys, correlation_id } - } + fn new_policy_update( + policy_meta: common::opa::PolicyMeta, + transaction_id: ChronicleTransactionId, + ) -> Self { + OpaEvent::PolicyUpdate { policy: policy_meta, correlation_id: transaction_id } + } + + fn new_key_update(keys: common::opa::Keys, correlation_id: ChronicleTransactionId) -> Self { + OpaEvent::KeyUpdate { keys, correlation_id } + } } fn extract_event( - event: subxt::events::EventDetails, + event: subxt::events::EventDetails, ) -> Result, SubxtClientError> -where - C: subxt::Config, + where + C: subxt::Config, { - type PolicyUpdate = (common::opa::codec::PolicyMetaV1, ChronicleTransactionId); - type KeyUpdate = (common::opa::codec::KeysV1, ChronicleTransactionId); - match (event.pallet_name(), event.variant_name(), event.field_bytes()) { - ("Opa", "PolicyUpdate", mut event_bytes) => match PolicyUpdate::decode(&mut event_bytes) { - Ok((meta, correlation_id)) => - Ok(Some(OpaEvent::new_policy_update(meta.try_into()?, correlation_id))), - Err(e) => { - tracing::error!("Failed to decode ProvModel: {}", e); - Err(e.into()) - }, - }, - ("Chronicle", "KeyUpdate", mut event_bytes) => match KeyUpdate::decode(&mut event_bytes) { - Ok((keys, correlation_id)) => - Ok(OpaEvent::new_key_update(keys.try_into()?, correlation_id).into()), - Err(e) => { - tracing::error!("Failed to decode Contradiction: {}", e); - Err(e.into()) - }, - }, - (_pallet, _event, _) => Ok(None), - } + type PolicyUpdate = (common::opa::codec::PolicyMetaV1, ChronicleTransactionId); + type KeyUpdate = (common::opa::codec::KeysV1, ChronicleTransactionId); + match (event.pallet_name(), event.variant_name(), event.field_bytes()) { + ("Opa", "PolicyUpdate", mut event_bytes) => match PolicyUpdate::decode(&mut event_bytes) { + Ok((meta, correlation_id)) => + Ok(Some(OpaEvent::new_policy_update(meta.try_into()?, correlation_id))), + Err(e) => { + tracing::error!("Failed to decode ProvModel: {}", e); + Err(e.into()) + } + }, + ("Chronicle", "KeyUpdate", mut event_bytes) => match KeyUpdate::decode(&mut event_bytes) { + Ok((keys, correlation_id)) => + Ok(OpaEvent::new_key_update(keys.try_into()?, correlation_id).into()), + Err(e) => { + tracing::error!("Failed to decode Contradiction: {}", e); + Err(e.into()) + } + }, + (_pallet, _event, _) => Ok(None), + } } #[async_trait::async_trait] impl LedgerEventCodec for OpaEventCodec -where - C: subxt::Config, + where + C: subxt::Config, { - type Error = SubxtClientError; - type Sink = OpaEvent; - type Source = subxt::events::EventDetails; - - async fn maybe_deserialize( - source: Self::Source, - ) -> Result, Self::Error> - where - Self: Sized, - { - match extract_event(source) { - Ok(Some(ev)) => Ok(Some((ev, Span::NotTraced))), - Ok(None) => Ok(None), - Err(e) => Err(e), - } - } + type Error = SubxtClientError; + type Sink = OpaEvent; + type Source = subxt::events::EventDetails; + + async fn maybe_deserialize( + source: Self::Source, + ) -> Result, Self::Error> + where + Self: Sized, + { + match extract_event(source) { + Ok(Some(ev)) => Ok(Some((ev, Span::NotTraced))), + Ok(None) => Ok(None), + Err(e) => Err(e), + } + } } impl LedgerEvent for OpaEvent { - fn correlation_id(&self) -> [u8; 16] { - match self { - Self::PolicyUpdate { correlation_id, .. } => **correlation_id, - Self::KeyUpdate { correlation_id, .. } => **correlation_id, - } - } + fn correlation_id(&self) -> [u8; 16] { + match self { + Self::PolicyUpdate { correlation_id, .. } => **correlation_id, + Self::KeyUpdate { correlation_id, .. } => **correlation_id, + } + } } impl Signer for OpaTransaction -where - C: subxt::Config< - AccountId = AccountId32, - Address = MultiAddress, - Signature = MultiSignature, - >, + where + C: subxt::Config< + AccountId=AccountId32, + Address=MultiAddress, + Signature=MultiSignature, + >, { - // The account id for an ecdsa key is the blake2_256 hash of the compressed public key - fn account_id(&self) -> AccountId32 { - AccountId32::from(blake2_256(&self.account_key().public().0)) - } - - fn address(&self) -> MultiAddress<::AccountId, ()> { - MultiAddress::Id(>::account_id(self)) - } - - fn sign(&self, signer_payload: &[u8]) -> MultiSignature { - self.account_key().sign(signer_payload).into() - } + // The account id for an ecdsa key is the blake2_256 hash of the compressed public key + fn account_id(&self) -> AccountId32 { + AccountId32::from(blake2_256(&self.account_key().public().0)) + } + + fn address(&self) -> MultiAddress<::AccountId, ()> { + MultiAddress::Id(>::account_id(self)) + } + + fn sign(&self, signer_payload: &[u8]) -> MultiSignature { + self.account_key().sign(signer_payload).into() + } } pub type OpaSubstrateClient = SubstrateClient, OpaTransaction>; diff --git a/crates/protocol-substrate-opa/src/loader.rs b/crates/protocol-substrate-opa/src/loader.rs index 4ef820f38..700fce516 100644 --- a/crates/protocol-substrate-opa/src/loader.rs +++ b/crates/protocol-substrate-opa/src/loader.rs @@ -1,124 +1,126 @@ use common::opa::{ - codec::PolicyV1, - std::{PolicyLoader, PolicyLoaderError}, - OpaSettings, + codec::PolicyV1, + std::{PolicyLoader, PolicyLoaderError}, + OpaSettings, }; use opa::bundle::Bundle; use protocol_substrate::{SubstrateClient, SubxtClientError}; use subxt::{ - ext::{scale_value::Composite, sp_core::blake2_128}, - PolkadotConfig, + ext::{scale_value::Composite, sp_core::blake2_128}, + PolkadotConfig, }; use tracing::{debug, error, info, instrument, warn}; use crate::{transaction::OpaTransaction, OpaEventCodec, OpaSubstrateClient}; pub struct SubstratePolicyLoader { - settings: OpaSettings, - policy: Option>, - client: OpaSubstrateClient, - addr_string: String, + settings: OpaSettings, + policy: Option>, + client: OpaSubstrateClient, + addr_string: String, } impl SubstratePolicyLoader { - pub fn new( - settings: OpaSettings, - client: &SubstrateClient, OpaTransaction>, - ) -> Self { - Self { - addr_string: settings.policy_address.to_string(), - settings, - policy: None, - client: client.clone(), - } - } - - #[instrument(level = "debug", skip(self), fields(policy_address = %self.settings.policy_address, entrypoint = %self.settings.entrypoint))] - async fn load_bundle_from_chain(&mut self) -> Result, SubxtClientError> { - if let Some(policy) = self.policy.as_ref() { - return Ok(policy.clone()); - } - let load_policy_from = self.settings.policy_address; - debug!(policy_address=?load_policy_from, "Loading policy from address"); - let load_policy_from = subxt::ext::scale_value::serde::to_value(load_policy_from)?; - loop { - tracing::debug!(target: "protocol_substrate_opa::loader", "Loading policy from storage."); - let call = subxt::dynamic::runtime_api_call( - "Opa", - "get_policy", - Composite::unnamed(vec![load_policy_from.clone()]), - ); - - let policy: PolicyV1 = self - .client - .client - .runtime_api() - .at_latest() - .await? - .call(call) - .await - .map_err(SubxtClientError::from) - .and_then(|r| r.as_type::().map_err(SubxtClientError::from))?; - - if let Some(policy) = Some(policy) { - return Ok(policy.into_vec()); - } else { - warn!("Policy not found, retrying in 2 seconds"); - tokio::time::sleep(std::time::Duration::from_secs(2)).await; - continue; - } - } - } + pub fn new( + settings: OpaSettings, + client: &SubstrateClient, OpaTransaction>, + ) -> Self { + Self { + addr_string: settings.policy_address.to_string(), + settings, + policy: None, + client: client.clone(), + } + } + + #[instrument(level = "debug", skip(self), fields( + policy_address = % self.settings.policy_address, entrypoint = % self.settings.entrypoint + ))] + async fn load_bundle_from_chain(&mut self) -> Result, SubxtClientError> { + if let Some(policy) = self.policy.as_ref() { + return Ok(policy.clone()); + } + let load_policy_from = self.settings.policy_address; + debug!(policy_address=?load_policy_from, "Loading policy from address"); + let load_policy_from = subxt::ext::scale_value::serde::to_value(load_policy_from)?; + loop { + tracing::debug!(target: "protocol_substrate_opa::loader", "Loading policy from storage."); + let call = subxt::dynamic::runtime_api_call( + "Opa", + "get_policy", + Composite::unnamed(vec![load_policy_from.clone()]), + ); + + let policy: PolicyV1 = self + .client + .client + .runtime_api() + .at_latest() + .await? + .call(call) + .await + .map_err(SubxtClientError::from) + .and_then(|r| r.as_type::().map_err(SubxtClientError::from))?; + + if let Some(policy) = Some(policy) { + return Ok(policy.into_vec()); + } else { + warn!("Policy not found, retrying in 2 seconds"); + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + continue; + } + } + } } #[async_trait::async_trait] impl PolicyLoader for SubstratePolicyLoader { - fn set_address(&mut self, _address: &str) { - unimplemented!() - } - - fn set_rule_name(&mut self, _name: &str) { - unimplemented!() - } - - fn set_entrypoint(&mut self, _entrypoint: &str) { - unimplemented!() - } - - fn get_address(&self) -> &str { - &self.addr_string - } - - fn get_rule_name(&self) -> &str { - &self.settings.policy_name - } - - fn get_entrypoint(&self) -> &str { - &self.settings.entrypoint - } - - fn get_policy(&self) -> &[u8] { - self.policy.as_ref().unwrap() - } - - async fn load_policy(&mut self) -> Result<(), PolicyLoaderError> { - let bundle = self - .load_bundle_from_chain() - .await - .map_err(|e| PolicyLoaderError::Substrate(e.into()))?; - info!(fetched_policy_bytes=?bundle.len(), "Fetched policy"); - if bundle.is_empty() { - error!("Policy not found: {}", self.get_rule_name()); - return Err(PolicyLoaderError::MissingPolicy(self.get_rule_name().to_string())); - } - self.load_policy_from_bundle(&Bundle::from_bytes(&*bundle)?) - } - - fn load_policy_from_bytes(&mut self, policy: &[u8]) { - self.policy = Some(policy.to_vec()) - } - - fn hash(&self) -> String { - hex::encode(blake2_128(self.policy.as_ref().unwrap())) - } + fn set_address(&mut self, _address: &str) { + unimplemented!() + } + + fn set_rule_name(&mut self, _name: &str) { + unimplemented!() + } + + fn set_entrypoint(&mut self, _entrypoint: &str) { + unimplemented!() + } + + fn get_address(&self) -> &str { + &self.addr_string + } + + fn get_rule_name(&self) -> &str { + &self.settings.policy_name + } + + fn get_entrypoint(&self) -> &str { + &self.settings.entrypoint + } + + fn get_policy(&self) -> &[u8] { + self.policy.as_ref().unwrap() + } + + async fn load_policy(&mut self) -> Result<(), PolicyLoaderError> { + let bundle = self + .load_bundle_from_chain() + .await + .map_err(|e| PolicyLoaderError::Substrate(e.into()))?; + info!(fetched_policy_bytes=?bundle.len(), "Fetched policy"); + if bundle.is_empty() { + error!("Policy not found: {}", self.get_rule_name()); + return Err(PolicyLoaderError::MissingPolicy(self.get_rule_name().to_string())); + } + self.load_policy_from_bundle(&Bundle::from_bytes(&*bundle)?) + } + + fn load_policy_from_bytes(&mut self, policy: &[u8]) { + self.policy = Some(policy.to_vec()) + } + + fn hash(&self) -> String { + hex::encode(blake2_128(self.policy.as_ref().unwrap())) + } } diff --git a/crates/protocol-substrate-opa/src/submission_builder.rs b/crates/protocol-substrate-opa/src/submission_builder.rs index f7926a0ce..4f20dfb0b 100644 --- a/crates/protocol-substrate-opa/src/submission_builder.rs +++ b/crates/protocol-substrate-opa/src/submission_builder.rs @@ -1,197 +1,197 @@ use core::panic; use std::{ - cell::RefCell, - sync::{Arc, Mutex}, + cell::RefCell, + sync::{Arc, Mutex}, }; use chronicle_signing::{ - ChronicleSigning, OpaKnownKeyNamesSigner, SecretError, WithSecret, OPA_NAMESPACE, + ChronicleSigning, OpaKnownKeyNamesSigner, SecretError, WithSecret, OPA_NAMESPACE, }; use common::{ - k256::{ - ecdsa::{Signature, SigningKey, VerifyingKey}, - pkcs8::{EncodePublicKey, LineEnding}, - schnorr::signature::Signer, - PublicKey, - }, - opa::{ - codec::{NewPublicKeyV1, SignedOperationPayloadV1}, - BootstrapRoot, NewPublicKey, OpaSubmission, Operation, Payload, Policy, RegisterKey, - RotateKey, SetPolicy, SignedOperation, SignedOperationPayload, - }, + k256::{ + ecdsa::{Signature, SigningKey, VerifyingKey}, + pkcs8::{EncodePublicKey, LineEnding}, + schnorr::signature::Signer, + PublicKey, + }, + opa::{ + codec::{NewPublicKeyV1, SignedOperationPayloadV1}, + BootstrapRoot, NewPublicKey, OpaSubmission, Operation, Payload, Policy, RegisterKey, + RotateKey, SetPolicy, SignedOperation, SignedOperationPayload, + }, }; use subxt::ext::codec::Encode; use uuid::Uuid; fn bootstrap_root(public_key: VerifyingKey) -> BootstrapRoot { - let public_key: PublicKey = public_key.into(); - BootstrapRoot { public_key: public_key.to_public_key_pem(LineEnding::CRLF).unwrap().into() } + let public_key: PublicKey = public_key.into(); + BootstrapRoot { public_key: public_key.to_public_key_pem(LineEnding::CRLF).unwrap().into() } } fn register_key( - id: impl AsRef, - public_key: &VerifyingKey, - overwrite_existing: bool, + id: impl AsRef, + public_key: &VerifyingKey, + overwrite_existing: bool, ) -> RegisterKey { - let public_key: PublicKey = public_key.into(); - RegisterKey { - id: id.as_ref().to_string(), - public_key: public_key.to_public_key_pem(LineEnding::CRLF).unwrap().into(), - overwrite_existing, - } + let public_key: PublicKey = public_key.into(); + RegisterKey { + id: id.as_ref().to_string(), + public_key: public_key.to_public_key_pem(LineEnding::CRLF).unwrap().into(), + overwrite_existing, + } } fn rotate_key(id: impl AsRef, old_key: &SigningKey, new_key: &SigningKey) -> RotateKey { - let new_verifying_public_key: PublicKey = new_key.verifying_key().into(); - let new_key_message = NewPublicKey { - id: id.as_ref().to_string(), - public_key: new_verifying_public_key.to_public_key_pem(LineEnding::CRLF).unwrap().into(), - }; - - let new_key_bytes = NewPublicKeyV1::from(new_key_message.clone()).encode(); - - let old_signature: Signature = old_key.sign(&new_key_bytes); - let old_verifying_key = old_key.verifying_key(); - let old_verifying_public_key: PublicKey = old_verifying_key.into(); - - let new_signature: Signature = new_key.sign(&new_key_bytes); - - RotateKey { - payload: new_key_message, - previous_signature: old_signature.to_vec(), - previous_signing_key: old_verifying_public_key - .to_public_key_pem(LineEnding::CRLF) - .unwrap() - .into(), - new_signature: new_signature.to_vec(), - new_signing_key: new_verifying_public_key - .to_public_key_pem(LineEnding::CRLF) - .unwrap() - .into(), - } + let new_verifying_public_key: PublicKey = new_key.verifying_key().into(); + let new_key_message = NewPublicKey { + id: id.as_ref().to_string(), + public_key: new_verifying_public_key.to_public_key_pem(LineEnding::CRLF).unwrap().into(), + }; + + let new_key_bytes = NewPublicKeyV1::from(new_key_message.clone()).encode(); + + let old_signature: Signature = old_key.sign(&new_key_bytes); + let old_verifying_key = old_key.verifying_key(); + let old_verifying_public_key: PublicKey = old_verifying_key.into(); + + let new_signature: Signature = new_key.sign(&new_key_bytes); + + RotateKey { + payload: new_key_message, + previous_signature: old_signature.to_vec(), + previous_signing_key: old_verifying_public_key + .to_public_key_pem(LineEnding::CRLF) + .unwrap() + .into(), + new_signature: new_signature.to_vec(), + new_signing_key: new_verifying_public_key + .to_public_key_pem(LineEnding::CRLF) + .unwrap() + .into(), + } } fn set_policy(id: impl AsRef, policy: Vec) -> SetPolicy { - SetPolicy { id: id.as_ref().to_owned(), policy: Policy::new(policy) } + SetPolicy { id: id.as_ref().to_owned(), policy: Policy::new(policy) } } enum BuildingMessage { - BootstrapRoot(BootstrapRoot), - RegisterKey(SignedOperation), - RotateKey(SignedOperation), - SetPolicy(SignedOperation), + BootstrapRoot(BootstrapRoot), + RegisterKey(SignedOperation), + RotateKey(SignedOperation), + SetPolicy(SignedOperation), } pub struct SubmissionBuilder { - message: Option, + message: Option, } impl SubmissionBuilder { - pub fn bootstrap_root(public_key: VerifyingKey) -> Self { - Self { message: Some(BuildingMessage::BootstrapRoot(bootstrap_root(public_key))) } - } - - pub async fn register_key( - id: impl AsRef, - new_key: &str, - signer: &ChronicleSigning, - overwrite_existing: bool, - ) -> Result { - let operation = SignedOperationPayload { - operation: Operation::RegisterKey(register_key( - id, - &signer.verifying_key(OPA_NAMESPACE, new_key).await?, - overwrite_existing, - )), - }; - - let signature = signer - .opa_sign(&SignedOperationPayloadV1::from(operation.clone()).encode()) - .await?; - let key: PublicKey = signer.opa_verifying().await?.into(); - let signed_operation = SignedOperation { - payload: operation, - signature: signature.to_vec(), - verifying_key: key.to_public_key_pem(LineEnding::CRLF).unwrap().into(), - }; - Ok(Self { message: Some(BuildingMessage::RegisterKey(signed_operation)) }) - } - - pub async fn rotate_key( - id: &str, - signer: &ChronicleSigning, - old_key: &str, - new_key: &str, - ) -> Result { - let extract_key: Arc>>> = - Arc::new(Mutex::new(None.into())); - - signer - .with_signing_key(OPA_NAMESPACE, old_key, |old_key| { - extract_key.lock().unwrap().replace(Some(old_key.clone())); - }) - .await?; - - let old_key = extract_key.lock().unwrap().borrow().clone().unwrap(); - - signer - .with_signing_key(OPA_NAMESPACE, new_key, |new_key| { - extract_key.lock().unwrap().replace(Some(new_key.clone())); - }) - .await?; - - let new_key = extract_key.lock().unwrap().borrow().clone().unwrap(); - - let operation = SignedOperationPayload { - operation: Operation::RotateKey(rotate_key(id, &old_key, &new_key)), - }; - - let signature = signer - .opa_sign(&SignedOperationPayloadV1::from(operation.clone()).encode()) - .await?; - let key: PublicKey = signer.opa_verifying().await?.into(); - - let signed_operation = SignedOperation { - payload: operation, - signature, - verifying_key: key.to_public_key_pem(LineEnding::CRLF).unwrap().into(), - }; - Ok(Self { message: Some(BuildingMessage::RotateKey(signed_operation)) }) - } - - pub async fn set_policy( - id: &str, - policy: Vec, - signer: &ChronicleSigning, - ) -> Result { - let operation = - SignedOperationPayload { operation: Operation::SetPolicy(set_policy(id, policy)) }; - let signature = signer - .opa_sign(&SignedOperationPayloadV1::from(operation.clone()).encode()) - .await?; - let key: PublicKey = signer.opa_verifying().await?.into(); - - let signed_operation = SignedOperation { - payload: operation, - signature, - verifying_key: key.to_public_key_pem(LineEnding::CRLF).unwrap().into(), - }; - - Ok(Self { message: Some(BuildingMessage::SetPolicy(signed_operation)) }) - } - - pub fn build(self, span_id: u64, correlation_id: Uuid) -> OpaSubmission { - OpaSubmission { - span_id, - correlation_id: correlation_id.into_bytes(), - version: "1.0".to_string(), - payload: match self.message { - Some(BuildingMessage::BootstrapRoot(message)) => Payload::BootstrapRoot(message), - Some(BuildingMessage::RotateKey(message)) => Payload::SignedOperation(message), - Some(BuildingMessage::SetPolicy(message)) => Payload::SignedOperation(message), - Some(BuildingMessage::RegisterKey(message)) => Payload::SignedOperation(message), - None => panic!("No message to build"), - }, - } - } + pub fn bootstrap_root(public_key: VerifyingKey) -> Self { + Self { message: Some(BuildingMessage::BootstrapRoot(bootstrap_root(public_key))) } + } + + pub async fn register_key( + id: impl AsRef, + new_key: &str, + signer: &ChronicleSigning, + overwrite_existing: bool, + ) -> Result { + let operation = SignedOperationPayload { + operation: Operation::RegisterKey(register_key( + id, + &signer.verifying_key(OPA_NAMESPACE, new_key).await?, + overwrite_existing, + )), + }; + + let signature = signer + .opa_sign(&SignedOperationPayloadV1::from(operation.clone()).encode()) + .await?; + let key: PublicKey = signer.opa_verifying().await?.into(); + let signed_operation = SignedOperation { + payload: operation, + signature: signature.to_vec(), + verifying_key: key.to_public_key_pem(LineEnding::CRLF).unwrap().into(), + }; + Ok(Self { message: Some(BuildingMessage::RegisterKey(signed_operation)) }) + } + + pub async fn rotate_key( + id: &str, + signer: &ChronicleSigning, + old_key: &str, + new_key: &str, + ) -> Result { + let extract_key: Arc>>> = + Arc::new(Mutex::new(None.into())); + + signer + .with_signing_key(OPA_NAMESPACE, old_key, |old_key| { + extract_key.lock().unwrap().replace(Some(old_key.clone())); + }) + .await?; + + let old_key = extract_key.lock().unwrap().borrow().clone().unwrap(); + + signer + .with_signing_key(OPA_NAMESPACE, new_key, |new_key| { + extract_key.lock().unwrap().replace(Some(new_key.clone())); + }) + .await?; + + let new_key = extract_key.lock().unwrap().borrow().clone().unwrap(); + + let operation = SignedOperationPayload { + operation: Operation::RotateKey(rotate_key(id, &old_key, &new_key)), + }; + + let signature = signer + .opa_sign(&SignedOperationPayloadV1::from(operation.clone()).encode()) + .await?; + let key: PublicKey = signer.opa_verifying().await?.into(); + + let signed_operation = SignedOperation { + payload: operation, + signature, + verifying_key: key.to_public_key_pem(LineEnding::CRLF).unwrap().into(), + }; + Ok(Self { message: Some(BuildingMessage::RotateKey(signed_operation)) }) + } + + pub async fn set_policy( + id: &str, + policy: Vec, + signer: &ChronicleSigning, + ) -> Result { + let operation = + SignedOperationPayload { operation: Operation::SetPolicy(set_policy(id, policy)) }; + let signature = signer + .opa_sign(&SignedOperationPayloadV1::from(operation.clone()).encode()) + .await?; + let key: PublicKey = signer.opa_verifying().await?.into(); + + let signed_operation = SignedOperation { + payload: operation, + signature, + verifying_key: key.to_public_key_pem(LineEnding::CRLF).unwrap().into(), + }; + + Ok(Self { message: Some(BuildingMessage::SetPolicy(signed_operation)) }) + } + + pub fn build(self, span_id: u64, correlation_id: Uuid) -> OpaSubmission { + OpaSubmission { + span_id, + correlation_id: correlation_id.into_bytes(), + version: "1.0".to_string(), + payload: match self.message { + Some(BuildingMessage::BootstrapRoot(message)) => Payload::BootstrapRoot(message), + Some(BuildingMessage::RotateKey(message)) => Payload::SignedOperation(message), + Some(BuildingMessage::SetPolicy(message)) => Payload::SignedOperation(message), + Some(BuildingMessage::RegisterKey(message)) => Payload::SignedOperation(message), + None => panic!("No message to build"), + }, + } + } } diff --git a/crates/protocol-substrate-opa/src/transaction.rs b/crates/protocol-substrate-opa/src/transaction.rs index f32887a01..01d8c9f64 100644 --- a/crates/protocol-substrate-opa/src/transaction.rs +++ b/crates/protocol-substrate-opa/src/transaction.rs @@ -1,5 +1,5 @@ use chronicle_signing::{ - ChronicleSigning, OwnedSecret, SecretError, BATCHER_NAMESPACE, BATCHER_PK, + ChronicleSigning, OwnedSecret, SecretError, BATCHER_NAMESPACE, BATCHER_PK, }; use common::opa::{codec::OpaSubmissionV1, OpaSubmission}; use protocol_abstract::LedgerTransaction; @@ -9,150 +9,150 @@ use thiserror::Error; #[derive(Debug, Error)] pub enum TransactionError { - #[error("Secret error: {0}")] - SecretError( - #[from] - #[source] - SecretError, - ), - #[error("Secret string error: {0}")] - SecretStringError( - #[from] - #[source] - SecretStringError, - ), + #[error("Secret error: {0}")] + SecretError( + #[from] + #[source] + SecretError, + ), + #[error("Secret string error: {0}")] + SecretStringError( + #[from] + #[source] + SecretStringError, + ), } #[derive(Clone)] // Note, the subxt client requires synchronous, infallible access to the signing keypair, so we // extract it on construction pub enum OpaTransaction { - BootstrapRoot(OpaSubmission, ChronicleSigning, subxt::ext::sp_core::ecdsa::Pair), - RotateRoot(OpaSubmission, ChronicleSigning, subxt::ext::sp_core::ecdsa::Pair), - RegisterKey(OpaSubmission, ChronicleSigning, String, bool, subxt::ext::sp_core::ecdsa::Pair), - RotateKey(OpaSubmission, ChronicleSigning, String, subxt::ext::sp_core::ecdsa::Pair), - SetPolicy(OpaSubmission, ChronicleSigning, String, subxt::ext::sp_core::ecdsa::Pair), + BootstrapRoot(OpaSubmission, ChronicleSigning, subxt::ext::sp_core::ecdsa::Pair), + RotateRoot(OpaSubmission, ChronicleSigning, subxt::ext::sp_core::ecdsa::Pair), + RegisterKey(OpaSubmission, ChronicleSigning, String, bool, subxt::ext::sp_core::ecdsa::Pair), + RotateKey(OpaSubmission, ChronicleSigning, String, subxt::ext::sp_core::ecdsa::Pair), + SetPolicy(OpaSubmission, ChronicleSigning, String, subxt::ext::sp_core::ecdsa::Pair), } impl OpaTransaction { - pub async fn bootstrap_root( - opa_submission: OpaSubmission, - signer: &ChronicleSigning, - ) -> Result { - Ok(Self::BootstrapRoot( - opa_submission, - signer.to_owned(), - subxt::ext::sp_core::ecdsa::Pair::from_seed_slice( - &signer.copy_signing_key(BATCHER_NAMESPACE, BATCHER_PK).await?.to_bytes(), - )?, - )) - } + pub async fn bootstrap_root( + opa_submission: OpaSubmission, + signer: &ChronicleSigning, + ) -> Result { + Ok(Self::BootstrapRoot( + opa_submission, + signer.to_owned(), + subxt::ext::sp_core::ecdsa::Pair::from_seed_slice( + &signer.copy_signing_key(BATCHER_NAMESPACE, BATCHER_PK).await?.to_bytes(), + )?, + )) + } - pub async fn rotate_root( - opa_submission: OpaSubmission, - signer: &ChronicleSigning, - ) -> Result { - Ok(Self::RotateRoot( - opa_submission, - signer.to_owned(), - subxt::ext::sp_core::ecdsa::Pair::from_seed_slice( - &signer.copy_signing_key(BATCHER_NAMESPACE, BATCHER_PK).await?.to_bytes(), - )?, - )) - } + pub async fn rotate_root( + opa_submission: OpaSubmission, + signer: &ChronicleSigning, + ) -> Result { + Ok(Self::RotateRoot( + opa_submission, + signer.to_owned(), + subxt::ext::sp_core::ecdsa::Pair::from_seed_slice( + &signer.copy_signing_key(BATCHER_NAMESPACE, BATCHER_PK).await?.to_bytes(), + )?, + )) + } - pub async fn register_key( - name: impl AsRef, - opa_submission: OpaSubmission, - signer: &ChronicleSigning, - overwrite_existing: bool, - ) -> Result { - Ok(Self::RegisterKey( - opa_submission, - signer.to_owned(), - name.as_ref().to_owned(), - overwrite_existing, - subxt::ext::sp_core::ecdsa::Pair::from_seed_slice( - &signer.copy_signing_key(BATCHER_NAMESPACE, BATCHER_PK).await?.to_bytes(), - )?, - )) - } + pub async fn register_key( + name: impl AsRef, + opa_submission: OpaSubmission, + signer: &ChronicleSigning, + overwrite_existing: bool, + ) -> Result { + Ok(Self::RegisterKey( + opa_submission, + signer.to_owned(), + name.as_ref().to_owned(), + overwrite_existing, + subxt::ext::sp_core::ecdsa::Pair::from_seed_slice( + &signer.copy_signing_key(BATCHER_NAMESPACE, BATCHER_PK).await?.to_bytes(), + )?, + )) + } - pub async fn rotate_key( - name: impl AsRef, - opa_submission: OpaSubmission, - signer: &ChronicleSigning, - ) -> Result { - Ok(Self::RegisterKey( - opa_submission, - signer.to_owned(), - name.as_ref().to_owned(), - false, - subxt::ext::sp_core::ecdsa::Pair::from_seed_slice( - &signer.copy_signing_key(BATCHER_NAMESPACE, BATCHER_PK).await?.to_bytes(), - )?, - )) - } + pub async fn rotate_key( + name: impl AsRef, + opa_submission: OpaSubmission, + signer: &ChronicleSigning, + ) -> Result { + Ok(Self::RegisterKey( + opa_submission, + signer.to_owned(), + name.as_ref().to_owned(), + false, + subxt::ext::sp_core::ecdsa::Pair::from_seed_slice( + &signer.copy_signing_key(BATCHER_NAMESPACE, BATCHER_PK).await?.to_bytes(), + )?, + )) + } - pub async fn set_policy( - name: impl AsRef, - opa_submission: OpaSubmission, - signer: &ChronicleSigning, - ) -> Result { - Ok(Self::SetPolicy( - opa_submission, - signer.to_owned(), - name.as_ref().to_owned(), - subxt::ext::sp_core::ecdsa::Pair::from_seed_slice( - &signer.copy_signing_key(BATCHER_NAMESPACE, BATCHER_PK).await?.to_bytes(), - )?, - )) - } + pub async fn set_policy( + name: impl AsRef, + opa_submission: OpaSubmission, + signer: &ChronicleSigning, + ) -> Result { + Ok(Self::SetPolicy( + opa_submission, + signer.to_owned(), + name.as_ref().to_owned(), + subxt::ext::sp_core::ecdsa::Pair::from_seed_slice( + &signer.copy_signing_key(BATCHER_NAMESPACE, BATCHER_PK).await?.to_bytes(), + )?, + )) + } - pub fn account_key(&self) -> &subxt::ext::sp_core::ecdsa::Pair { - match self { - OpaTransaction::BootstrapRoot(_, _, k) => k, - OpaTransaction::RotateRoot(_, _, k) => k, - OpaTransaction::RegisterKey(_, _, _, _, k) => k, - OpaTransaction::RotateKey(_, _, _, k) => k, - OpaTransaction::SetPolicy(_, _, _, k) => k, - } - } + pub fn account_key(&self) -> &subxt::ext::sp_core::ecdsa::Pair { + match self { + OpaTransaction::BootstrapRoot(_, _, k) => k, + OpaTransaction::RotateRoot(_, _, k) => k, + OpaTransaction::RegisterKey(_, _, _, _, k) => k, + OpaTransaction::RotateKey(_, _, _, k) => k, + OpaTransaction::SetPolicy(_, _, _, k) => k, + } + } - pub fn submission(&self) -> &OpaSubmission { - match self { - OpaTransaction::BootstrapRoot(o, _, _) => o, - OpaTransaction::RotateRoot(o, _, _) => o, - OpaTransaction::RegisterKey(o, _, _, _, _) => o, - OpaTransaction::RotateKey(o, _, _, _) => o, - OpaTransaction::SetPolicy(o, _, _, _) => o, - } - } + pub fn submission(&self) -> &OpaSubmission { + match self { + OpaTransaction::BootstrapRoot(o, _, _) => o, + OpaTransaction::RotateRoot(o, _, _) => o, + OpaTransaction::RegisterKey(o, _, _, _, _) => o, + OpaTransaction::RotateKey(o, _, _, _) => o, + OpaTransaction::SetPolicy(o, _, _, _) => o, + } + } } #[async_trait::async_trait] impl LedgerTransaction for OpaTransaction { - type Error = SecretError; - type Payload = OpaSubmissionV1; + type Error = SecretError; + type Payload = OpaSubmissionV1; - async fn as_payload(&self) -> Result { - Ok(match self.clone() { - OpaTransaction::BootstrapRoot(o, _, _) => o, - OpaTransaction::RotateRoot(o, _, _) => o, - OpaTransaction::RegisterKey(o, _, _, _, _) => o, - OpaTransaction::RotateKey(o, _, _, _) => o, - OpaTransaction::SetPolicy(o, _, _, _) => o, - } - .into()) - } + async fn as_payload(&self) -> Result { + Ok(match self.clone() { + OpaTransaction::BootstrapRoot(o, _, _) => o, + OpaTransaction::RotateRoot(o, _, _) => o, + OpaTransaction::RegisterKey(o, _, _, _, _) => o, + OpaTransaction::RotateKey(o, _, _, _) => o, + OpaTransaction::SetPolicy(o, _, _, _) => o, + } + .into()) + } - fn correlation_id(&self) -> [u8; 16] { - match self { - OpaTransaction::BootstrapRoot(o, _, _) => o.correlation_id, - OpaTransaction::RotateRoot(o, _, _) => o.correlation_id, - OpaTransaction::RegisterKey(o, _, _, _, _) => o.correlation_id, - OpaTransaction::RotateKey(o, _, _, _) => o.correlation_id, - OpaTransaction::SetPolicy(o, _, _, _) => o.correlation_id, - } - } + fn correlation_id(&self) -> [u8; 16] { + match self { + OpaTransaction::BootstrapRoot(o, _, _) => o.correlation_id, + OpaTransaction::RotateRoot(o, _, _) => o.correlation_id, + OpaTransaction::RegisterKey(o, _, _, _, _) => o.correlation_id, + OpaTransaction::RotateKey(o, _, _, _) => o.correlation_id, + OpaTransaction::SetPolicy(o, _, _, _) => o.correlation_id, + } + } } diff --git a/crates/protocol-substrate/Cargo.toml b/crates/protocol-substrate/Cargo.toml index f49c19067..f90aaa1b6 100644 --- a/crates/protocol-substrate/Cargo.toml +++ b/crates/protocol-substrate/Cargo.toml @@ -1,26 +1,26 @@ [package] edition = "2021" -name = "protocol-substrate" +name = "protocol-substrate" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = { workspace = true } +anyhow = { workspace = true } async-trait = { workspace = true } -derivative = { workspace = true } -futures = { workspace = true } -hex = { workspace = true } -k256 = { workspace = true } -serde = { workspace = true } -subxt = { version = "0.34", features = ["substrate-compat"] } -thiserror = { workspace = true } -tokio = { workspace = true } -tracing = { workspace = true } -uuid = { workspace = true } +derivative = { workspace = true } +futures = { workspace = true } +hex = { workspace = true } +k256 = { workspace = true } +serde = { workspace = true } +subxt = { version = "0.34", features = ["substrate-compat"] } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +uuid = { workspace = true } # Local dependencies chronicle-signing = { path = "../chronicle-signing" } -common = { path = "../common", features = ["parity-encoding", "std"] } -pallet-chronicle = { path = "../pallet-chronicle", features = ["std"] } +common = { path = "../common", features = ["parity-encoding", "std"] } +pallet-chronicle = { path = "../pallet-chronicle", features = ["std"] } protocol-abstract = { path = "../protocol-abstract" } diff --git a/crates/protocol-substrate/src/subxt_client.rs b/crates/protocol-substrate/src/subxt_client.rs index e29ff2388..833258754 100644 --- a/crates/protocol-substrate/src/subxt_client.rs +++ b/crates/protocol-substrate/src/subxt_client.rs @@ -2,599 +2,601 @@ use std::{convert::Infallible, marker::PhantomData, net::SocketAddr, time::Durat use derivative::Derivative; use futures::{ - stream::{self, BoxStream}, - FutureExt, StreamExt, TryFutureExt, TryStreamExt, + stream::{self, BoxStream}, + FutureExt, StreamExt, TryFutureExt, TryStreamExt, }; use pallet_chronicle::ChronicleTransactionId; use subxt::{ - backend::BackendExt, - config::ExtrinsicParams, - error::MetadataError, - ext::{ - codec::{Decode, Encode}, - sp_core::{twox_128, H256}, - }, - metadata::{ - types::{PalletMetadata, StorageEntryMetadata, StorageEntryType}, - DecodeWithMetadata, EncodeWithMetadata, - }, - storage::{DynamicAddress, StorageAddress}, - tx::{Payload, SubmittableExtrinsic}, - utils::{AccountId32, MultiAddress, MultiSignature}, - Metadata, OnlineClient, + backend::BackendExt, + config::ExtrinsicParams, + error::MetadataError, + ext::{ + codec::{Decode, Encode}, + sp_core::{twox_128, H256}, + }, + metadata::{ + types::{PalletMetadata, StorageEntryMetadata, StorageEntryType}, + DecodeWithMetadata, EncodeWithMetadata, + }, + storage::{DynamicAddress, StorageAddress}, + tx::{Payload, SubmittableExtrinsic}, + utils::{AccountId32, MultiAddress, MultiSignature}, + Metadata, OnlineClient, }; pub use subxt::Config; use protocol_abstract::{ - BlockId, FromBlock, LedgerEvent, LedgerEventCodec, LedgerEventContext, LedgerReader, - LedgerTransaction, LedgerWriter, Position, RetryLedger, WriteConsistency, + BlockId, FromBlock, LedgerEvent, LedgerEventCodec, LedgerEventContext, LedgerReader, + LedgerTransaction, LedgerWriter, Position, RetryLedger, WriteConsistency, }; #[derive(Derivative)] #[derivative(Clone(bound = ""))] pub struct SubstrateClient { - pub client: OnlineClient, - _p: PhantomData<(EC, T)>, + pub client: OnlineClient, + _p: PhantomData<(EC, T)>, } type ExtrinsicResult = - Result<(SubmittableExtrinsic>, [u8; 16]), subxt::Error>; +Result<(SubmittableExtrinsic>, [u8; 16]), subxt::Error>; impl SubstrateClient -where - C: subxt::Config< - Hash = subxt::utils::H256, - Address = MultiAddress, - Signature = MultiSignature, - >, - >::OtherParams: Default, - T: LedgerTransaction + Send + Sync, - ::Payload: subxt::ext::scale_encode::EncodeAsFields, - EC: LedgerEventCodec + Send + Sync, + where + C: subxt::Config< + Hash=subxt::utils::H256, + Address=MultiAddress, + Signature=MultiSignature, + >, + >::OtherParams: Default, + T: LedgerTransaction + Send + Sync, + ::Payload: subxt::ext::scale_encode::EncodeAsFields, + EC: LedgerEventCodec + Send + Sync, { - pub async fn connect(url: impl AsRef) -> Result { - Ok(Self { client: OnlineClient::from_url(url).await?, _p: Default::default() }) - } - - pub async fn connect_socket_addr(socket: SocketAddr) -> Result { - tracing::info!("Connecting to Substrate client via SocketAddr: {:?}", socket); - let client_result = OnlineClient::from_url(socket.to_string()).await; - match client_result { - Ok(client) => { - tracing::info!("Successfully connected to Substrate client."); - Ok(Self { client, _p: Default::default() }) - }, - Err(e) => { - tracing::error!("Failed to connect to Substrate client: {:?}", e); - Err(SubxtClientError::from(e)) - }, - } - } - - pub fn retry(&self, duration: Duration) -> RetryLedger - where - Self: LedgerReader + Sized, - { - tracing::debug!(target: "substrate_client", "Creating a retryable ledger reader."); - RetryLedger::new(self.clone(), duration) - } - - // TODO: bring the pallet / call name in from trait - - #[tracing::instrument(level="trace" , skip(self, signer, correlation_id, operations), fields(correlation_id = %hex::encode(correlation_id), ret))] - pub async fn create_extrinsic + Send>( - &self, - signer: &S, - correlation_id: [u8; 16], - operations: &T, - ) -> ExtrinsicResult { - let payload = Payload::new("Chronicle", "apply", operations.as_payload().await.unwrap()); - - self.client - .tx() - .create_signed(&payload, signer, Default::default()) - .await - .map(|extrinsic| (extrinsic, correlation_id)) - } - - pub async fn send_extrinsic( - &self, - consistency: WriteConsistency, - extrinsic: (SubmittableExtrinsic>, [u8; 16]), - ) -> Result { - extrinsic - .0 - .submit_and_watch() - .and_then(|progress| match consistency { - WriteConsistency::Weak => futures::future::ok(()).boxed(), - WriteConsistency::Strong => progress - .wait_for_finalized_success() - .and_then(|_| futures::future::ok(())) - .boxed(), - }) - .await - .map(|_| extrinsic.1.into()) - .map_err(|e| (e, ChronicleTransactionId::from(extrinsic.1))) - } + pub async fn connect(url: impl AsRef) -> Result { + Ok(Self { client: OnlineClient::from_url(url).await?, _p: Default::default() }) + } + + pub async fn connect_socket_addr(socket: SocketAddr) -> Result { + tracing::info!("Connecting to Substrate client via SocketAddr: {:?}", socket); + let client_result = OnlineClient::from_url(socket.to_string()).await; + match client_result { + Ok(client) => { + tracing::info!("Successfully connected to Substrate client."); + Ok(Self { client, _p: Default::default() }) + } + Err(e) => { + tracing::error!("Failed to connect to Substrate client: {:?}", e); + Err(SubxtClientError::from(e)) + } + } + } + + pub fn retry(&self, duration: Duration) -> RetryLedger + where + Self: LedgerReader + Sized, + { + tracing::debug!(target: "substrate_client", "Creating a retryable ledger reader."); + RetryLedger::new(self.clone(), duration) + } + + // TODO: bring the pallet / call name in from trait + + #[tracing::instrument(level = "trace", skip(self, signer, correlation_id, operations), fields( + correlation_id = % hex::encode(correlation_id), ret + ))] + pub async fn create_extrinsic + Send>( + &self, + signer: &S, + correlation_id: [u8; 16], + operations: &T, + ) -> ExtrinsicResult { + let payload = Payload::new("Chronicle", "apply", operations.as_payload().await.unwrap()); + + self.client + .tx() + .create_signed(&payload, signer, Default::default()) + .await + .map(|extrinsic| (extrinsic, correlation_id)) + } + + pub async fn send_extrinsic( + &self, + consistency: WriteConsistency, + extrinsic: (SubmittableExtrinsic>, [u8; 16]), + ) -> Result { + extrinsic + .0 + .submit_and_watch() + .and_then(|progress| match consistency { + WriteConsistency::Weak => futures::future::ok(()).boxed(), + WriteConsistency::Strong => progress + .wait_for_finalized_success() + .and_then(|_| futures::future::ok(())) + .boxed(), + }) + .await + .map(|_| extrinsic.1.into()) + .map_err(|e| (e, ChronicleTransactionId::from(extrinsic.1))) + } } #[derive(Debug, thiserror::Error)] pub enum SubxtClientError { - #[error("Subxt error: {0}")] - SubxtError( - #[from] - #[source] - subxt::Error, - ), - - #[error("Invalid block")] - InvalidBlock, - - #[error("Codec: {0}")] - Codec( - #[from] - #[source] - subxt::ext::codec::Error, - ), - - #[error("Decode: {0}")] - Decode( - #[from] - #[source] - subxt::error::DecodeError, - ), - - #[error("Serde: {0}")] - Serde( - #[from] - #[source] - subxt::ext::scale_value::serde::SerializerError, - ), + #[error("Subxt error: {0}")] + SubxtError( + #[from] + #[source] + subxt::Error, + ), + + #[error("Invalid block")] + InvalidBlock, + + #[error("Codec: {0}")] + Codec( + #[from] + #[source] + subxt::ext::codec::Error, + ), + + #[error("Decode: {0}")] + Decode( + #[from] + #[source] + subxt::error::DecodeError, + ), + + #[error("Serde: {0}")] + Serde( + #[from] + #[source] + subxt::ext::scale_value::serde::SerializerError, + ), } impl From for SubxtClientError { - fn from(_value: Infallible) -> Self { - unreachable!() - } + fn from(_value: Infallible) -> Self { + unreachable!() + } } impl SubstrateClient -where - C: subxt::Config, - H: subxt::config::Header + Send + Sync + Decode + Encode, - EC: LedgerEventCodec> - + Send - + Sync, - T: LedgerTransaction + Send + Sync, + where + C: subxt::Config, + H: subxt::config::Header + Send + Sync + Decode + Encode, + EC: LedgerEventCodec> + + Send + + Sync, + T: LedgerTransaction + Send + Sync, { - // Return child blocks of from_block, limiting to num_blocks if not none - async fn block_hashes_from( - &self, - from_block: C::Hash, - num_blocks: Option, - ) -> Result>, SubxtClientError> { - // Get the block at hash - let block = self.client.blocks().at(from_block).await?; - - let from_block_num = block.number(); - - let hashes = stream::unfold( - (self.client.clone(), from_block_num), - move |(client, block_num)| async move { - if let Some(num_blocks) = num_blocks { - if num_blocks == block_num { - return None; - } - } - - let block_hash: Result = client - .backend() - .call_decoding( - "chain_getBlockHash", - Some(&vec![block_num].encode()), - subxt::utils::H256::zero(), - ) - .await - .map_err(SubxtClientError::from); - - Some((block_hash, (client, block_num + 1))) - }, - ); - - Ok(Box::pin(hashes)) - } - - // Return events from `number_of_blocks` blocks from the client, starting at `from_block` - async fn events_for_block( - &self, - from_block: C::Hash, - ) -> Result::Sink>>, SubxtClientError> { - let header = self.client.backend().block_header(from_block).await?; - let block_num = match header { - Some(header) => Ok(header.number()), - None => { - tracing::error!("Block header is None"); - Err(SubxtClientError::InvalidBlock) - }, - }?; - - let events_for_block = match self.client.events().at(from_block).await { - Ok(events) => Ok(events), - Err(e) => { - tracing::error!("Failed to get events for block: {}", e); - Err(SubxtClientError::InvalidBlock) - }, - }?; - - let events_for_block = - stream::unfold(events_for_block.iter(), |mut events_for_block| async move { - match events_for_block.next() { - Some(Ok(event)) => match EC::maybe_deserialize(event).await { - Ok(Some(event)) => Some((event, events_for_block)), - _ => None, - }, - Some(Err(e)) => { - tracing::error!("Cannot fetch event {}", e); - None - }, - _ => None, - } - }); - - let event_stream = events_for_block.map(move |(event, span)| { - let correlation_id = event.correlation_id(); - ( - event, - ChronicleTransactionId::from(correlation_id), - BlockId::Block(from_block), - Position::from(block_num), - span, - ) - }); - - Ok(event_stream.boxed()) - } - - async fn stream_finalized_events( - &self, - ) -> Result::Sink>>, SubxtClientError> { - let blocks = self.client.blocks().subscribe_finalized().await?; - - let parsed_events = blocks - .map_err(SubxtClientError::from) - .and_then(|block| async move { - let block_num = block.number(); - let block_hash = block.hash(); - - let events = block.events().await.map_err(SubxtClientError::from); - - match events { - Err(e) => Err(e), - Ok(events) => { - let events = events - .iter() - .filter_map(|event| { - event - .map_err(SubxtClientError::from) - .and_then(|event| { - futures::executor::block_on(EC::maybe_deserialize(event)) - }) - .transpose() - .map(|event| { - event.map(|(event, span)| { - let correlation_id = event.correlation_id(); - ( - event, - ChronicleTransactionId::from(correlation_id), - BlockId::Block(block_hash), - Position::from(block_num), - span, - ) - }) - }) - }) - .collect::>(); - Ok(stream::iter(events)) - }, - } - }) - .boxed(); - - //Unfold and terminate stream on error - let flattened_stream = stream::unfold(parsed_events, |mut parsed_events| async move { - match parsed_events.next().await { - Some(Ok(events)) => Some((events, parsed_events)), - Some(Err(e)) => { - tracing::error!("Subscription error {}", e); - None - }, - _ => None, - } - }) - .flatten() - .boxed(); - - // Terminate on parse error in flattened stream, - let flattened_stream = - stream::unfold(flattened_stream, |mut flattened_stream| async move { - match flattened_stream.next().await { - Some(Err(e)) => { - tracing::error!("Event parse error {}", e); - None - }, - Some(Ok(event)) => Some((event, flattened_stream)), - None => None, - } - }) - .boxed(); - - Ok(flattened_stream) - } - - async fn historical_events( - &self, - from_block: C::Hash, - num_blocks: Option, - ) -> Result::Sink>>, SubxtClientError> { - let from_block_clone = self; - let block_hashes = from_block_clone.block_hashes_from(from_block, num_blocks).await?; - - let events = stream::unfold( - (block_hashes, self), - move |(mut block_hashes, self_clone)| async move { - let next_block_hash = block_hashes.next().await; - match next_block_hash { - Some(Ok(block_hash)) => { - let events = self_clone.events_for_block(block_hash).await; - match events { - Ok(events) => Some((events, (block_hashes, self_clone))), - Err(e) => { - tracing::error!("Subscription error {}", e); - None - }, - } - }, - Some(Err(e)) => { - tracing::error!("Subscription error {}", e); - None - }, - _ => None, - } - }, - ) - .flatten() - .boxed(); - - Ok(events) - } + // Return child blocks of from_block, limiting to num_blocks if not none + async fn block_hashes_from( + &self, + from_block: C::Hash, + num_blocks: Option, + ) -> Result>, SubxtClientError> { + // Get the block at hash + let block = self.client.blocks().at(from_block).await?; + + let from_block_num = block.number(); + + let hashes = stream::unfold( + (self.client.clone(), from_block_num), + move |(client, block_num)| async move { + if let Some(num_blocks) = num_blocks { + if num_blocks == block_num { + return None; + } + } + + let block_hash: Result = client + .backend() + .call_decoding( + "chain_getBlockHash", + Some(&vec![block_num].encode()), + subxt::utils::H256::zero(), + ) + .await + .map_err(SubxtClientError::from); + + Some((block_hash, (client, block_num + 1))) + }, + ); + + Ok(Box::pin(hashes)) + } + + // Return events from `number_of_blocks` blocks from the client, starting at `from_block` + async fn events_for_block( + &self, + from_block: C::Hash, + ) -> Result::Sink>>, SubxtClientError> { + let header = self.client.backend().block_header(from_block).await?; + let block_num = match header { + Some(header) => Ok(header.number()), + None => { + tracing::error!("Block header is None"); + Err(SubxtClientError::InvalidBlock) + } + }?; + + let events_for_block = match self.client.events().at(from_block).await { + Ok(events) => Ok(events), + Err(e) => { + tracing::error!("Failed to get events for block: {}", e); + Err(SubxtClientError::InvalidBlock) + } + }?; + + let events_for_block = + stream::unfold(events_for_block.iter(), |mut events_for_block| async move { + match events_for_block.next() { + Some(Ok(event)) => match EC::maybe_deserialize(event).await { + Ok(Some(event)) => Some((event, events_for_block)), + _ => None, + }, + Some(Err(e)) => { + tracing::error!("Cannot fetch event {}", e); + None + } + _ => None, + } + }); + + let event_stream = events_for_block.map(move |(event, span)| { + let correlation_id = event.correlation_id(); + ( + event, + ChronicleTransactionId::from(correlation_id), + BlockId::Block(from_block), + Position::from(block_num), + span, + ) + }); + + Ok(event_stream.boxed()) + } + + async fn stream_finalized_events( + &self, + ) -> Result::Sink>>, SubxtClientError> { + let blocks = self.client.blocks().subscribe_finalized().await?; + + let parsed_events = blocks + .map_err(SubxtClientError::from) + .and_then(|block| async move { + let block_num = block.number(); + let block_hash = block.hash(); + + let events = block.events().await.map_err(SubxtClientError::from); + + match events { + Err(e) => Err(e), + Ok(events) => { + let events = events + .iter() + .filter_map(|event| { + event + .map_err(SubxtClientError::from) + .and_then(|event| { + futures::executor::block_on(EC::maybe_deserialize(event)) + }) + .transpose() + .map(|event| { + event.map(|(event, span)| { + let correlation_id = event.correlation_id(); + ( + event, + ChronicleTransactionId::from(correlation_id), + BlockId::Block(block_hash), + Position::from(block_num), + span, + ) + }) + }) + }) + .collect::>(); + Ok(stream::iter(events)) + } + } + }) + .boxed(); + + //Unfold and terminate stream on error + let flattened_stream = stream::unfold(parsed_events, |mut parsed_events| async move { + match parsed_events.next().await { + Some(Ok(events)) => Some((events, parsed_events)), + Some(Err(e)) => { + tracing::error!("Subscription error {}", e); + None + } + _ => None, + } + }) + .flatten() + .boxed(); + + // Terminate on parse error in flattened stream, + let flattened_stream = + stream::unfold(flattened_stream, |mut flattened_stream| async move { + match flattened_stream.next().await { + Some(Err(e)) => { + tracing::error!("Event parse error {}", e); + None + } + Some(Ok(event)) => Some((event, flattened_stream)), + None => None, + } + }) + .boxed(); + + Ok(flattened_stream) + } + + async fn historical_events( + &self, + from_block: C::Hash, + num_blocks: Option, + ) -> Result::Sink>>, SubxtClientError> { + let from_block_clone = self; + let block_hashes = from_block_clone.block_hashes_from(from_block, num_blocks).await?; + + let events = stream::unfold( + (block_hashes, self), + move |(mut block_hashes, self_clone)| async move { + let next_block_hash = block_hashes.next().await; + match next_block_hash { + Some(Ok(block_hash)) => { + let events = self_clone.events_for_block(block_hash).await; + match events { + Ok(events) => Some((events, (block_hashes, self_clone))), + Err(e) => { + tracing::error!("Subscription error {}", e); + None + } + } + } + Some(Err(e)) => { + tracing::error!("Subscription error {}", e); + None + } + _ => None, + } + }, + ) + .flatten() + .boxed(); + + Ok(events) + } } #[async_trait::async_trait] impl LedgerWriter for SubstrateClient -where - C: subxt::Config< - Address = MultiAddress, - AccountId = AccountId32, - Hash = H256, - Signature = MultiSignature, - >, - >::OtherParams: Default + Send, - E: LedgerEventCodec> + Send + Sync, - T: LedgerTransaction + Send + Sync + subxt::tx::Signer, - ::Payload: subxt::ext::scale_encode::EncodeAsFields, + where + C: subxt::Config< + Address=MultiAddress, + AccountId=AccountId32, + Hash=H256, + Signature=MultiSignature, + >, + >::OtherParams: Default + Send, + E: LedgerEventCodec> + Send + Sync, + T: LedgerTransaction + Send + Sync + subxt::tx::Signer, + ::Payload: subxt::ext::scale_encode::EncodeAsFields, { - type Error = SubxtClientError; - type Submittable = (SubmittableExtrinsic>, [u8; 16]); - type Transaction = T; - - async fn pre_submit( - &self, - tx: Self::Transaction, - ) -> Result<(Self::Submittable, ChronicleTransactionId), Self::Error> { - let correlation_id = tx.correlation_id(); - let (ext, id) = self.create_extrinsic(&tx, correlation_id, &tx).await?; - - Ok(((ext, id), id.into())) - } - - async fn do_submit( - &self, - consistency: WriteConsistency, - submittable: Self::Submittable, - ) -> Result { - tracing::info!( + type Error = SubxtClientError; + type Submittable = (SubmittableExtrinsic>, [u8; 16]); + type Transaction = T; + + async fn pre_submit( + &self, + tx: Self::Transaction, + ) -> Result<(Self::Submittable, ChronicleTransactionId), Self::Error> { + let correlation_id = tx.correlation_id(); + let (ext, id) = self.create_extrinsic(&tx, correlation_id, &tx).await?; + + Ok(((ext, id), id.into())) + } + + async fn do_submit( + &self, + consistency: WriteConsistency, + submittable: Self::Submittable, + ) -> Result { + tracing::info!( target: "substrate_client", correlation_id = ?submittable.1, "Submitting extrinsic with correlation ID." ); - self.send_extrinsic(consistency, submittable) - .await - .map_err(|(e, id)| (e.into(), id)) - } + self.send_extrinsic(consistency, submittable) + .await + .map_err(|(e, id)| (e.into(), id)) + } } #[async_trait::async_trait] pub trait SubstrateStateReader { - type Error: std::error::Error; - /// Get the state entry at `address` - async fn get_state_entry( - &self, - pallet_name: &str, - entry_name: &str, - address: K, - ) -> Result, Self::Error>; + type Error: std::error::Error; + /// Get the state entry at `address` + async fn get_state_entry( + &self, + pallet_name: &str, + entry_name: &str, + address: K, + ) -> Result, Self::Error>; } pub(crate) fn validate_storage_address( - address: &Address, - pallet: PalletMetadata<'_>, + address: &Address, + pallet: PalletMetadata<'_>, ) -> Result<(), subxt::Error> { - if let Some(hash) = address.validation_hash() { - validate_storage(pallet, address.entry_name(), hash)?; - } - Ok(()) + if let Some(hash) = address.validation_hash() { + validate_storage(pallet, address.entry_name(), hash)?; + } + Ok(()) } /// Return details about the given storage entry. fn lookup_entry_details<'a>( - pallet_name: &str, - entry_name: &str, - metadata: &'a Metadata, + pallet_name: &str, + entry_name: &str, + metadata: &'a Metadata, ) -> Result<(PalletMetadata<'a>, &'a StorageEntryMetadata), subxt::Error> { - let pallet_metadata = metadata.pallet_by_name_err(pallet_name)?; - let storage_metadata = pallet_metadata - .storage() - .ok_or_else(|| MetadataError::StorageNotFoundInPallet(pallet_name.to_owned()))?; - let storage_entry = storage_metadata - .entry_by_name(entry_name) - .ok_or_else(|| MetadataError::StorageEntryNotFound(entry_name.to_owned()))?; - Ok((pallet_metadata, storage_entry)) + let pallet_metadata = metadata.pallet_by_name_err(pallet_name)?; + let storage_metadata = pallet_metadata + .storage() + .ok_or_else(|| MetadataError::StorageNotFoundInPallet(pallet_name.to_owned()))?; + let storage_entry = storage_metadata + .entry_by_name(entry_name) + .ok_or_else(|| MetadataError::StorageEntryNotFound(entry_name.to_owned()))?; + Ok((pallet_metadata, storage_entry)) } /// Validate a storage entry against the metadata. fn validate_storage( - pallet: PalletMetadata<'_>, - storage_name: &str, - hash: [u8; 32], + pallet: PalletMetadata<'_>, + storage_name: &str, + hash: [u8; 32], ) -> Result<(), subxt::Error> { - let Some(expected_hash) = pallet.storage_hash(storage_name) else { - return Err(MetadataError::IncompatibleCodegen.into()); - }; - if expected_hash != hash { - return Err(MetadataError::IncompatibleCodegen.into()); - } - Ok(()) + let Some(expected_hash) = pallet.storage_hash(storage_name) else { + return Err(MetadataError::IncompatibleCodegen.into()); + }; + if expected_hash != hash { + return Err(MetadataError::IncompatibleCodegen.into()); + } + Ok(()) } /// Fetch the return type out of a [`StorageEntryType`]. fn return_type_from_storage_entry_type(entry: &StorageEntryType) -> u32 { - match entry { - StorageEntryType::Plain(ty) => *ty, - StorageEntryType::Map { value_ty, .. } => *value_ty, - } + match entry { + StorageEntryType::Plain(ty) => *ty, + StorageEntryType::Map { value_ty, .. } => *value_ty, + } } /// Given some bytes, a pallet and storage name, decode the response. fn decode_storage_with_metadata( - bytes: &mut &[u8], - metadata: &Metadata, - storage_metadata: &StorageEntryMetadata, + bytes: &mut &[u8], + metadata: &Metadata, + storage_metadata: &StorageEntryMetadata, ) -> Result { - let ty = storage_metadata.entry_type(); - let return_ty = return_type_from_storage_entry_type(ty); - let val = T::decode_with_metadata(bytes, return_ty, metadata)?; - Ok(val) + let ty = storage_metadata.entry_type(); + let return_ty = return_type_from_storage_entry_type(ty); + let val = T::decode_with_metadata(bytes, return_ty, metadata)?; + Ok(val) } pub(crate) fn write_storage_address_root_bytes( - addr: &Address, - out: &mut Vec, + addr: &Address, + out: &mut Vec, ) { - out.extend(twox_128(addr.pallet_name().as_bytes())); - out.extend(twox_128(addr.entry_name().as_bytes())); + out.extend(twox_128(addr.pallet_name().as_bytes())); + out.extend(twox_128(addr.entry_name().as_bytes())); } pub(crate) fn storage_address_bytes( - addr: &Address, - metadata: &Metadata, + addr: &Address, + metadata: &Metadata, ) -> Result, subxt::Error> { - let mut bytes = Vec::new(); - write_storage_address_root_bytes(addr, &mut bytes); - addr.append_entry_bytes(metadata, &mut bytes)?; - Ok(bytes) + let mut bytes = Vec::new(); + write_storage_address_root_bytes(addr, &mut bytes); + addr.append_entry_bytes(metadata, &mut bytes)?; + Ok(bytes) } #[async_trait::async_trait] impl SubstrateStateReader for SubstrateClient -where - C: subxt::Config, - EC: LedgerEventCodec + Send + Sync, - T: protocol_abstract::LedgerTransaction + Send + Sync, + where + C: subxt::Config, + EC: LedgerEventCodec + Send + Sync, + T: protocol_abstract::LedgerTransaction + Send + Sync, { - type Error = SubxtClientError; - - async fn get_state_entry( - &self, - pallet_name: &str, - entry_name: &str, - address: K, - ) -> Result, Self::Error> { - let metadata = self.client.metadata(); - let (pallet, entry) = lookup_entry_details(pallet_name, entry_name, &metadata)?; - - let address = DynamicAddress::new(pallet_name, entry_name, vec![address]); - - // Metadata validation checks whether the static address given - // is likely to actually correspond to a real storage entry or not. - // if not, it means static codegen doesn't line up with runtime - // metadata. - validate_storage_address(&address, pallet)?; - - // Look up the return type ID to enable DecodeWithMetadata: - let lookup_bytes = storage_address_bytes(&address, &metadata)?; - if let Some(data) = self.client.storage().at_latest().await?.fetch_raw(lookup_bytes).await? - { - let val = decode_storage_with_metadata::(&mut &*data, &metadata, entry)?; - Ok(Some(val)) - } else { - Ok(None) - } - } + type Error = SubxtClientError; + + async fn get_state_entry( + &self, + pallet_name: &str, + entry_name: &str, + address: K, + ) -> Result, Self::Error> { + let metadata = self.client.metadata(); + let (pallet, entry) = lookup_entry_details(pallet_name, entry_name, &metadata)?; + + let address = DynamicAddress::new(pallet_name, entry_name, vec![address]); + + // Metadata validation checks whether the static address given + // is likely to actually correspond to a real storage entry or not. + // if not, it means static codegen doesn't line up with runtime + // metadata. + validate_storage_address(&address, pallet)?; + + // Look up the return type ID to enable DecodeWithMetadata: + let lookup_bytes = storage_address_bytes(&address, &metadata)?; + if let Some(data) = self.client.storage().at_latest().await?.fetch_raw(lookup_bytes).await? + { + let val = decode_storage_with_metadata::(&mut &*data, &metadata, entry)?; + Ok(Some(val)) + } else { + Ok(None) + } + } } #[async_trait::async_trait] impl LedgerReader for SubstrateClient -where - C: subxt::Config, - H: subxt::config::Header + Decode + Encode + Send + Sync, - EC: LedgerEventCodec> - + Send - + Sync, - T: LedgerTransaction + Send + Sync, + where + C: subxt::Config, + H: subxt::config::Header + Decode + Encode + Send + Sync, + EC: LedgerEventCodec> + + Send + + Sync, + T: LedgerTransaction + Send + Sync, { - type Error = SubxtClientError; - type Event = ::Sink; - type EventCodec = EC; - - // Get the block height of the ledger, and the id of the highest block - async fn block_height(&self) -> Result<(Position, BlockId), Self::Error> { - let block = self.client.blocks().at_latest().await?; - - Ok((Position::from(block.number()), BlockId::from(block.hash()))) - } - - /// Subscribe to state updates from this ledger, starting at `offset`, and - /// ending the stream after `number_of_blocks` blocks have been processed. - async fn state_updates( - &self, - // The block to start from - from_block: FromBlock, - // The number of blocks to process before ending the stream - number_of_blocks: Option, - ) -> Result>, Self::Error> { - // If fromblock is not head, then load in historical blocks and yield up to number_of_blocks - // events - let historical = match from_block { - FromBlock::Head => stream::empty().boxed(), - FromBlock::First => self - .historical_events(self.client.backend().genesis_hash().await?, number_of_blocks) - .await? - .boxed(), - FromBlock::BlockId(BlockId::Block(hash)) => - self.historical_events(hash, number_of_blocks).await?.boxed(), - FromBlock::BlockId(BlockId::Unknown) => self - .historical_events(self.client.backend().genesis_hash().await?, number_of_blocks) - .await? - .boxed(), - }; - - let all = historical.chain(self.stream_finalized_events().await?); - - //TODO: only take number_of_blocks worth of events before closing the stream - - Ok(all.boxed()) - } + type Error = SubxtClientError; + type Event = ::Sink; + type EventCodec = EC; + + // Get the block height of the ledger, and the id of the highest block + async fn block_height(&self) -> Result<(Position, BlockId), Self::Error> { + let block = self.client.blocks().at_latest().await?; + + Ok((Position::from(block.number()), BlockId::from(block.hash()))) + } + + /// Subscribe to state updates from this ledger, starting at `offset`, and + /// ending the stream after `number_of_blocks` blocks have been processed. + async fn state_updates( + &self, + // The block to start from + from_block: FromBlock, + // The number of blocks to process before ending the stream + number_of_blocks: Option, + ) -> Result>, Self::Error> { + // If fromblock is not head, then load in historical blocks and yield up to number_of_blocks + // events + let historical = match from_block { + FromBlock::Head => stream::empty().boxed(), + FromBlock::First => self + .historical_events(self.client.backend().genesis_hash().await?, number_of_blocks) + .await? + .boxed(), + FromBlock::BlockId(BlockId::Block(hash)) => + self.historical_events(hash, number_of_blocks).await?.boxed(), + FromBlock::BlockId(BlockId::Unknown) => self + .historical_events(self.client.backend().genesis_hash().await?, number_of_blocks) + .await? + .boxed(), + }; + + let all = historical.chain(self.stream_finalized_events().await?); + + //TODO: only take number_of_blocks worth of events before closing the stream + + Ok(all.boxed()) + } } diff --git a/crates/runtime-api-chronicle/Cargo.toml b/crates/runtime-api-chronicle/Cargo.toml index cef0b2de0..b529e3513 100644 --- a/crates/runtime-api-chronicle/Cargo.toml +++ b/crates/runtime-api-chronicle/Cargo.toml @@ -11,7 +11,7 @@ sp-api = { version = "23.0.0", default-features = false } sp-core = { version = "25.0.0", default-features = false } #Local dependencies -common = {path="../common", default-features=false, features=["parity-encoding"]} +common = { path = "../common", default-features = false, features = ["parity-encoding"] } [features] default = ["std"] diff --git a/crates/runtime-api-chronicle/src/lib.rs b/crates/runtime-api-chronicle/src/lib.rs index cdcb71087..90c6d1874 100644 --- a/crates/runtime-api-chronicle/src/lib.rs +++ b/crates/runtime-api-chronicle/src/lib.rs @@ -1,8 +1,9 @@ #![cfg_attr(not(feature = "std"), no_std)] + pub type Hash = sp_core::H256; pub mod chronicle_core { - pub use common::*; + pub use common::*; } // Here we declare the runtime API. It is implemented it the `impl` block in