diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 136cd2fe2..c831c3abf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,12 +27,13 @@ jobs: just start kubectl wait --for=condition=Ready --timeout=2m pod rpc-0 kubectl port-forward svc/rpc 9276:9276 & - - run: ./test/scenarios_test.py ${{matrix.backend}} + - run: ./test/scenarios_test.py --backend=${{matrix.backend}} rpc: runs-on: ubuntu-latest strategy: matrix: backend: [compose, k8s] + cli: [--rust_cli, ""] steps: - uses: actions/checkout@v4 - if: matrix.backend == 'compose' @@ -41,6 +42,9 @@ jobs: uses: extractions/setup-just@v1 - if: matrix.backend == 'k8s' uses: medyagh/setup-minikube@master + - if: matrix.cli == '--rust_cli' + run: | + cargo build - if: matrix.backend == 'k8s' run: | pip install --upgrade pip @@ -48,7 +52,7 @@ jobs: just start kubectl wait --for=condition=Ready --timeout=2m pod rpc-0 kubectl port-forward svc/rpc 9276:9276 & - - run: ./test/rpc_test.py ${{matrix.backend}} + - run: ./test/rpc_test.py --backend=${{matrix.backend}} ${{matrix.cli}} graph: runs-on: ubuntu-latest strategy: @@ -69,7 +73,7 @@ jobs: just start kubectl wait --for=condition=Ready --timeout=2m pod rpc-0 kubectl port-forward svc/rpc 9276:9276 & - - run: ./test/graph_test.py ${{matrix.backend}} + - run: ./test/graph_test.py --backend=${{matrix.backend}} ln: runs-on: ubuntu-latest strategy: @@ -90,7 +94,7 @@ jobs: just start kubectl wait --for=condition=Ready --timeout=2m pod rpc-0 kubectl port-forward svc/rpc 9276:9276 & - - run: ./test/ln_test.py ${{matrix.backend}} + - run: ./test/ln_test.py --backend=${{matrix.backend}} build: needs: [scenarios, rpc, graph, ln] # Only run if the others complete successfully as it's slow runs-on: ubuntu-latest @@ -112,4 +116,4 @@ jobs: just start kubectl wait --for=condition=Ready --timeout=2m pod rpc-0 kubectl port-forward svc/rpc 9276:9276 & - - run: ./test/build_branch_test.py ${{matrix.backend}} + - run: ./test/build_branch_test.py --backend=${{matrix.backend}} diff --git a/.gitignore b/.gitignore index 54b2e7c75..c7aa45d49 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,8 @@ __pycache__ warnet.egg-info .python-version .env + + +# Added by cargo + +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000..54ef9f0c1 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2460 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "serde", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" + +[[package]] +name = "async-lock" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-trait" +version = "0.1.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + +[[package]] +name = "bytecount" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cc" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fancy-regex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set", + "regex", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fraction" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3027ae1df8d41b4bed2241c8fdad4acc1e7af60c8e17743534b545e77182d678" +dependencies = [ + "lazy_static", + "num", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +dependencies = [ + "gloo-timers", + "send_wrapper", +] + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "gloo-net" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "http", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "h2" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.2.6", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "log", + "rustls 0.21.10", + "rustls-native-certs 0.6.3", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "iso8601" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924e5d73ea28f59011fec52a0d12185d496a9b075d360657aed2a5707f701153" +dependencies = [ + "nom", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonrpsee" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cdbb7cb6f3ba28f5b212dd250ab4483105efc3e381f5c8bb90340f14f0a2cc3" +dependencies = [ + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-http-client", + "jsonrpsee-types", + "jsonrpsee-wasm-client", + "jsonrpsee-ws-client", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab2e14e727d2faf388c99d9ca5210566ed3b044f07d92c29c3611718d178380" +dependencies = [ + "futures-channel", + "futures-util", + "gloo-net", + "http", + "jsonrpsee-core", + "pin-project", + "rustls-native-certs 0.7.0", + "rustls-pki-types", + "soketto", + "thiserror", + "tokio", + "tokio-rustls 0.25.0", + "tokio-util", + "tracing", + "url", + "webpki-roots", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71962a1c49af43adf81d337e4ebc93f3c915faf6eccaa14d74e255107dfd7723" +dependencies = [ + "anyhow", + "async-lock", + "async-trait", + "beef", + "futures-timer", + "futures-util", + "hyper", + "jsonrpsee-types", + "pin-project", + "rustc-hash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "wasm-bindgen-futures", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c13987da51270bda2c1c9b40c19be0fe9b225c7a0553963d8f17e683a50ce84" +dependencies = [ + "async-trait", + "hyper", + "hyper-rustls", + "jsonrpsee-core", + "jsonrpsee-types", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e53c72de6cd2ad6ac1aa6e848206ef8b736f92ed02354959130373dfa5b3cbd" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonrpsee-wasm-client" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae2c3f2411052b4a831cb7a34cd1498e0d8b9309bd49fca67567634ff64023d" +dependencies = [ + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", +] + +[[package]] +name = "jsonrpsee-ws-client" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8a07ab8da9a283b906f6735ddd17d3680158bb72259e853441d1dd0167079ec" +dependencies = [ + "http", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", + "url", +] + +[[package]] +name = "jsonschema" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a071f4f7efc9a9118dfb627a0a94ef247986e1ab8606a4c806ae2b3aa3b6978" +dependencies = [ + "ahash", + "anyhow", + "base64 0.21.7", + "bytecount", + "clap", + "fancy-regex", + "fraction", + "getrandom", + "iso8601", + "itoa", + "memchr", + "num-cmp", + "once_cell", + "parking_lot", + "percent-encoding", + "regex", + "reqwest", + "serde", + "serde_json", + "time", + "url", + "uuid", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.5.0", + "libc", + "redox_syscall", +] + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minidom" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe549115a674f5ec64c754d85e37d6f42664bd0ef4ffb62b619489ad99c6cb1a" +dependencies = [ + "quick-xml", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-cmp" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa" + +[[package]] +name = "num-complex" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "ordered-multimap" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4d6a8c22fc714f0c2373e6091bf6f5e9b37b1bc0b1184874b7e0a4e303d318f" +dependencies = [ + "dlv-list", + "hashbrown 0.14.3", +] + +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap 2.2.6", +] + +[[package]] +name = "petgraph-graphml" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f99237d858a7675759c308324348d81742553ed1d65ddce0854a55688e8487b" +dependencies = [ + "petgraph", + "xml-rs", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettytable-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" +dependencies = [ + "csv", + "encode_unicode", + "is-terminal", + "lazy_static", + "term", + "unicode-width", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe1e430bdcf30c9fdc25053b9c459bb1a4672af4617b6c783d7d91dc17c6bbb0" +dependencies = [ + "memchr", +] + +[[package]] +name = "quickxml_to_serde" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "286b05c7a00b356ff6ac5218e10d628e0a3be02e777d067ca7286d353c3c407e" +dependencies = [ + "minidom", + "regex", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rust-ini" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d625ed57d8f49af6cfa514c42e1a71fadcff60eb0b1c517ff82fe41aa025b41" +dependencies = [ + "cfg-if", + "ordered-multimap", + "trim-in-place", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.2", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile 1.0.4", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.1.1", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f48172685e6ff52a556baa527774f61fcaa884f59daf3375c62a3f1cd2549dab" +dependencies = [ + "base64 0.21.7", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "soketto" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +dependencies = [ + "base64 0.13.1", + "bytes", + "futures", + "httparse", + "log", + "rand", + "sha-1", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.10", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.3", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "trim-in-place" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "warnet" +version = "0.1.0" +dependencies = [ + "anyhow", + "base64 0.22.0", + "clap", + "jsonrpsee", + "jsonschema", + "petgraph", + "petgraph-graphml", + "prettytable-rs", + "quickxml_to_serde", + "rand", + "rust-ini", + "serde", + "serde_json", + "tokio", + "xmltree", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "xml-rs" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" + +[[package]] +name = "xmltree" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" +dependencies = [ + "indexmap 1.9.3", + "xml-rs", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..84a569c1b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "warnet" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.81" +base64 = "0.22.0" +clap = { version = "4.5.4", features = ["derive"] } +jsonrpsee = { version = "0.22.3", features = ["http-client", "client"] } +jsonschema = "0.17.1" +petgraph = "0.6.4" +petgraph-graphml = "3.0.0" +prettytable-rs = "0.10.0" +quickxml_to_serde = "0.6.0" +rand = "0.8.5" +rust-ini = "0.21.0" +serde = { version = "1.0.197", features = ["derive"] } +serde_json = "1.0.115" +tokio = { version = "1.36.0", features = ["rt-multi-thread"] } +xmltree = { version = "0.10.3", features = ["indexmap"] } + +[[bin]] +name = "warcli" +path = "src/rust-cli/main.rs" diff --git a/docs/install.md b/docs/install.md index 8f2fea085..a5211e56e 100644 --- a/docs/install.md +++ b/docs/install.md @@ -70,14 +70,27 @@ cd warnet ## Install Warnet -### Optional: use a virtual Python environment such as `venv` +The Warnet server and cli tool need to be installed using PIP: -```bash -python3 -m venv .venv # Use alternative venv manager if desired -source .venv/bin/activate -``` +> [!TIP] +> Use a python virtual environment such as venv +> ```bash +> python3 -m venv .venv # Use alternative venv manager if desired +> source .venv/bin/activate +> ``` ```bash pip install --upgrade pip pip install -e . ``` + +### Experimental Rust cli tool + +There is an experimental Rust cli tool which can be built using `cargo`: + +```bash +# build +cargo build +# Run +./target/debug/warcli help +``` diff --git a/src/rust-cli/debug.rs b/src/rust-cli/debug.rs new file mode 100644 index 000000000..4fdbb0af0 --- /dev/null +++ b/src/rust-cli/debug.rs @@ -0,0 +1,34 @@ +use anyhow::Context; +use jsonrpsee::core::params::ObjectParams; +use std::path::PathBuf; + +use clap::Subcommand; + +use crate::rpc_call::make_rpc_call; + +#[derive(Subcommand, Debug)] +pub enum DebugCommand { + /// Generate the docker-compose file for a given graph_file + GenerateCompose { + /// Path to graph file to generate from + graph_file_path: PathBuf, + }, +} + +pub async fn handle_debug_command( + command: &DebugCommand, + mut rpc_params: ObjectParams, +) -> anyhow::Result<()> { + match command { + DebugCommand::GenerateCompose { graph_file_path } => { + rpc_params + .insert("graph_file", graph_file_path.to_str()) + .context("Adding graph_file_path to rpc params")?; + let data = make_rpc_call("generate_compose", rpc_params) + .await + .context("Calling generate_compose RPC")?; + println!("Docker-compose file generated: {:?}", data); + } + } + Ok(()) +} diff --git a/src/rust-cli/general.rs b/src/rust-cli/general.rs new file mode 100644 index 000000000..9209d3722 --- /dev/null +++ b/src/rust-cli/general.rs @@ -0,0 +1,89 @@ +use crate::rpc_call::make_rpc_call; +use anyhow::Context; +use jsonrpsee::core::params::ObjectParams; + +use crate::util::pretty_print_value; + +pub enum NodeType { + LnCli, + BitcoinCli, +} + +pub async fn handle_rpc_commands( + node_type: NodeType, + node_index: &u64, + method: &String, + rpc_params: &Option>, + mut params: ObjectParams, +) -> anyhow::Result<()> { + params + .insert("node", node_index) + .context("add node_index param")?; + params + .insert("method", method) + .context("add method param")?; + if let Some(p) = rpc_params { + params.insert("params", p).context("add rpc params")?; + } + let data = match node_type { + NodeType::LnCli => make_rpc_call("tank_lncli", params) + .await + .context("make RPC call lncli")?, + NodeType::BitcoinCli => make_rpc_call("tank_bcli", params) + .await + .context("make RPC call bitcoin-cli")?, + }; + pretty_print_value(&data).context("Pretty print the result")?; + Ok(()) +} + +pub async fn handle_debug_log_command(node: &u64, mut params: ObjectParams) -> anyhow::Result<()> { + params + .insert("node", node) + .context("add node_index param")?; + let data = make_rpc_call("tank_debug_log", params) + .await + .context("make RPC call tank_debug_log")?; + pretty_print_value(&data).context("pretty print result")?; + Ok(()) +} + +pub async fn handle_messages_command( + node_a: &u64, + node_b: &u64, + mut params: ObjectParams, +) -> anyhow::Result<()> { + params + .insert("node_a", node_a) + .context("add node_b param")?; + params + .insert("node_b", node_b) + .context("add node_b param")?; + let data = make_rpc_call("tank_messages", params) + .await + .context("Failed to make RPC call tank_messages")?; + pretty_print_value(&data).context("pretty print result")?; + Ok(()) +} + +pub async fn handle_grep_logs_command( + pattern: &String, + mut params: ObjectParams, +) -> anyhow::Result<()> { + params + .insert("pattern", pattern) + .context("add pattern param")?; + let data = make_rpc_call("logs_grep", params) + .await + .context("Failed to make RPC call tank_messages")?; + pretty_print_value(&data).context("pretty print result")?; + Ok(()) +} + +pub async fn handle_stop_command(params: ObjectParams) -> anyhow::Result<()> { + let data = make_rpc_call("server_stop", params) + .await + .context("Failed to make RPC call server_stop")?; + pretty_print_value(&data).context("pretty print result")?; + Ok(()) +} diff --git a/src/rust-cli/graph.rs b/src/rust-cli/graph.rs new file mode 100644 index 000000000..70dbf88c8 --- /dev/null +++ b/src/rust-cli/graph.rs @@ -0,0 +1,270 @@ +use rand::seq::SliceRandom; +use rand::thread_rng; +use std::borrow::Cow; +use std::fs::File; +use std::io::{BufReader, Cursor, Read}; +use std::path::{Path, PathBuf}; + +use crate::util::{dump_bitcoin_conf, parse_bitcoin_conf}; +use anyhow::Context; +use clap::Subcommand; +use jsonschema::JSONSchema; +use petgraph::graph::{DiGraph, NodeIndex}; +use petgraph_graphml::GraphMl; +use quickxml_to_serde::{xml_string_to_json, Config}; +use xmltree::{Element, EmitterConfig, XMLNode}; + +#[derive(Subcommand, Debug)] +pub enum GraphCommand { + /// Create a cycle graph with 7 extra random outbounds per node. + Create { + /// Number of nodes in the graph + number: usize, + /// Write graph to this file path + #[arg(short, long)] + outfile: Option, + /// Bitcoin Core version to set on nodes + #[arg(short, long)] + version: Option, + /// config values to add to bitcoin.conf + #[arg(short, long)] + bitcoin_conf: Option, + }, + /// (broken) Validate a *.graphml file against the graph schema + Validate { + /// Path to graph file + graph: PathBuf, + }, +} + +fn create_graph(number: usize) -> anyhow::Result> { + // Create initial cycle graph + let mut graph = DiGraph::new(); + let mut last_node: Option = None; + let mut first_node: Option = None; + + for _ in 0..number { + let new_node = graph.add_node(()); + if let Some(ln) = last_node { + graph.add_edge(ln, new_node, ()); // Add an edge from the last node to the new one + } else { + first_node = Some(new_node); + } + last_node = Some(new_node); + } + + if number > 0 { + if let (Some(first), Some(last)) = (first_node, last_node) { + graph.add_edge(last, first, ()); // Connect the last node to the first to complete the cycle + } + } + + // Add more outbound connections to each node + for node in graph.node_indices() { + let mut candidates = Vec::new(); + for potential_target in graph.node_indices() { + if node != potential_target && !graph.contains_edge(node, potential_target) { + candidates.push(potential_target); + } + } + // Add 7 extra outbounds + for _ in 0..7 { + if let Some(&random_target) = candidates.choose(&mut thread_rng()) { + graph.add_edge(node, random_target, ()); + // Remove the selected target from candidates to avoid trying to add it again + candidates.retain(|&x| x != random_target); + } + } + } + Ok(graph) +} + +fn handle_bitcoin_conf(bitcoin_conf: Option<&Path>) -> String { + let mut conf_contents: String = String::new(); + if bitcoin_conf.is_some() { + let conf = parse_bitcoin_conf(bitcoin_conf); + // Iterate over sections and their properties + for (section, prop) in &conf { + println!("[{:?}]", section); + for (key, value) in prop.iter() { + println!("{}={}", key, value); + } + } + conf_contents += &dump_bitcoin_conf(&conf); + }; + conf_contents +} + +fn convert_to_graphml(graph: &petgraph::graph::DiGraph<(), ()>) -> anyhow::Result> { + let graphml = GraphMl::new(graph).pretty_print(true); + let mut buf = Vec::new(); + graphml + .to_writer(&mut buf) + .expect("Failed to write GraphML data"); + Ok(buf) +} + +fn add_custom_attributes( + graphml_buf: Vec, + version_str: &str, + bitcoin_conf: &str, +) -> xmltree::Element { + let cursor = Cursor::new(graphml_buf); + let mut graphml_element = Element::parse(cursor).unwrap(); + + let keys = vec![ + ("version", "string"), + ("bitcoin_config", "string"), + ("tc_netem", "string"), + ("build_args", "string"), + ("exporter", "boolean"), + ("collect_logs", "boolean"), + ("image", "string"), + ]; + for (attr_name, attr_type) in keys { + let mut key_element = Element::new("key"); + key_element + .attributes + .insert("attr.name".to_string(), attr_name.to_string()); + key_element + .attributes + .insert("attr.type".to_string(), attr_type.to_string()); + key_element + .attributes + .insert("for".to_string(), "node".to_string()); + key_element + .attributes + .insert("id".to_string(), attr_name.to_string()); + + graphml_element.children.push(XMLNode::Element(key_element)); + } + // Find the element first + if let Some(XMLNode::Element(graph_el)) = graphml_element + .children + .iter_mut() + .find(|e| matches!(e, XMLNode::Element(el) if el.name == "graph")) + { + // Iterate over the children of the element to find elements + for node in graph_el.children.iter_mut() { + if let XMLNode::Element(ref mut el) = node { + if el.name == "node" { + let data_elements = vec![ + ("version", version_str), + ("bitcoin_config", bitcoin_conf), + ("tc_netem", ""), + ("build_args", ""), + ("exporter", "false"), + ("collect_logs", "false"), + ("image", ""), + ]; + for (key, value) in data_elements { + let mut data_element = Element::new("data"); + data_element + .attributes + .insert("key".to_string(), key.to_string()); + data_element.children.push(XMLNode::Text(value.to_string())); + el.children.push(XMLNode::Element(data_element)); + } + } + } + } + } + graphml_element +} + +fn validate_schema(graph: &PathBuf) -> anyhow::Result<()> { + let f = + File::open("src/schema/graph_schema.json").context("Read schema file from source dir")?; + let reader = BufReader::new(f); + let schema: serde_json::Value = + serde_json::from_reader(reader).context("Read schema into serde_json Value")?; + // TODO: this hack needing a static lifetime seems wrong. Try and fix it + let schema_static: &'static serde_json::Value = Box::leak(Box::new(schema)); + let compiled_schema = + JSONSchema::compile(schema_static).context("compile schema into JSONSchema")?; + + // Parse graph into serde_json::Value + let f = File::open(graph).context("Read xml graph from disk")?; + let mut reader = BufReader::new(f); + let mut xml_string = String::new(); + reader.read_to_string(&mut xml_string)?; + let conf = Config::new_with_defaults(); + let json = xml_string_to_json(xml_string, &conf).context("Convert xml string to JSON")?; + println!("{}", json); + + // Validate schema + // TODO: THIS IS NOT WORKING + // We need to iterate over nodes and edges and call validate on each one, I think? + let result = compiled_schema.validate(&json); + if let Err(errors) = result { + for error in errors { + println!("Validation error: {}", error); + println!("Instance path: {}", error.instance_path); + } + } + println!("Schema validated successfully!"); + + Ok(()) +} + +fn handle_create_command( + number: &usize, + outfile: &Option, + version: &Option, + bitcoin_conf: &Option, +) -> anyhow::Result<()> { + let version_str: &str = version.as_deref().unwrap_or("26.0"); + + // Create empty graph + let graph: DiGraph<(), ()> = create_graph(*number).context("creating graph")?; + + // Parse any custom bitcoin conf + let bitcoin_conf: String = handle_bitcoin_conf(bitcoin_conf.as_deref()); + + // Dump graph to graphml format + let graphml_buf: Vec = convert_to_graphml(&graph).context("Convert to graphml")?; + + // Configure graphml output settings + let graphml_config = EmitterConfig { + write_document_declaration: true, + perform_indent: true, + indent_string: Cow::Borrowed(" "), + line_separator: Cow::Borrowed("\n"), + ..Default::default() // Keep other defaults + }; + + // Add custom elements to graph + let modified_graphml: xmltree::Element = + add_custom_attributes(graphml_buf, version_str, bitcoin_conf.as_str()); + + // Write either to outfile or stdout + match outfile { + Some(path) => { + let file = File::create(path).context("Writing final graphml file")?; + modified_graphml.write_with_config(file, graphml_config)?; + } + None => { + let stdout = std::io::stdout(); + let handle = stdout.lock(); + modified_graphml.write_with_config(handle, graphml_config)?; + } + } + Ok(()) +} + +pub async fn handle_graph_command(command: &GraphCommand) -> anyhow::Result<()> { + match command { + GraphCommand::Create { + number, + outfile, + version, + bitcoin_conf, + } => handle_create_command(number, outfile, version, bitcoin_conf) + .context("Create a graph")?, + + GraphCommand::Validate { graph } => { + let _ = validate_schema(graph).context("Validating graph schema"); + } + } + Ok(()) +} diff --git a/src/rust-cli/image.rs b/src/rust-cli/image.rs new file mode 100644 index 000000000..86a5413ed --- /dev/null +++ b/src/rust-cli/image.rs @@ -0,0 +1,160 @@ +use anyhow::bail; +use clap::Subcommand; +use std::fs; +use std::process::{Command, Stdio}; + +#[derive(Subcommand, Debug)] +pub enum ImageCommand { + /// Build a bitcoind/bitcoin-cli docker image. + /// Optionally deploy to remote registry using --action=push, otherwise image is loaded to local registry. + Build { + /// Github repo e.g. bitcoin/bitcoin + #[arg(long)] + repo: String, + /// Branch e.g. v27.0 + #[arg(long)] + branch: String, + /// docker registry e.g. user/repo + #[arg(long)] + registry: String, + /// docker image tag(s) to apply e.g. 27.0-warnet + #[arg(long)] + tag: String, + /// Custom Bitcoin Core build args to use + #[arg(long)] + build_args: Option, + /// Arches to build for (multiple arches only supported with action=push) + #[arg(long)] + arches: Option, + /// Load (to local) or push (to remote) registry + #[arg(long)] + action: Option, + }, +} + +const ARCHES: [&str; 3] = ["amd64", "arm64", "armv7"]; + +fn run_command(command: &str) -> anyhow::Result { + println!("Executing: {}", command); + let mut child = Command::new("bash") + .arg("-c") + .arg(command) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .spawn()?; + + let output = child.wait()?; + + if output.success() { + Ok(true) + } else { + bail!("Command failed") + } +} + +fn build_image( + repo: &String, + branch: &String, + docker_registry: &String, + tag: &String, + build_args: &Option, + arches: &Option, + action: &Option, +) -> anyhow::Result<()> { + let build_args = match build_args { + Some(args) => format!("\"{}\"", args), + None => "\"--disable-tests --without-gui --disable-bench --disable-fuzz-binary --enable-suppress-external-warnings \"".to_string(), + }; + + let mut build_arches = vec![]; + match arches { + Some(a) => build_arches.extend(a.split(',').map(String::from)), + None => build_arches.push("amd64".to_string()), + } + + for arch in &build_arches { + if !ARCHES.contains(&arch.as_str()) { + println!("Error: {} is not a supported architecture", arch); + bail!("Unsupported architecture: {}", arch); + } + } + + println!("repo={}", repo); + println!("branch={}", branch); + println!("docker_registry={}", docker_registry); + println!("tag={}", tag); + println!("build_args={}", build_args); + println!("build_arches={:?}", build_arches); + + if !fs::metadata("src/templates") + .map(|m| m.is_dir()) + .unwrap_or(false) + { + println!("Directory src/templates does not exist."); + println!("Please run this script from the project root."); + bail!("src/templates directory not found"); + } + + let builder_name = "bitcoind-builder"; + let create_builder_cmd = format!("docker buildx create --name {} --use", builder_name); + let creat_builder_res = run_command(&create_builder_cmd); + if creat_builder_res.is_err() { + let use_builder_cmd = format!("docker buildx use {}", builder_name); + run_command(&use_builder_cmd)?; + } + + let image_full_name = format!("{}:{}", docker_registry, tag); + println!("image_full_name={}", image_full_name); + + let platforms = build_arches + .iter() + .map(|arch| format!("linux/{}", arch)) + .collect::>() + .join(","); + + let action = match action { + Some(action) => action, + None => "load", + }; + let build_command = format!( + "docker buildx build --platform {} --build-arg REPO={} --build-arg BRANCH={} --build-arg BUILD_ARGS={} --tag {} --file src/templates/Dockerfile . --{}", + platforms, repo, branch, build_args, image_full_name, action + ); + + println!("Using build_command={}", build_command); + + let res = run_command(&build_command); + if res.is_ok() { + println!("Build completed"); + } else { + println!("Build failed."); + } + + let cleanup_builder_cmd = format!("docker buildx rm {}", builder_name); + let cleanup_res = run_command(&cleanup_builder_cmd); + if cleanup_res.is_ok() { + println!("Buildx builder removed successfully."); + } else { + println!("Warning: Failed to remove the buildx builder."); + } + + match res { + Ok(true) => Ok(()), + Ok(false) => bail!("Build command failed, but no specific error was provided."), + Err(e) => bail!("Build command failed with error: {}", e), + } +} + +pub async fn handle_image_command(command: &ImageCommand) -> anyhow::Result<()> { + match command { + ImageCommand::Build { + repo, + branch, + registry, + tag, + build_args, + arches, + action, + } => build_image(repo, branch, registry, tag, build_args, arches, action), + } +} diff --git a/src/rust-cli/main.rs b/src/rust-cli/main.rs new file mode 100644 index 000000000..548ded168 --- /dev/null +++ b/src/rust-cli/main.rs @@ -0,0 +1,163 @@ +use anyhow::Context; +use clap::{Parser, Subcommand}; + +mod debug; +mod general; +mod graph; +mod image; +mod network; +mod rpc_call; +mod scenarios; +mod util; +use crate::debug::{handle_debug_command, DebugCommand}; +use crate::general::*; +use crate::graph::{handle_graph_command, GraphCommand}; +use crate::image::{handle_image_command, ImageCommand}; +use crate::network::{handle_network_command, NetworkCommand}; +use crate::scenarios::{handle_scenario_command, ScenarioCommand}; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Cli { + #[arg(long)] + /// The warnet network command corresponds to + network: Option, + + #[command(subcommand)] + command: Option, +} + +#[derive(Subcommand, Debug)] +enum Commands { + /// Debug commands (deprecated) + Debug { + #[command(subcommand)] + command: Option, + }, + /// Fetch the Bitcoin Core debug log from a node + DebugLog { + /// Node index (integer) + node: u64, + }, + /// Graph commands + Graph { + #[command(subcommand)] + command: Option, + }, + /// Grep combined logs using regex + GrepLogs { + /// Pattern to search for (as regex) + pattern: String, + }, + /// Build a warnet-ready bitcoind docker image from a github branch + Image { + #[command(subcommand)] + command: Option, + }, + /// Call "lncli ..." on a node + LnCli { + /// Node index (integer) + node: u64, + /// lncli method + method: String, + /// Optional arguments to method + params: Option>, + }, + /// Fetch bitcoin P2P messages sent between two nodes + Messages { + /// First node + node_a: u64, + /// Second node + node_b: u64, + }, + /// Network commands + Network { + #[command(subcommand)] + command: Option, + }, + /// Call "bitcoin-cli ..." on a node + Rpc { + /// Node index (integer) + node: u64, + /// bitcoin-cli method + #[arg(allow_hyphen_values = true)] + method: String, + /// Optional arguments to method + params: Option>, + }, + /// Scenario commands + Scenarios { + #[command(subcommand)] + command: Option, + }, + /// Stop warnet server + Stop {}, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let cli = Cli::parse(); + let mut rpc_params = jsonrpsee::core::params::ObjectParams::new(); + if let Some(network_value) = &cli.network { + rpc_params + .insert("network", network_value) + .context("Adding --network to rpc_params")?; + } + + match &cli.command { + Some(Commands::Debug { command }) => { + if let Some(command) = command { + handle_debug_command(command, rpc_params).await?; + } + } + Some(Commands::Graph { command }) => { + if let Some(command) = command { + handle_graph_command(command).await?; + } + } + Some(Commands::Network { command }) => { + if let Some(command) = command { + handle_network_command(command, rpc_params).await?; + } + } + Some(Commands::Scenarios { command }) => { + if let Some(command) = command { + handle_scenario_command(command, rpc_params).await?; + } + } + Some(Commands::Rpc { + node, + method, + params, + }) => { + handle_rpc_commands(NodeType::BitcoinCli, node, method, params, rpc_params).await?; + } + Some(Commands::LnCli { + node, + method, + params, + }) => { + handle_rpc_commands(NodeType::LnCli, node, method, params, rpc_params).await?; + } + Some(Commands::DebugLog { node }) => { + handle_debug_log_command(node, rpc_params).await?; + } + Some(Commands::Image { command }) => { + if let Some(command) = command { + handle_image_command(command).await?; + } + } + Some(Commands::Messages { node_a, node_b }) => { + handle_messages_command(node_a, node_b, rpc_params).await?; + } + Some(Commands::GrepLogs { pattern }) => { + handle_grep_logs_command(pattern, rpc_params).await?; + } + Some(Commands::Stop {}) => { + handle_stop_command(rpc_params).await?; + } + None => println!("No command provided"), + } + + Ok(()) +} diff --git a/src/rust-cli/network.rs b/src/rust-cli/network.rs new file mode 100644 index 000000000..edb04d515 --- /dev/null +++ b/src/rust-cli/network.rs @@ -0,0 +1,160 @@ +use anyhow::{bail, Context}; +use base64::{engine::general_purpose, Engine as _}; +use clap::Subcommand; +use jsonrpsee::core::params::ObjectParams; +use prettytable::{cell, Row, Table}; +use serde_json::Value; +use std::path::PathBuf; + +use crate::rpc_call::make_rpc_call; + +#[derive(Subcommand, Debug)] +pub enum NetworkCommand { + /// Start a network from a graph_file + Start { + /// Path to graph file + graph_file: PathBuf, + /// Force overwite config dir if already exists + #[arg(long, short)] + force: bool, + }, + /// Bring a network back up + Up {}, + /// Take a network down + Down {}, + /// Get network info + Info {}, + /// Shows the status of a network + Status {}, + /// Return if network is connected + Connected {}, + /// Export network details for sim-ln + Export {}, +} + +fn graph_file_to_b64(graph_file: &PathBuf) -> anyhow::Result { + let file_contents = std::fs::read(graph_file).context("Failed to read graph file from fs")?; + Ok(general_purpose::STANDARD.encode(file_contents)) +} + +fn handle_network_status_response(data: serde_json::Value) -> anyhow::Result<()> { + if let serde_json::Value::Array(items) = &data { + for item in items { + if let (Some(tank_index), Some(bitcoin_status)) = ( + item.get("tank_index").and_then(|v| v.as_i64()), + item.get("bitcoin_status").and_then(|v| v.as_str()), + ) { + println!("Tank: {:<6} Bitcoin: {}", tank_index, bitcoin_status); + } else { + bail!("Error: Response item is missing expected fields"); + } + } + } else { + bail!("Error: Expected an array in the response"); + } + Ok(()) +} + +fn handle_network_start_response(data: serde_json::Value) -> anyhow::Result<()> { + // warnet table + if let Some(warnet_headers) = data["warnet_headers"].as_array() { + let mut table = Table::new(); + let headers: Vec<_> = warnet_headers + .iter() + .map(|header| header.as_str().unwrap_or("")) + .collect(); + table.add_row(Row::new( + headers.into_iter().map(|header| cell!(header)).collect(), + )); + // just used as fallback if warnet or its array content is missing + let v: Vec = vec![Value::Null]; + + if let Some(warnet) = data["warnet"].as_array().and_then(|row| row.first()) { + let row_data: Vec<_> = match warnet.as_array() { + Some(array) => array, + None => &v, + } + .iter() + .map(|item| item.as_str().unwrap_or("")) + .collect(); + table.add_row(Row::new( + row_data.into_iter().map(|row| cell!(row)).collect(), + )); + } + table.printstd(); + } else { + bail!("No warnet table headers found in response") + } + // tanks table + if let Some(tank_headers) = data["tank_headers"].as_array() { + let mut table = Table::new(); + let headers: Vec<_> = tank_headers + .iter() + .map(|header| header.as_str().unwrap_or("")) + .collect(); + table.add_row(Row::new( + headers.into_iter().map(|header| cell!(header)).collect(), + )); + + let v: Vec = vec![Value::Null]; + if let Some(tanks) = data["tanks"].as_array() { + for tank in tanks { + let row_data: Vec<_> = match tank.as_array() { + Some(array) => array, + None => &v, + } + .iter() + .map(|item| item.as_str().unwrap_or("")) + .collect(); + table.add_row(Row::new( + row_data.into_iter().map(|row| cell!(row)).collect(), + )); + } + } + table.printstd(); + } else { + bail!("no tank headers found in response") + } + Ok(()) +} + +pub async fn handle_network_command( + command: &NetworkCommand, + mut params: ObjectParams, +) -> anyhow::Result<()> { + let (request, params) = match command { + NetworkCommand::Start { graph_file, force } => { + let b64_graph = + graph_file_to_b64(graph_file).context("Reading graph file to base 64")?; + params + .insert("graph_file", b64_graph) + .context("Add base64 graph file to params")?; + params + .insert("force", *force) + .context("Add force bool to params")?; + ("network_from_file", params) + } + NetworkCommand::Up {} => ("network_up", params), + NetworkCommand::Down {} => ("network_down", params), + NetworkCommand::Info {} => ("network_info", params), + NetworkCommand::Status {} => ("network_status", params), + NetworkCommand::Connected {} => ("network_connected", params), + NetworkCommand::Export {} => ("network_export", params), + }; + + let data = make_rpc_call(request, params).await?; + match request { + "network_status" => { + handle_network_status_response(data).context("Handling network status response")? + } + "network_from_file" => { + handle_network_start_response(data.clone()) + .context("Handling network start response")?; + } + _ => { + println!("{}", data) + } + } + // TODO: add response handling for other network commands + Ok(()) +} diff --git a/src/rust-cli/rpc_call.rs b/src/rust-cli/rpc_call.rs new file mode 100644 index 000000000..814d34734 --- /dev/null +++ b/src/rust-cli/rpc_call.rs @@ -0,0 +1,13 @@ +use jsonrpsee::{core::client::ClientT, http_client::HttpClientBuilder}; + +use serde_json::Value; + +pub async fn make_rpc_call( + request: &str, + params: jsonrpsee::core::params::ObjectParams, +) -> anyhow::Result { + let url = "http://127.0.0.1:9276/api"; + let client = HttpClientBuilder::default().build(url)?; + let response = client.request::(request, params).await?; + Ok(response) +} diff --git a/src/rust-cli/scenarios.rs b/src/rust-cli/scenarios.rs new file mode 100644 index 000000000..daf3dbfb8 --- /dev/null +++ b/src/rust-cli/scenarios.rs @@ -0,0 +1,183 @@ +use crate::rpc_call::make_rpc_call; +use anyhow::{bail, Context}; +use base64::{engine::general_purpose, Engine as _}; +use clap::Subcommand; +use jsonrpsee::core::params::ObjectParams; +use prettytable::{row, Table}; +use std::path::PathBuf; + +#[derive(Subcommand, Debug)] +pub enum ScenarioCommand { + /// List available scenarios in the Warnet Test Framework + Available {}, + /// Run a scenario file from remote repository (on warnet server) + Run { + /// Scenario name + scenario: String, + /// Arguments to scenario + additional_args: Vec, + }, + /// Run a local scenario file by sending it to the server + RunFile { + /// Path to scenario file + scenario_path: PathBuf, + /// Arguments to scenario + additional_args: Vec, + }, + /// List active scenarios + Active {}, + /// Stop a scenario + Stop { + /// PID of scenario to stop + pid: u64, + }, +} +async fn handle_available(params: ObjectParams) -> anyhow::Result<()> { + let data = make_rpc_call("scenarios_available", params) + .await + .context("Making RPC to fetch available scenarios")?; + if let serde_json::Value::Array(scenarios) = data { + let mut table = Table::new(); + table.add_row(row!["Scenario", "Description"]); + for scenario in scenarios { + if let serde_json::Value::Array(details) = scenario { + if details.len() == 2 { + let name = details[0].as_str().unwrap_or("Unknown"); + let description = details[1].as_str().unwrap_or("No description"); + table.add_row(row![name, description]); + } + } + } + table.printstd(); + } else { + bail!("Unexpected response format."); + } + Ok(()) +} + +async fn handle_run( + mut params: ObjectParams, + scenario: &str, + additional_args: &Vec, +) -> anyhow::Result<()> { + params + .insert("scenario", scenario) + .context("Add scenario to params")?; + params + .insert("additional_args", additional_args) + .context("Add additional_args to params")?; + let data = make_rpc_call("scenarios_run", params) + .await + .context("Making RPC call to run scenario with remote file")?; + println!("{:?}", data); + Ok(()) +} + +async fn handle_run_file( + mut params: ObjectParams, + scenario_path: &PathBuf, + additional_args: &Vec, +) -> anyhow::Result<()> { + let file_contents = std::fs::read(scenario_path).context("Failed to read scenario file")?; + let scenario_base64 = general_purpose::STANDARD.encode(file_contents); + params + .insert("scenario_base64", scenario_base64) + .context("Adding scenario to params")?; + params + .insert("additional_args", additional_args) + .context("Adding additional_args to params")?; + let data = make_rpc_call("scenarios_run_file", params) + .await + .context("Making RPC call to run scenario with local file")?; + println!("{:?}", data); + Ok(()) +} + +async fn handle_active(params: ObjectParams) -> anyhow::Result<()> { + let data = make_rpc_call("scenarios_list_running", params) + .await + .context("Making RPC call to list running scenarios")?; + if let serde_json::Value::Array(scenarios) = data { + let mut table = Table::new(); + table.add_row(row!["PID", "Command", "Network", "Active"]); + for scenario in scenarios { + if let serde_json::Value::Object(details) = scenario { + let pid = details + .get("pid") + .and_then(|v| v.as_i64()) + .map_or_else(|| "Unknown".to_string(), |v| v.to_string()); + let cmd = details + .get("cmd") + .and_then(|v| v.as_str()) + .unwrap_or("Unknown"); + let network = details + .get("network") + .and_then(|v| v.as_str()) + .unwrap_or("Unknown"); + let active = details + .get("active") + .and_then(|v| v.as_bool()) + .map_or_else(|| "Unknown".to_string(), |v| v.to_string()); + table.add_row(row![pid, cmd, network, active]); + } + } + table.printstd(); + } else { + bail!("Unexpected response format."); + } + Ok(()) +} + +async fn handle_stop(mut params: ObjectParams, pid: &u64) -> anyhow::Result<()> { + params.insert("pid", pid).context("Add pid to params")?; + let data = make_rpc_call("scenarios_stop", params) + .await + .context("Making RPC call to stop running scenario")?; + if let serde_json::Value::String(message) = data { + println!("{}", message); + } else { + bail!("Unexpected response format."); + } + Ok(()) +} + +pub async fn handle_scenario_command( + command: &ScenarioCommand, + params: ObjectParams, +) -> anyhow::Result<()> { + match command { + ScenarioCommand::Available {} => { + handle_available(params) + .await + .context("List available scenarios")?; + } + ScenarioCommand::Run { + scenario, + additional_args, + } => { + handle_run(params, scenario, additional_args) + .await + .context("Run scenario from remote")?; + } + + ScenarioCommand::RunFile { + scenario_path, + additional_args, + } => { + handle_run_file(params, scenario_path, additional_args) + .await + .context("Run scenario file from path")?; + } + ScenarioCommand::Active {} => { + handle_active(params) + .await + .context("List active scenarios")?; + } + ScenarioCommand::Stop { pid } => { + handle_stop(params, pid) + .await + .context(format!("Stop running scenario with pid: {}", pid))?; + } + }; + Ok(()) +} diff --git a/src/rust-cli/util.rs b/src/rust-cli/util.rs new file mode 100644 index 000000000..2e153ac76 --- /dev/null +++ b/src/rust-cli/util.rs @@ -0,0 +1,60 @@ +use anyhow::Context; +use ini::Ini; +use serde_json::Value; +use std::path::Path; + +pub fn pretty_print_value(value: &Value) -> anyhow::Result<()> { + match value { + Value::String(inner_json) => { + // Attempt to parse the string as JSON + match serde_json::from_str::(inner_json) { + Ok(parsed_inner) => { + // If parsing succeeds, pretty print the JSON + println!( + "{}", + serde_json::to_string_pretty(&parsed_inner) + .context("Failed to pretty print inner JSON")? + ); + } + Err(_) => { + // If parsing fails, it's not valid JSON, so just print the string itself + println!("{}", inner_json); + } + } + } + // If `value` is not a string (i.e., already a JSON Value), pretty print it directly + _ => println!( + "{}", + serde_json::to_string_pretty(&value).context("Failed to pretty print JSON")? + ), + } + Ok(()) +} + +pub fn parse_bitcoin_conf(file_path: Option<&Path>) -> Ini { + Ini::load_from_file(file_path.unwrap()).expect("Failed to load or parse the file") +} + +pub fn dump_bitcoin_conf(conf: &Ini) -> String { + let mut entries = Vec::new(); + + // Global section + let global = conf.general_section(); + for (key, value) in global.iter() { + entries.push(format!("{}={}", key, value)); + } + + // named sections (networks) + for (section, properties) in conf.iter() { + if let Some(section_name) = section { + // Add section name as part of the output for non-global sections + // Skip or handle differently if your format does not require section names + entries.push(format!("[{}]", section_name)); + for (key, value) in properties.iter() { + entries.push(format!("{}={}", key, value)); + } + } + } + + entries.join(",") +} diff --git a/src/warnet/server.py b/src/warnet/server.py index f6e507215..58ef2437b 100644 --- a/src/warnet/server.py +++ b/src/warnet/server.py @@ -169,7 +169,7 @@ def setup_rpc(self): # Logs self.jsonrpc.register(self.logs_grep) - def get_warnet(self, network: str) -> Warnet: + def get_warnet(self, network: str = "warnet") -> Warnet: """ Will get a warnet from the cache if it exists. Otherwise it will create the network using from_network() and save it @@ -268,7 +268,7 @@ def tank_messages(self, network: str, node_a: int, node_b: int) -> str: self.logger.error(msg) raise ServerError(message=msg) from e - def network_export(self, network: str) -> str: + def network_export(self, network: str = "warnet") -> str: """ Export all data for sim-ln to subdirectory """ @@ -283,7 +283,7 @@ def network_export(self, network: str) -> str: self.logger.error(msg) raise ServerError(message=msg) from e - def scenarios_available(self) -> list[tuple]: + def scenarios_available(self, network: str = "warnet") -> list[tuple]: """ List available scenarios in the Warnet Test Framework """ @@ -403,7 +403,7 @@ def proc_logger(): self.logger.error(msg) raise ServerError(message=msg) from e - def scenarios_stop(self, pid: int) -> str: + def scenarios_stop(self, pid: int, network: str = "warnet") -> str: matching_scenarios = [sc for sc in self.running_scenarios if sc["pid"] == pid] if matching_scenarios: matching_scenarios[0]["proc"].terminate() # sends SIGTERM @@ -415,7 +415,7 @@ def scenarios_stop(self, pid: int) -> str: self.logger.error(msg) raise ServerError(message=msg) - def scenarios_list_running(self) -> list[dict]: + def scenarios_list_running(self, network: str = "warnet") -> list[dict]: running = [ { "pid": sc["pid"], @@ -567,7 +567,7 @@ def generate_deployment(self, graph_file: str, network: str = "warnet") -> str: self.logger.error(msg) raise ServerError(message=msg) from e - def server_stop(self) -> None: + def server_stop(self, network: str = "warnet") -> None: """ Stop warnet. """ diff --git a/src/warnet/warnet.py b/src/warnet/warnet.py index b912242d1..73737e7e4 100644 --- a/src/warnet/warnet.py +++ b/src/warnet/warnet.py @@ -106,7 +106,8 @@ def from_graph_file( with open(destination, "wb") as f: f.write(graph_file) self.network_name = network - self.graph = networkx.parse_graphml(graph_file.decode("utf-8"), node_type=int, force_multigraph=True) + self.graph = networkx.parse_graphml(graph_file.decode("utf-8"), node_type=str, force_multigraph=True) + self.graph = networkx.convert_node_labels_to_integers(self.graph) validate_graph_schema(self.graph) self.tanks_from_graph() logger.info(f"Created Warnet using directory {self.config_dir}") @@ -127,7 +128,8 @@ def from_network(cls, network_name, backend="compose"): self = cls(config_dir, backend, network_name) self.network_name = network_name # Get network graph edges from graph file (required for network restarts) - self.graph = networkx.read_graphml(Path(self.config_dir / self.graph_name), node_type=int, force_multigraph=True) + self.graph = networkx.read_graphml(Path(self.config_dir / self.graph_name), node_type=str, force_multigraph=True) + self.graph = networkx.convert_node_labels_to_integers(self.graph) validate_graph_schema(self.graph) self.tanks_from_graph() for tank in self.tanks: diff --git a/test/rpc_test.py b/test/rpc_test.py index 9b8a6a577..ac8acddeb 100755 --- a/test/rpc_test.py +++ b/test/rpc_test.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 - import os from pathlib import Path @@ -7,6 +6,7 @@ graph_file_path = Path(os.path.dirname(__file__)) / "data" / "v25_x_12.graphml" + base = TestBase() base.start_server() print(base.warcli(f"network start {graph_file_path}")) diff --git a/test/test_base.py b/test/test_base.py index da8aee186..f60ab78fc 100644 --- a/test/test_base.py +++ b/test/test_base.py @@ -1,5 +1,7 @@ +import argparse import atexit import os +import shlex import sys import threading from pathlib import Path @@ -11,6 +13,11 @@ from warnet.utils import exponential_backoff from warnet.warnet import Warnet +parser = argparse.ArgumentParser(description="TestBase args") +parser.add_argument("--backend", type=str, default="compose", help="Use compose or k8s backend") +parser.add_argument("--rust_cli", action="store_true", help="Use experimental Rust CLI") +args = parser.parse_args() + class TestBase: def __init__(self): @@ -31,15 +38,11 @@ def __init__(self): self.server_thread = None self.stop_threads = threading.Event() self.network = True + self.rust_cli = args.rust_cli atexit.register(self.cleanup) - # Default backend - self.backend = "compose" - # CLI arg overrides env - if len(sys.argv) > 1: - self.backend = sys.argv[1] - + self.backend = args.backend if self.backend not in ["compose", "k8s"]: print(f"Invalid backend {self.backend}") sys.exit(1) @@ -77,10 +80,25 @@ def cleanup(self, signum=None, frame=None): self.server = None # Execute a warcli RPC using command line (always returns string) - def warcli(self, str, network=True): - cmd = ["warcli"] + str.split() - if network: - cmd += ["--network", self.network_name] + def warcli(self, commands, network=True): + cmd = "" + cmd_args = ' '.join(commands.split()) + if self.rust_cli: + # a temporary hack to fetch the path of the debug binary + script_path = Path(__file__).resolve() + project_root = script_path.parent.parent + warcli_relative_path = Path("target/debug/warcli") + warcli_absolute_path = project_root / warcli_relative_path + cmd += f"{warcli_absolute_path} " + if network: + cmd += f"--network {self.network_name} " + cmd += cmd_args + else: + cmd += "warcli " + cmd += cmd_args + if network: + cmd += f" --network {self.network_name} " + cmd = shlex.split(cmd) proc = run(cmd, capture_output=True) if proc.stderr: