mirror of
https://github.com/serai-dex/serai.git
synced 2025-01-03 09:29:46 +00:00
Validator DHT (#494)
* Route validators for any active set through sc-authority-discovery Additionally adds an RPC route to retrieve their P2P addresses. * Have the coordinator get peers from substrate * Have the RPC return one address, not up to 3 Prevents the coordinator from believing it has 3 peers when it has one. * Add missing feature to serai-client * Correct network argument in serai-client for p2p_validators call * Add a test in serai-client to check DHT population with a much quicker failure than the coordinator tests * Update to latest Substrate Removes distinguishing BABE/AuthorityDiscovery keys which causes sc_authority_discovery to populate as desired. * Update to a properly tagged substrate commit * Add all dialed to peers to GossipSub * cargo fmt * Reduce common code in serai-coordinator-tests with amore involved new_test * Use a recursive async function to spawn `n` DockerTests with the necessary networking configuration * Merge UNIQUE_ID and ONE_AT_A_TIME * Tidy up the new recursive code in tests/coordinator * Use a Mutex in CONTEXT to let it be set multiple times * Make complimentary edits to full-stack tests * Augment coordinator P2p connection logs * Drop lock acquisitions before recursing * Better scope lock acquisitions in full-stack, preventing a deadlock * Ensure OUTER_OPS is reset across the test boundary * Add cargo deny allowance for dockertest fork
This commit is contained in:
parent
00774c29d7
commit
b493e3e31f
28 changed files with 1551 additions and 1225 deletions
234
Cargo.lock
generated
234
Cargo.lock
generated
|
@ -290,6 +290,17 @@ dependencies = [
|
||||||
"pin-project-lite 0.2.13",
|
"pin-project-lite 0.2.13",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-recursion"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.41",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.74"
|
version = "0.1.74"
|
||||||
|
@ -1597,8 +1608,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dockertest"
|
name = "dockertest"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/kayabaNerve/dockertest-rs?branch=arc#c0ea77997048f9edc9987984bbe20e43fac74e06"
|
||||||
checksum = "88933ed892cc8f5be247da11a1cd86a5c64802ac0172982e8aeb8315cb6dacfa"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -2217,7 +2227,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fork-tree"
|
name = "fork-tree"
|
||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
]
|
]
|
||||||
|
@ -2240,7 +2250,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frame-benchmarking"
|
name = "frame-benchmarking"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"frame-support-procedural",
|
"frame-support-procedural",
|
||||||
|
@ -2265,7 +2275,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frame-executive"
|
name = "frame-executive"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"frame-system",
|
"frame-system",
|
||||||
|
@ -2294,7 +2304,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frame-support"
|
name = "frame-support"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"environmental",
|
"environmental",
|
||||||
|
@ -2327,7 +2337,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frame-support-procedural"
|
name = "frame-support-procedural"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"Inflector",
|
"Inflector",
|
||||||
"cfg-expr",
|
"cfg-expr",
|
||||||
|
@ -2345,7 +2355,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frame-support-procedural-tools"
|
name = "frame-support-procedural-tools"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-support-procedural-tools-derive",
|
"frame-support-procedural-tools-derive",
|
||||||
"proc-macro-crate 1.3.1",
|
"proc-macro-crate 1.3.1",
|
||||||
|
@ -2357,7 +2367,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frame-support-procedural-tools-derive"
|
name = "frame-support-procedural-tools-derive"
|
||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -2367,7 +2377,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frame-system"
|
name = "frame-system"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
|
@ -2386,7 +2396,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frame-system-rpc-runtime-api"
|
name = "frame-system-rpc-runtime-api"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"sp-api",
|
"sp-api",
|
||||||
|
@ -2395,7 +2405,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frame-try-runtime"
|
name = "frame-try-runtime"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
@ -4715,7 +4725,7 @@ version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e"
|
checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate 1.3.1",
|
"proc-macro-crate 2.0.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.41",
|
"syn 2.0.41",
|
||||||
|
@ -4829,7 +4839,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pallet-authorship"
|
name = "pallet-authorship"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"frame-system",
|
"frame-system",
|
||||||
|
@ -4843,7 +4853,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pallet-babe"
|
name = "pallet-babe"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-benchmarking",
|
"frame-benchmarking",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
|
@ -4867,7 +4877,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pallet-grandpa"
|
name = "pallet-grandpa"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-benchmarking",
|
"frame-benchmarking",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
|
@ -4890,7 +4900,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pallet-session"
|
name = "pallet-session"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"frame-system",
|
"frame-system",
|
||||||
|
@ -4911,7 +4921,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pallet-timestamp"
|
name = "pallet-timestamp"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-benchmarking",
|
"frame-benchmarking",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
|
@ -4929,7 +4939,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pallet-transaction-payment"
|
name = "pallet-transaction-payment"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"frame-system",
|
"frame-system",
|
||||||
|
@ -4945,7 +4955,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pallet-transaction-payment-rpc"
|
name = "pallet-transaction-payment-rpc"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jsonrpsee",
|
"jsonrpsee",
|
||||||
"pallet-transaction-payment-rpc-runtime-api",
|
"pallet-transaction-payment-rpc-runtime-api",
|
||||||
|
@ -4961,7 +4971,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pallet-transaction-payment-rpc-runtime-api"
|
name = "pallet-transaction-payment-rpc-runtime-api"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pallet-transaction-payment",
|
"pallet-transaction-payment",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
@ -6114,7 +6124,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-allocator"
|
name = "sc-allocator"
|
||||||
version = "4.1.0-dev"
|
version = "4.1.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
|
@ -6125,7 +6135,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-authority-discovery"
|
name = "sc-authority-discovery"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -6153,7 +6163,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-basic-authorship"
|
name = "sc-basic-authorship"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"futures-timer",
|
"futures-timer",
|
||||||
|
@ -6176,7 +6186,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-block-builder"
|
name = "sc-block-builder"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"sc-client-api",
|
"sc-client-api",
|
||||||
|
@ -6191,7 +6201,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-chain-spec"
|
name = "sc-chain-spec"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memmap2",
|
"memmap2",
|
||||||
"sc-chain-spec-derive",
|
"sc-chain-spec-derive",
|
||||||
|
@ -6210,7 +6220,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-chain-spec-derive"
|
name = "sc-chain-spec-derive"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate 1.3.1",
|
"proc-macro-crate 1.3.1",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -6221,7 +6231,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-cli"
|
name = "sc-cli"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"array-bytes",
|
"array-bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@ -6260,7 +6270,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-client-api"
|
name = "sc-client-api"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fnv",
|
"fnv",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -6285,7 +6295,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-client-db"
|
name = "sc-client-db"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hash-db",
|
"hash-db",
|
||||||
"kvdb",
|
"kvdb",
|
||||||
|
@ -6311,7 +6321,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-consensus"
|
name = "sc-consensus"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -6336,7 +6346,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-consensus-babe"
|
name = "sc-consensus-babe"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"fork-tree",
|
"fork-tree",
|
||||||
|
@ -6372,7 +6382,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-consensus-epochs"
|
name = "sc-consensus-epochs"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fork-tree",
|
"fork-tree",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
@ -6385,7 +6395,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-consensus-grandpa"
|
name = "sc-consensus-grandpa"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"array-bytes",
|
"array-bytes",
|
||||||
|
@ -6426,7 +6436,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-consensus-slots"
|
name = "sc-consensus-slots"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -6449,7 +6459,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-executor"
|
name = "sc-executor"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot 0.12.1",
|
||||||
|
@ -6471,7 +6481,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-executor-common"
|
name = "sc-executor-common"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sc-allocator",
|
"sc-allocator",
|
||||||
"sp-maybe-compressed-blob",
|
"sp-maybe-compressed-blob",
|
||||||
|
@ -6483,7 +6493,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-executor-wasmtime"
|
name = "sc-executor-wasmtime"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
@ -6500,7 +6510,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-informant"
|
name = "sc-informant"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -6516,7 +6526,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-keystore"
|
name = "sc-keystore"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"array-bytes",
|
"array-bytes",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot 0.12.1",
|
||||||
|
@ -6530,7 +6540,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-network"
|
name = "sc-network"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"array-bytes",
|
"array-bytes",
|
||||||
"async-channel",
|
"async-channel",
|
||||||
|
@ -6572,7 +6582,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-network-bitswap"
|
name = "sc-network-bitswap"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"cid",
|
"cid",
|
||||||
|
@ -6592,7 +6602,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-network-common"
|
name = "sc-network-common"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
|
@ -6609,7 +6619,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-network-gossip"
|
name = "sc-network-gossip"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -6628,7 +6638,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-network-light"
|
name = "sc-network-light"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"array-bytes",
|
"array-bytes",
|
||||||
"async-channel",
|
"async-channel",
|
||||||
|
@ -6649,7 +6659,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-network-sync"
|
name = "sc-network-sync"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"array-bytes",
|
"array-bytes",
|
||||||
"async-channel",
|
"async-channel",
|
||||||
|
@ -6683,7 +6693,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-network-transactions"
|
name = "sc-network-transactions"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"array-bytes",
|
"array-bytes",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -6701,7 +6711,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-offchain"
|
name = "sc-offchain"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
|
@ -6733,7 +6743,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-proposer-metrics"
|
name = "sc-proposer-metrics"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"substrate-prometheus-endpoint",
|
"substrate-prometheus-endpoint",
|
||||||
|
@ -6742,7 +6752,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-rpc"
|
name = "sc-rpc"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"jsonrpsee",
|
"jsonrpsee",
|
||||||
|
@ -6772,7 +6782,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-rpc-api"
|
name = "sc-rpc-api"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jsonrpsee",
|
"jsonrpsee",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
@ -6791,7 +6801,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-rpc-server"
|
name = "sc-rpc-server"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"jsonrpsee",
|
"jsonrpsee",
|
||||||
|
@ -6806,7 +6816,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-rpc-spec-v2"
|
name = "sc-rpc-spec-v2"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"array-bytes",
|
"array-bytes",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -6832,7 +6842,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-service"
|
name = "sc-service"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"directories",
|
"directories",
|
||||||
|
@ -6895,7 +6905,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-state-db"
|
name = "sc-state-db"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
@ -6906,7 +6916,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-sysinfo"
|
name = "sc-sysinfo"
|
||||||
version = "6.0.0-dev"
|
version = "6.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -6925,7 +6935,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-telemetry"
|
name = "sc-telemetry"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -6944,7 +6954,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-tracing"
|
name = "sc-tracing"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@ -6972,7 +6982,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-tracing-proc-macro"
|
name = "sc-tracing-proc-macro"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate 1.3.1",
|
"proc-macro-crate 1.3.1",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -6983,7 +6993,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-transaction-pool"
|
name = "sc-transaction-pool"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -7009,7 +7019,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-transaction-pool-api"
|
name = "sc-transaction-pool-api"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -7025,7 +7035,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sc-utils"
|
name = "sc-utils"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -7281,6 +7291,7 @@ dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
"monero-serai",
|
"monero-serai",
|
||||||
|
"multiaddr",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"serai-abi",
|
"serai-abi",
|
||||||
|
@ -7359,6 +7370,8 @@ dependencies = [
|
||||||
name = "serai-coordinator-tests"
|
name = "serai-coordinator-tests"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-recursion",
|
||||||
|
"async-trait",
|
||||||
"blake2",
|
"blake2",
|
||||||
"borsh",
|
"borsh",
|
||||||
"ciphersuite",
|
"ciphersuite",
|
||||||
|
@ -7418,6 +7431,8 @@ version = "0.1.0"
|
||||||
name = "serai-full-stack-tests"
|
name = "serai-full-stack-tests"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-recursion",
|
||||||
|
"async-trait",
|
||||||
"bitcoin-serai",
|
"bitcoin-serai",
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"dockertest",
|
"dockertest",
|
||||||
|
@ -7427,6 +7442,7 @@ dependencies = [
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"serai-client",
|
"serai-client",
|
||||||
"serai-coordinator-tests",
|
"serai-coordinator-tests",
|
||||||
|
"serai-docker-tests",
|
||||||
"serai-message-queue-tests",
|
"serai-message-queue-tests",
|
||||||
"serai-processor",
|
"serai-processor",
|
||||||
"serai-processor-tests",
|
"serai-processor-tests",
|
||||||
|
@ -7559,6 +7575,7 @@ dependencies = [
|
||||||
"sp-timestamp",
|
"sp-timestamp",
|
||||||
"substrate-build-script-utils",
|
"substrate-build-script-utils",
|
||||||
"substrate-frame-rpc-system",
|
"substrate-frame-rpc-system",
|
||||||
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -7671,6 +7688,7 @@ dependencies = [
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"frame-system",
|
"frame-system",
|
||||||
"frame-system-rpc-runtime-api",
|
"frame-system-rpc-runtime-api",
|
||||||
|
"hashbrown 0.14.3",
|
||||||
"pallet-authorship",
|
"pallet-authorship",
|
||||||
"pallet-babe",
|
"pallet-babe",
|
||||||
"pallet-grandpa",
|
"pallet-grandpa",
|
||||||
|
@ -8061,7 +8079,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-api"
|
name = "sp-api"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hash-db",
|
"hash-db",
|
||||||
"log",
|
"log",
|
||||||
|
@ -8082,7 +8100,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-api-proc-macro"
|
name = "sp-api-proc-macro"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"Inflector",
|
"Inflector",
|
||||||
"blake2",
|
"blake2",
|
||||||
|
@ -8096,7 +8114,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-application-crypto"
|
name = "sp-application-crypto"
|
||||||
version = "23.0.0"
|
version = "23.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"scale-info",
|
"scale-info",
|
||||||
|
@ -8109,7 +8127,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-arithmetic"
|
name = "sp-arithmetic"
|
||||||
version = "16.0.0"
|
version = "16.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"integer-sqrt",
|
"integer-sqrt",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
@ -8123,7 +8141,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-authority-discovery"
|
name = "sp-authority-discovery"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"scale-info",
|
"scale-info",
|
||||||
|
@ -8135,7 +8153,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-block-builder"
|
name = "sp-block-builder"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sp-api",
|
"sp-api",
|
||||||
"sp-inherents",
|
"sp-inherents",
|
||||||
|
@ -8146,7 +8164,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-blockchain"
|
name = "sp-blockchain"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"log",
|
"log",
|
||||||
|
@ -8164,7 +8182,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-consensus"
|
name = "sp-consensus"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -8178,7 +8196,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-consensus-babe"
|
name = "sp-consensus-babe"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
@ -8197,7 +8215,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-consensus-grandpa"
|
name = "sp-consensus-grandpa"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"finality-grandpa",
|
"finality-grandpa",
|
||||||
"log",
|
"log",
|
||||||
|
@ -8215,7 +8233,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-consensus-slots"
|
name = "sp-consensus-slots"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"scale-info",
|
"scale-info",
|
||||||
|
@ -8227,7 +8245,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-core"
|
name = "sp-core"
|
||||||
version = "21.0.0"
|
version = "21.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"array-bytes",
|
"array-bytes",
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
|
@ -8270,7 +8288,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-core-hashing"
|
name = "sp-core-hashing"
|
||||||
version = "9.0.0"
|
version = "9.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2b_simd",
|
"blake2b_simd",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
@ -8282,7 +8300,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-core-hashing-proc-macro"
|
name = "sp-core-hashing-proc-macro"
|
||||||
version = "9.0.0"
|
version = "9.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"sp-core-hashing",
|
"sp-core-hashing",
|
||||||
|
@ -8292,7 +8310,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-database"
|
name = "sp-database"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kvdb",
|
"kvdb",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot 0.12.1",
|
||||||
|
@ -8301,7 +8319,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-debug-derive"
|
name = "sp-debug-derive"
|
||||||
version = "8.0.0"
|
version = "8.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -8311,7 +8329,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-externalities"
|
name = "sp-externalities"
|
||||||
version = "0.19.0"
|
version = "0.19.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"environmental",
|
"environmental",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
@ -8322,7 +8340,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-inherents"
|
name = "sp-inherents"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"impl-trait-for-tuples",
|
"impl-trait-for-tuples",
|
||||||
|
@ -8336,7 +8354,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-io"
|
name = "sp-io"
|
||||||
version = "23.0.0"
|
version = "23.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"ed25519",
|
"ed25519",
|
||||||
|
@ -8358,7 +8376,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-keyring"
|
name = "sp-keyring"
|
||||||
version = "24.0.0"
|
version = "24.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
|
@ -8369,7 +8387,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-keystore"
|
name = "sp-keystore"
|
||||||
version = "0.27.0"
|
version = "0.27.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot 0.12.1",
|
||||||
|
@ -8381,7 +8399,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-maybe-compressed-blob"
|
name = "sp-maybe-compressed-blob"
|
||||||
version = "4.1.0-dev"
|
version = "4.1.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"zstd 0.12.4",
|
"zstd 0.12.4",
|
||||||
|
@ -8390,7 +8408,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-metadata-ir"
|
name = "sp-metadata-ir"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-metadata",
|
"frame-metadata",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
@ -8401,7 +8419,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-offchain"
|
name = "sp-offchain"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sp-api",
|
"sp-api",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
|
@ -8411,7 +8429,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-panic-handler"
|
name = "sp-panic-handler"
|
||||||
version = "8.0.0"
|
version = "8.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
@ -8421,7 +8439,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-rpc"
|
name = "sp-rpc"
|
||||||
version = "6.0.0"
|
version = "6.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -8431,7 +8449,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-runtime"
|
name = "sp-runtime"
|
||||||
version = "24.0.0"
|
version = "24.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"hash256-std-hasher",
|
"hash256-std-hasher",
|
||||||
|
@ -8453,7 +8471,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-runtime-interface"
|
name = "sp-runtime-interface"
|
||||||
version = "17.0.0"
|
version = "17.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"impl-trait-for-tuples",
|
"impl-trait-for-tuples",
|
||||||
|
@ -8471,7 +8489,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-runtime-interface-proc-macro"
|
name = "sp-runtime-interface-proc-macro"
|
||||||
version = "11.0.0"
|
version = "11.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"Inflector",
|
"Inflector",
|
||||||
"proc-macro-crate 1.3.1",
|
"proc-macro-crate 1.3.1",
|
||||||
|
@ -8483,7 +8501,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-session"
|
name = "sp-session"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"scale-info",
|
"scale-info",
|
||||||
|
@ -8498,7 +8516,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-staking"
|
name = "sp-staking"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"impl-trait-for-tuples",
|
"impl-trait-for-tuples",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
@ -8512,7 +8530,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-state-machine"
|
name = "sp-state-machine"
|
||||||
version = "0.28.0"
|
version = "0.28.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hash-db",
|
"hash-db",
|
||||||
"log",
|
"log",
|
||||||
|
@ -8533,12 +8551,12 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-std"
|
name = "sp-std"
|
||||||
version = "8.0.0"
|
version = "8.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-storage"
|
name = "sp-storage"
|
||||||
version = "13.0.0"
|
version = "13.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"impl-serde",
|
"impl-serde",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
@ -8551,7 +8569,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-timestamp"
|
name = "sp-timestamp"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
@ -8564,7 +8582,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-tracing"
|
name = "sp-tracing"
|
||||||
version = "10.0.0"
|
version = "10.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"sp-std",
|
"sp-std",
|
||||||
|
@ -8576,7 +8594,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-transaction-pool"
|
name = "sp-transaction-pool"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sp-api",
|
"sp-api",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
|
@ -8585,7 +8603,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-trie"
|
name = "sp-trie"
|
||||||
version = "22.0.0"
|
version = "22.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"hash-db",
|
"hash-db",
|
||||||
|
@ -8608,7 +8626,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-version"
|
name = "sp-version"
|
||||||
version = "22.0.0"
|
version = "22.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"impl-serde",
|
"impl-serde",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
@ -8625,7 +8643,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-version-proc-macro"
|
name = "sp-version-proc-macro"
|
||||||
version = "8.0.0"
|
version = "8.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -8636,7 +8654,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-wasm-interface"
|
name = "sp-wasm-interface"
|
||||||
version = "14.0.0"
|
version = "14.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"impl-trait-for-tuples",
|
"impl-trait-for-tuples",
|
||||||
|
@ -8649,7 +8667,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sp-weights"
|
name = "sp-weights"
|
||||||
version = "20.0.0"
|
version = "20.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"scale-info",
|
"scale-info",
|
||||||
|
@ -8827,12 +8845,12 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "substrate-build-script-utils"
|
name = "substrate-build-script-utils"
|
||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "substrate-frame-rpc-system"
|
name = "substrate-frame-rpc-system"
|
||||||
version = "4.0.0-dev"
|
version = "4.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-system-rpc-runtime-api",
|
"frame-system-rpc-runtime-api",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -8851,7 +8869,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "substrate-prometheus-endpoint"
|
name = "substrate-prometheus-endpoint"
|
||||||
version = "0.10.0-dev"
|
version = "0.10.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hyper",
|
"hyper",
|
||||||
"log",
|
"log",
|
||||||
|
@ -8863,7 +8881,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "substrate-wasm-builder"
|
name = "substrate-wasm-builder"
|
||||||
version = "5.0.0-dev"
|
version = "5.0.0-dev"
|
||||||
source = "git+https://github.com/serai-dex/substrate#34c8c3595e7a3230058ee5e181c9d7e4be329ed2"
|
source = "git+https://github.com/serai-dex/substrate#400d5c9d4da49ae96035964da14c7654478b11e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"build-helper",
|
"build-helper",
|
||||||
|
|
|
@ -97,6 +97,8 @@ lazy_static = { git = "https://github.com/rust-lang-nursery/lazy-static.rs", rev
|
||||||
sp-core-hashing = { git = "https://github.com/serai-dex/substrate" }
|
sp-core-hashing = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sp-std = { git = "https://github.com/serai-dex/substrate" }
|
sp-std = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
||||||
|
dockertest = { git = "https://github.com/kayabaNerve/dockertest-rs", branch = "arc" }
|
||||||
|
|
||||||
[workspace.lints.clippy]
|
[workspace.lints.clippy]
|
||||||
unwrap_or_default = "allow"
|
unwrap_or_default = "allow"
|
||||||
borrow_as_ptr = "deny"
|
borrow_as_ptr = "deny"
|
||||||
|
|
|
@ -50,7 +50,7 @@ env_logger = { version = "0.10", default-features = false, features = ["humantim
|
||||||
|
|
||||||
futures-util = { version = "0.3", default-features = false, features = ["std"] }
|
futures-util = { version = "0.3", default-features = false, features = ["std"] }
|
||||||
tokio = { version = "1", default-features = false, features = ["rt-multi-thread", "sync", "time", "macros"] }
|
tokio = { version = "1", default-features = false, features = ["rt-multi-thread", "sync", "time", "macros"] }
|
||||||
libp2p = { version = "0.52", default-features = false, features = ["tokio", "tcp", "noise", "yamux", "gossipsub", "mdns", "macros"] }
|
libp2p = { version = "0.52", default-features = false, features = ["tokio", "tcp", "noise", "yamux", "gossipsub", "macros"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tributary = { package = "tributary-chain", path = "./tributary", features = ["tests"] }
|
tributary = { package = "tributary-chain", path = "./tributary", features = ["tests"] }
|
||||||
|
|
|
@ -951,10 +951,8 @@ pub async fn run<D: Db, Pro: Processors, P: P2p>(
|
||||||
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
||||||
p2p: P,
|
p2p: P,
|
||||||
processors: Pro,
|
processors: Pro,
|
||||||
serai: Serai,
|
serai: Arc<Serai>,
|
||||||
) {
|
) {
|
||||||
let serai = Arc::new(serai);
|
|
||||||
|
|
||||||
let (new_tributary_spec_send, mut new_tributary_spec_recv) = mpsc::unbounded_channel();
|
let (new_tributary_spec_send, mut new_tributary_spec_recv) = mpsc::unbounded_channel();
|
||||||
// Reload active tributaries from the database
|
// Reload active tributaries from the database
|
||||||
for spec in ActiveTributaryDb::active_tributaries(&raw_db).1 {
|
for spec in ActiveTributaryDb::active_tributaries(&raw_db).1 {
|
||||||
|
@ -1212,11 +1210,10 @@ async fn main() {
|
||||||
key_bytes.zeroize();
|
key_bytes.zeroize();
|
||||||
key
|
key
|
||||||
};
|
};
|
||||||
let p2p = LibP2p::new();
|
|
||||||
|
|
||||||
let processors = Arc::new(MessageQueue::from_env(Service::Coordinator));
|
let processors = Arc::new(MessageQueue::from_env(Service::Coordinator));
|
||||||
|
|
||||||
let serai = || async {
|
let serai = (async {
|
||||||
loop {
|
loop {
|
||||||
let Ok(serai) = Serai::new(format!(
|
let Ok(serai) = Serai::new(format!(
|
||||||
"http://{}:9944",
|
"http://{}:9944",
|
||||||
|
@ -1229,8 +1226,10 @@ async fn main() {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
log::info!("made initial connection to Serai node");
|
log::info!("made initial connection to Serai node");
|
||||||
return serai;
|
return Arc::new(serai);
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
run(db, key, p2p, processors, serai().await).await
|
.await;
|
||||||
|
let p2p = LibP2p::new(serai.clone());
|
||||||
|
run(db, key, p2p, processors, serai).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,11 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use rand_core::{RngCore, OsRng};
|
||||||
|
|
||||||
|
use scale::Encode;
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
use serai_client::primitives::NetworkId;
|
use serai_client::{primitives::NetworkId, validator_sets::primitives::ValidatorSet, Serai};
|
||||||
|
|
||||||
use serai_db::Db;
|
use serai_db::Db;
|
||||||
|
|
||||||
|
@ -20,6 +22,7 @@ use tokio::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use libp2p::{
|
use libp2p::{
|
||||||
|
core::multiaddr::{Protocol, Multiaddr},
|
||||||
identity::Keypair,
|
identity::Keypair,
|
||||||
PeerId,
|
PeerId,
|
||||||
tcp::Config as TcpConfig,
|
tcp::Config as TcpConfig,
|
||||||
|
@ -127,8 +130,8 @@ pub struct Message<P: P2p> {
|
||||||
pub trait P2p: Send + Sync + Clone + fmt::Debug + TributaryP2p {
|
pub trait P2p: Send + Sync + Clone + fmt::Debug + TributaryP2p {
|
||||||
type Id: Send + Sync + Clone + Copy + fmt::Debug;
|
type Id: Send + Sync + Clone + Copy + fmt::Debug;
|
||||||
|
|
||||||
async fn subscribe(&self, genesis: [u8; 32]);
|
async fn subscribe(&self, set: ValidatorSet, genesis: [u8; 32]);
|
||||||
async fn unsubscribe(&self, genesis: [u8; 32]);
|
async fn unsubscribe(&self, set: ValidatorSet, genesis: [u8; 32]);
|
||||||
|
|
||||||
async fn send_raw(&self, to: Self::Id, genesis: Option<[u8; 32]>, msg: Vec<u8>);
|
async fn send_raw(&self, to: Self::Id, genesis: Option<[u8; 32]>, msg: Vec<u8>);
|
||||||
async fn broadcast_raw(&self, genesis: Option<[u8; 32]>, msg: Vec<u8>);
|
async fn broadcast_raw(&self, genesis: Option<[u8; 32]>, msg: Vec<u8>);
|
||||||
|
@ -190,14 +193,12 @@ pub trait P2p: Send + Sync + Clone + fmt::Debug + TributaryP2p {
|
||||||
#[derive(NetworkBehaviour)]
|
#[derive(NetworkBehaviour)]
|
||||||
struct Behavior {
|
struct Behavior {
|
||||||
gossipsub: GsBehavior,
|
gossipsub: GsBehavior,
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
mdns: libp2p::mdns::tokio::Behaviour,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct LibP2p {
|
pub struct LibP2p {
|
||||||
subscribe: Arc<Mutex<mpsc::UnboundedSender<(bool, [u8; 32])>>>,
|
subscribe: Arc<Mutex<mpsc::UnboundedSender<(bool, ValidatorSet, [u8; 32])>>>,
|
||||||
broadcast: Arc<Mutex<mpsc::UnboundedSender<(Option<[u8; 32]>, Vec<u8>)>>>,
|
broadcast: Arc<Mutex<mpsc::UnboundedSender<(Option<[u8; 32]>, Vec<u8>)>>>,
|
||||||
receive: Arc<Mutex<mpsc::UnboundedReceiver<(PeerId, Vec<u8>)>>>,
|
receive: Arc<Mutex<mpsc::UnboundedReceiver<(PeerId, Vec<u8>)>>>,
|
||||||
}
|
}
|
||||||
|
@ -209,14 +210,13 @@ impl fmt::Debug for LibP2p {
|
||||||
|
|
||||||
impl LibP2p {
|
impl LibP2p {
|
||||||
#[allow(clippy::new_without_default)]
|
#[allow(clippy::new_without_default)]
|
||||||
pub fn new() -> Self {
|
pub fn new(serai: Arc<Serai>) -> Self {
|
||||||
// Block size limit + 1 KB of space for signatures/metadata
|
// Block size limit + 1 KB of space for signatures/metadata
|
||||||
const MAX_LIBP2P_MESSAGE_SIZE: usize = tributary::BLOCK_SIZE_LIMIT + 1024;
|
const MAX_LIBP2P_MESSAGE_SIZE: usize = tributary::BLOCK_SIZE_LIMIT + 1024;
|
||||||
|
|
||||||
log::info!("creating a libp2p instance");
|
log::info!("creating a libp2p instance");
|
||||||
|
|
||||||
let throwaway_key_pair = Keypair::generate_ed25519();
|
let throwaway_key_pair = Keypair::generate_ed25519();
|
||||||
let throwaway_peer_id = PeerId::from(throwaway_key_pair.public());
|
|
||||||
|
|
||||||
let behavior = Behavior {
|
let behavior = Behavior {
|
||||||
gossipsub: {
|
gossipsub: {
|
||||||
|
@ -258,14 +258,6 @@ impl LibP2p {
|
||||||
|
|
||||||
gossipsub
|
gossipsub
|
||||||
},
|
},
|
||||||
|
|
||||||
// Only use MDNS in debug environments, as it should have no value in a release build
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
mdns: {
|
|
||||||
log::info!("creating mdns service");
|
|
||||||
libp2p::mdns::tokio::Behaviour::new(libp2p::mdns::Config::default(), throwaway_peer_id)
|
|
||||||
.unwrap()
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Uses noise for authentication, yamux for multiplexing
|
// Uses noise for authentication, yamux for multiplexing
|
||||||
|
@ -294,8 +286,8 @@ impl LibP2p {
|
||||||
let (receive_send, receive_recv) = mpsc::unbounded_channel();
|
let (receive_send, receive_recv) = mpsc::unbounded_channel();
|
||||||
let (subscribe_send, mut subscribe_recv) = mpsc::unbounded_channel();
|
let (subscribe_send, mut subscribe_recv) = mpsc::unbounded_channel();
|
||||||
|
|
||||||
fn topic_for_genesis(genesis: [u8; 32]) -> IdentTopic {
|
fn topic_for_set(set: ValidatorSet) -> IdentTopic {
|
||||||
IdentTopic::new(format!("{LIBP2P_TOPIC}-{}", hex::encode(genesis)))
|
IdentTopic::new(format!("{LIBP2P_TOPIC}-{}", hex::encode(set.encode())))
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::spawn({
|
tokio::spawn({
|
||||||
|
@ -305,17 +297,14 @@ impl LibP2p {
|
||||||
fn broadcast_raw(
|
fn broadcast_raw(
|
||||||
p2p: &mut Swarm<Behavior>,
|
p2p: &mut Swarm<Behavior>,
|
||||||
time_of_last_p2p_message: &mut Instant,
|
time_of_last_p2p_message: &mut Instant,
|
||||||
genesis: Option<[u8; 32]>,
|
set: Option<ValidatorSet>,
|
||||||
msg: Vec<u8>,
|
msg: Vec<u8>,
|
||||||
) {
|
) {
|
||||||
// Update the time of last message
|
// Update the time of last message
|
||||||
*time_of_last_p2p_message = Instant::now();
|
*time_of_last_p2p_message = Instant::now();
|
||||||
|
|
||||||
let topic = if let Some(genesis) = genesis {
|
let topic =
|
||||||
topic_for_genesis(genesis)
|
if let Some(set) = set { topic_for_set(set) } else { IdentTopic::new(LIBP2P_TOPIC) };
|
||||||
} else {
|
|
||||||
IdentTopic::new(LIBP2P_TOPIC)
|
|
||||||
};
|
|
||||||
|
|
||||||
match p2p.behaviour_mut().gossipsub.publish(topic, msg.clone()) {
|
match p2p.behaviour_mut().gossipsub.publish(topic, msg.clone()) {
|
||||||
Err(PublishError::SigningError(e)) => panic!("signing error when broadcasting: {e}"),
|
Err(PublishError::SigningError(e)) => panic!("signing error when broadcasting: {e}"),
|
||||||
|
@ -331,37 +320,97 @@ impl LibP2p {
|
||||||
}
|
}
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
|
let mut set_for_genesis = HashMap::new();
|
||||||
|
let mut pending_p2p_connections = vec![];
|
||||||
// Run this task ad-infinitum
|
// Run this task ad-infinitum
|
||||||
loop {
|
loop {
|
||||||
|
// Handle pending P2P connections
|
||||||
|
// TODO: Break this out onto its own task with better peer management logic?
|
||||||
|
{
|
||||||
|
let mut connect = |addr: Multiaddr| {
|
||||||
|
log::info!("found peer from substrate: {addr}");
|
||||||
|
|
||||||
|
let protocols = addr.iter().filter_map(|piece| match piece {
|
||||||
|
// Drop PeerIds from the Substrate P2p network
|
||||||
|
Protocol::P2p(_) => None,
|
||||||
|
// Use our own TCP port
|
||||||
|
Protocol::Tcp(_) => Some(Protocol::Tcp(PORT)),
|
||||||
|
other => Some(other),
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut new_addr = Multiaddr::empty();
|
||||||
|
for protocol in protocols {
|
||||||
|
new_addr.push(protocol);
|
||||||
|
}
|
||||||
|
let addr = new_addr;
|
||||||
|
log::debug!("transformed found peer: {addr}");
|
||||||
|
|
||||||
|
if let Err(e) = swarm.dial(addr) {
|
||||||
|
log::warn!("dialing peer failed: {e:?}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
while let Some(network) = pending_p2p_connections.pop() {
|
||||||
|
if let Ok(mut nodes) = serai.p2p_validators(network).await {
|
||||||
|
// If there's an insufficient amount of nodes known, connect to all yet add it back
|
||||||
|
// and break
|
||||||
|
if nodes.len() < 3 {
|
||||||
|
log::warn!(
|
||||||
|
"insufficient amount of P2P nodes known for {:?}: {}",
|
||||||
|
network,
|
||||||
|
nodes.len()
|
||||||
|
);
|
||||||
|
pending_p2p_connections.push(network);
|
||||||
|
for node in nodes {
|
||||||
|
connect(node);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Randomly select up to 5
|
||||||
|
for _ in 0 .. 5 {
|
||||||
|
if !nodes.is_empty() {
|
||||||
|
let to_connect = nodes.swap_remove(
|
||||||
|
usize::try_from(OsRng.next_u64() % u64::try_from(nodes.len()).unwrap())
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
connect(to_connect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let time_since_last = Instant::now().duration_since(time_of_last_p2p_message);
|
let time_since_last = Instant::now().duration_since(time_of_last_p2p_message);
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
biased;
|
biased;
|
||||||
|
|
||||||
// Subscribe to any new topics
|
// Subscribe to any new topics
|
||||||
topic = subscribe_recv.recv() => {
|
set = subscribe_recv.recv() => {
|
||||||
let (subscribe, topic) = topic.expect("subscribe_recv closed. are we shutting down?");
|
let (subscribe, set, genesis): (_, ValidatorSet, [u8; 32]) =
|
||||||
|
set.expect("subscribe_recv closed. are we shutting down?");
|
||||||
|
let topic = topic_for_set(set);
|
||||||
if subscribe {
|
if subscribe {
|
||||||
swarm
|
log::info!("subscribing to p2p messages for {set:?}");
|
||||||
.behaviour_mut()
|
pending_p2p_connections.push(set.network);
|
||||||
.gossipsub
|
set_for_genesis.insert(genesis, set);
|
||||||
.subscribe(&topic_for_genesis(topic))
|
swarm.behaviour_mut().gossipsub.subscribe(&topic).unwrap();
|
||||||
.unwrap();
|
|
||||||
} else {
|
} else {
|
||||||
swarm
|
log::info!("unsubscribing to p2p messages for {set:?}");
|
||||||
.behaviour_mut()
|
set_for_genesis.remove(&genesis);
|
||||||
.gossipsub
|
swarm.behaviour_mut().gossipsub.unsubscribe(&topic).unwrap();
|
||||||
.unsubscribe(&topic_for_genesis(topic))
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle any queued outbound messages
|
// Handle any queued outbound messages
|
||||||
msg = broadcast_recv.recv() => {
|
msg = broadcast_recv.recv() => {
|
||||||
let (genesis, msg) = msg.expect("broadcast_recv closed. are we shutting down?");
|
let (genesis, msg): (Option<[u8; 32]>, Vec<u8>) =
|
||||||
|
msg.expect("broadcast_recv closed. are we shutting down?");
|
||||||
|
let set = genesis.and_then(|genesis| set_for_genesis.get(&genesis).copied());
|
||||||
broadcast_raw(
|
broadcast_raw(
|
||||||
&mut swarm,
|
&mut swarm,
|
||||||
&mut time_of_last_p2p_message,
|
&mut time_of_last_p2p_message,
|
||||||
genesis,
|
set,
|
||||||
msg,
|
msg,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -369,28 +418,17 @@ impl LibP2p {
|
||||||
// Handle new incoming messages
|
// Handle new incoming messages
|
||||||
event = swarm.next() => {
|
event = swarm.next() => {
|
||||||
match event {
|
match event {
|
||||||
#[cfg(debug_assertions)]
|
Some(SwarmEvent::Dialing { connection_id, .. }) => {
|
||||||
Some(SwarmEvent::Behaviour(BehaviorEvent::Mdns(
|
log::debug!("dialing to peer in connection ID {}", &connection_id);
|
||||||
libp2p::mdns::Event::Discovered(list),
|
|
||||||
))) => {
|
|
||||||
for (peer, mut addr) in list {
|
|
||||||
// Check the port is as expected to prevent trying to peer with Substrate nodes
|
|
||||||
if addr.pop() == Some(libp2p::multiaddr::Protocol::Tcp(PORT)) {
|
|
||||||
log::info!("found peer via mdns");
|
|
||||||
swarm.behaviour_mut().gossipsub.add_explicit_peer(&peer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[cfg(debug_assertions)]
|
Some(SwarmEvent::ConnectionEstablished { peer_id, connection_id, .. }) => {
|
||||||
Some(SwarmEvent::Behaviour(BehaviorEvent::Mdns(
|
log::debug!(
|
||||||
libp2p::mdns::Event::Expired(list),
|
"connection established to peer {} in connection ID {}",
|
||||||
))) => {
|
&peer_id,
|
||||||
for (peer, _) in list {
|
&connection_id,
|
||||||
log::info!("disconnecting peer due to mdns");
|
);
|
||||||
swarm.behaviour_mut().gossipsub.remove_explicit_peer(&peer);
|
swarm.behaviour_mut().gossipsub.add_explicit_peer(&peer_id)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Some(SwarmEvent::Behaviour(BehaviorEvent::Gossipsub(
|
Some(SwarmEvent::Behaviour(BehaviorEvent::Gossipsub(
|
||||||
GsEvent::Message { propagation_source, message, .. },
|
GsEvent::Message { propagation_source, message, .. },
|
||||||
))) => {
|
))) => {
|
||||||
|
@ -434,21 +472,21 @@ impl LibP2p {
|
||||||
impl P2p for LibP2p {
|
impl P2p for LibP2p {
|
||||||
type Id = PeerId;
|
type Id = PeerId;
|
||||||
|
|
||||||
async fn subscribe(&self, genesis: [u8; 32]) {
|
async fn subscribe(&self, set: ValidatorSet, genesis: [u8; 32]) {
|
||||||
self
|
self
|
||||||
.subscribe
|
.subscribe
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.send((true, genesis))
|
.send((true, set, genesis))
|
||||||
.expect("subscribe_send closed. are we shutting down?");
|
.expect("subscribe_send closed. are we shutting down?");
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn unsubscribe(&self, genesis: [u8; 32]) {
|
async fn unsubscribe(&self, set: ValidatorSet, genesis: [u8; 32]) {
|
||||||
self
|
self
|
||||||
.subscribe
|
.subscribe
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.send((false, genesis))
|
.send((false, set, genesis))
|
||||||
.expect("subscribe_send closed. are we shutting down?");
|
.expect("subscribe_send closed. are we shutting down?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,7 +590,7 @@ pub async fn handle_p2p_task<D: Db, P: P2p>(
|
||||||
channels.write().await.insert(genesis, send);
|
channels.write().await.insert(genesis, send);
|
||||||
|
|
||||||
// Subscribe to the topic for this tributary
|
// Subscribe to the topic for this tributary
|
||||||
p2p.subscribe(genesis).await;
|
p2p.subscribe(tributary.spec.set(), genesis).await;
|
||||||
|
|
||||||
// Per-Tributary P2P message handler
|
// Per-Tributary P2P message handler
|
||||||
tokio::spawn({
|
tokio::spawn({
|
||||||
|
@ -675,8 +713,8 @@ pub async fn handle_p2p_task<D: Db, P: P2p>(
|
||||||
}
|
}
|
||||||
TributaryEvent::TributaryRetired(set) => {
|
TributaryEvent::TributaryRetired(set) => {
|
||||||
if let Some(genesis) = set_to_genesis.remove(&set) {
|
if let Some(genesis) = set_to_genesis.remove(&set) {
|
||||||
|
p2p.unsubscribe(set, genesis).await;
|
||||||
channels.write().await.remove(&genesis);
|
channels.write().await.remove(&genesis);
|
||||||
p2p.unsubscribe(genesis).await;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::{
|
||||||
collections::{VecDeque, HashSet, HashMap},
|
collections::{VecDeque, HashSet, HashMap},
|
||||||
};
|
};
|
||||||
|
|
||||||
use serai_client::primitives::NetworkId;
|
use serai_client::{primitives::NetworkId, validator_sets::primitives::ValidatorSet};
|
||||||
|
|
||||||
use processor_messages::CoordinatorMessage;
|
use processor_messages::CoordinatorMessage;
|
||||||
|
|
||||||
|
@ -62,8 +62,8 @@ impl LocalP2p {
|
||||||
impl P2p for LocalP2p {
|
impl P2p for LocalP2p {
|
||||||
type Id = usize;
|
type Id = usize;
|
||||||
|
|
||||||
async fn subscribe(&self, _genesis: [u8; 32]) {}
|
async fn subscribe(&self, _set: ValidatorSet, _genesis: [u8; 32]) {}
|
||||||
async fn unsubscribe(&self, _genesis: [u8; 32]) {}
|
async fn unsubscribe(&self, _set: ValidatorSet, _genesis: [u8; 32]) {}
|
||||||
|
|
||||||
async fn send_raw(&self, to: Self::Id, _genesis: Option<[u8; 32]>, msg: Vec<u8>) {
|
async fn send_raw(&self, to: Self::Id, _genesis: Option<[u8; 32]>, msg: Vec<u8>) {
|
||||||
self.1.write().await.1[to].push_back((self.0, msg));
|
self.1.write().await.1[to].push_back((self.0, msg));
|
||||||
|
|
|
@ -100,4 +100,5 @@ allow-git = [
|
||||||
"https://github.com/serai-dex/substrate-bip39",
|
"https://github.com/serai-dex/substrate-bip39",
|
||||||
"https://github.com/serai-dex/substrate",
|
"https://github.com/serai-dex/substrate",
|
||||||
"https://github.com/monero-rs/base58-monero",
|
"https://github.com/monero-rs/base58-monero",
|
||||||
|
"https://github.com/kayabaNerve/dockertest-rs",
|
||||||
]
|
]
|
||||||
|
|
|
@ -27,6 +27,7 @@ serde_json = { version = "1", optional = true }
|
||||||
|
|
||||||
serai-abi = { path = "../abi", version = "0.1" }
|
serai-abi = { path = "../abi", version = "0.1" }
|
||||||
|
|
||||||
|
multiaddr = { version = "0.18", optional = true }
|
||||||
sp-core = { git = "https://github.com/serai-dex/substrate", optional = true }
|
sp-core = { git = "https://github.com/serai-dex/substrate", optional = true }
|
||||||
sp-runtime = { git = "https://github.com/serai-dex/substrate", optional = true }
|
sp-runtime = { git = "https://github.com/serai-dex/substrate", optional = true }
|
||||||
frame-system = { git = "https://github.com/serai-dex/substrate", optional = true }
|
frame-system = { git = "https://github.com/serai-dex/substrate", optional = true }
|
||||||
|
@ -56,7 +57,7 @@ dockertest = "0.4"
|
||||||
serai-docker-tests = { path = "../../tests/docker" }
|
serai-docker-tests = { path = "../../tests/docker" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
serai = ["thiserror", "serde", "serde_json", "sp-core", "sp-runtime", "frame-system", "simple-request"]
|
serai = ["thiserror", "serde", "serde_json", "serai-abi/serde", "multiaddr", "sp-core", "sp-runtime", "frame-system", "simple-request"]
|
||||||
borsh = ["serai-abi/borsh"]
|
borsh = ["serai-abi/borsh"]
|
||||||
|
|
||||||
networks = []
|
networks = []
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub use abi::{primitives, Transaction};
|
||||||
use abi::*;
|
use abi::*;
|
||||||
|
|
||||||
pub use primitives::{SeraiAddress, Signature, Amount};
|
pub use primitives::{SeraiAddress, Signature, Amount};
|
||||||
use primitives::Header;
|
use primitives::{Header, NetworkId};
|
||||||
|
|
||||||
pub mod coins;
|
pub mod coins;
|
||||||
pub use coins::SeraiCoins;
|
pub use coins::SeraiCoins;
|
||||||
|
@ -306,6 +306,14 @@ impl Serai {
|
||||||
pub fn as_of(&self, block: [u8; 32]) -> TemporalSerai {
|
pub fn as_of(&self, block: [u8; 32]) -> TemporalSerai {
|
||||||
TemporalSerai { serai: self, block, events: RwLock::new(None) }
|
TemporalSerai { serai: self, block, events: RwLock::new(None) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the P2P Multiaddrs for the validators of the specified network.
|
||||||
|
pub async fn p2p_validators(
|
||||||
|
&self,
|
||||||
|
network: NetworkId,
|
||||||
|
) -> Result<Vec<multiaddr::Multiaddr>, SeraiError> {
|
||||||
|
self.call("p2p_validators", network).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TemporalSerai<'a> {
|
impl<'a> TemporalSerai<'a> {
|
||||||
|
|
59
substrate/client/tests/dht.rs
Normal file
59
substrate/client/tests/dht.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use serai_client::{primitives::NetworkId, Serai};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn dht() {
|
||||||
|
use dockertest::{
|
||||||
|
PullPolicy, StartPolicy, LogOptions, LogAction, LogPolicy, LogSource, Image,
|
||||||
|
TestBodySpecification, DockerTest,
|
||||||
|
};
|
||||||
|
|
||||||
|
serai_docker_tests::build("serai".to_string());
|
||||||
|
|
||||||
|
let handle = |name| format!("serai_client-serai_node-{name}");
|
||||||
|
let composition = |name| {
|
||||||
|
TestBodySpecification::with_image(
|
||||||
|
Image::with_repository("serai-dev-serai").pull_policy(PullPolicy::Never),
|
||||||
|
)
|
||||||
|
.replace_cmd(vec![
|
||||||
|
"serai-node".to_string(),
|
||||||
|
"--unsafe-rpc-external".to_string(),
|
||||||
|
"--rpc-cors".to_string(),
|
||||||
|
"all".to_string(),
|
||||||
|
"--chain".to_string(),
|
||||||
|
"local".to_string(),
|
||||||
|
format!("--{name}"),
|
||||||
|
])
|
||||||
|
.set_publish_all_ports(true)
|
||||||
|
.set_handle(handle(name))
|
||||||
|
.set_start_policy(StartPolicy::Strict)
|
||||||
|
.set_log_options(Some(LogOptions {
|
||||||
|
action: LogAction::Forward,
|
||||||
|
policy: LogPolicy::Always,
|
||||||
|
source: LogSource::Both,
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut test = DockerTest::new().with_network(dockertest::Network::Isolated);
|
||||||
|
test.provide_container(composition("alice"));
|
||||||
|
test.provide_container(composition("bob"));
|
||||||
|
test.provide_container(composition("charlie"));
|
||||||
|
test.provide_container(composition("dave"));
|
||||||
|
test
|
||||||
|
.run_async(|ops| async move {
|
||||||
|
// Sleep until the Substrate RPC starts
|
||||||
|
let alice = handle("alice");
|
||||||
|
let serai_rpc = ops.handle(&alice).host_port(9944).unwrap();
|
||||||
|
let serai_rpc = format!("http://{}:{}", serai_rpc.0, serai_rpc.1);
|
||||||
|
// Sleep for a minute
|
||||||
|
tokio::time::sleep(core::time::Duration::from_secs(60)).await;
|
||||||
|
// Check the DHT has been populated
|
||||||
|
assert!(!Serai::new(serai_rpc.clone())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.p2p_validators(NetworkId::Bitcoin)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.is_empty());
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
|
@ -145,7 +145,7 @@ pub mod pallet {
|
||||||
fn increase_balance_internal(to: Public, balance: Balance) -> Result<(), Error<T, I>> {
|
fn increase_balance_internal(to: Public, balance: Balance) -> Result<(), Error<T, I>> {
|
||||||
let coin = &balance.coin;
|
let coin = &balance.coin;
|
||||||
|
|
||||||
// sub amount from account
|
// add amount to account
|
||||||
let new_amount = Self::balances(to, coin)
|
let new_amount = Self::balances(to, coin)
|
||||||
.checked_add(balance.amount.0)
|
.checked_add(balance.amount.0)
|
||||||
.ok_or(Error::<T, I>::AmountOverflowed)?;
|
.ok_or(Error::<T, I>::AmountOverflowed)?;
|
||||||
|
|
|
@ -20,11 +20,6 @@ workspace = true
|
||||||
name = "serai-node"
|
name = "serai-node"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4", features = ["derive"] }
|
|
||||||
|
|
||||||
futures-util = "0.3"
|
|
||||||
jsonrpsee = { version = "0.16", features = ["server"] }
|
|
||||||
|
|
||||||
sp-core = { git = "https://github.com/serai-dex/substrate" }
|
sp-core = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sp-timestamp = { git = "https://github.com/serai-dex/substrate" }
|
sp-timestamp = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sp-io = { git = "https://github.com/serai-dex/substrate" }
|
sp-io = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
@ -37,6 +32,12 @@ frame-benchmarking = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
||||||
serai-runtime = { path = "../runtime", features = ["std"] }
|
serai-runtime = { path = "../runtime", features = ["std"] }
|
||||||
|
|
||||||
|
clap = { version = "4", features = ["derive"] }
|
||||||
|
|
||||||
|
futures-util = "0.3"
|
||||||
|
tokio = { version = "1", features = ["sync", "rt-multi-thread"] }
|
||||||
|
jsonrpsee = { version = "0.16", features = ["server"] }
|
||||||
|
|
||||||
sc-offchain = { git = "https://github.com/serai-dex/substrate" }
|
sc-offchain = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-transaction-pool = { git = "https://github.com/serai-dex/substrate" }
|
sc-transaction-pool = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-transaction-pool-api = { git = "https://github.com/serai-dex/substrate" }
|
sc-transaction-pool-api = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
use std::sync::Arc;
|
use std::{sync::Arc, collections::HashSet};
|
||||||
|
|
||||||
use jsonrpsee::RpcModule;
|
|
||||||
|
|
||||||
use sp_blockchain::{Error as BlockchainError, HeaderBackend, HeaderMetadata};
|
use sp_blockchain::{Error as BlockchainError, HeaderBackend, HeaderMetadata};
|
||||||
use sp_block_builder::BlockBuilder;
|
use sp_block_builder::BlockBuilder;
|
||||||
use sp_api::ProvideRuntimeApi;
|
use sp_api::ProvideRuntimeApi;
|
||||||
|
|
||||||
use serai_runtime::{
|
use serai_runtime::{
|
||||||
primitives::{SubstrateAmount, PublicKey},
|
primitives::{NetworkId, SubstrateAmount, PublicKey},
|
||||||
Nonce, Block,
|
Nonce, Block, SeraiRuntimeApi,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
use jsonrpsee::RpcModule;
|
||||||
|
|
||||||
pub use sc_rpc_api::DenyUnsafe;
|
pub use sc_rpc_api::DenyUnsafe;
|
||||||
use sc_transaction_pool_api::TransactionPool;
|
use sc_transaction_pool_api::TransactionPool;
|
||||||
|
|
||||||
|
@ -18,6 +20,7 @@ pub struct FullDeps<C, P> {
|
||||||
pub client: Arc<C>,
|
pub client: Arc<C>,
|
||||||
pub pool: Arc<P>,
|
pub pool: Arc<P>,
|
||||||
pub deny_unsafe: DenyUnsafe,
|
pub deny_unsafe: DenyUnsafe,
|
||||||
|
pub authority_discovery: Option<sc_authority_discovery::Service>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_full<
|
pub fn create_full<
|
||||||
|
@ -34,16 +37,56 @@ pub fn create_full<
|
||||||
where
|
where
|
||||||
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, PublicKey, Nonce>
|
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, PublicKey, Nonce>
|
||||||
+ pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, SubstrateAmount>
|
+ pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, SubstrateAmount>
|
||||||
|
+ SeraiRuntimeApi<Block>
|
||||||
+ BlockBuilder<Block>,
|
+ BlockBuilder<Block>,
|
||||||
{
|
{
|
||||||
use substrate_frame_rpc_system::{System, SystemApiServer};
|
use substrate_frame_rpc_system::{System, SystemApiServer};
|
||||||
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
|
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
|
||||||
|
|
||||||
let mut module = RpcModule::new(());
|
let mut module = RpcModule::new(());
|
||||||
let FullDeps { client, pool, deny_unsafe } = deps;
|
let FullDeps { client, pool, deny_unsafe, authority_discovery } = deps;
|
||||||
|
|
||||||
module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?;
|
module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?;
|
||||||
module.merge(TransactionPayment::new(client).into_rpc())?;
|
module.merge(TransactionPayment::new(client.clone()).into_rpc())?;
|
||||||
|
|
||||||
|
if let Some(authority_discovery) = authority_discovery {
|
||||||
|
let mut authority_discovery_module = RpcModule::new((client, RwLock::new(authority_discovery)));
|
||||||
|
authority_discovery_module.register_async_method(
|
||||||
|
"p2p_validators",
|
||||||
|
|params, context| async move {
|
||||||
|
let network: NetworkId = params.parse()?;
|
||||||
|
let (client, authority_discovery) = &*context;
|
||||||
|
let latest_block = client.info().best_hash;
|
||||||
|
|
||||||
|
let validators = client.runtime_api().validators(latest_block, network).map_err(|_| {
|
||||||
|
jsonrpsee::core::Error::to_call_error(std::io::Error::other(format!(
|
||||||
|
"couldn't get validators from the latest block, which is likely a fatal bug. {}",
|
||||||
|
"please report this at https://github.com/serai-dex/serai",
|
||||||
|
)))
|
||||||
|
})?;
|
||||||
|
let mut all_p2p_addresses = vec![];
|
||||||
|
for validator in validators {
|
||||||
|
let mut returned_addresses = authority_discovery
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.get_addresses_by_authority_id(validator.into())
|
||||||
|
.await
|
||||||
|
.unwrap_or_else(HashSet::new)
|
||||||
|
.into_iter();
|
||||||
|
// Only take a single address
|
||||||
|
// There should be one, there may be two if their IP address changed, and more should only
|
||||||
|
// occur if they have multiple proxies/an IP address changing frequently/some issue
|
||||||
|
// preventing consistent self-identification
|
||||||
|
// It isn't beneficial to use multiple addresses for a single peer here
|
||||||
|
if let Some(address) = returned_addresses.next() {
|
||||||
|
all_p2p_addresses.push(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(all_p2p_addresses)
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
module.merge(authority_discovery_module)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(module)
|
Ok(module)
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,6 +206,42 @@ pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let role = config.role.clone();
|
||||||
|
let keystore = keystore_container.keystore();
|
||||||
|
let prometheus_registry = config.prometheus_registry().cloned();
|
||||||
|
|
||||||
|
// TODO: Ensure we're considered as an authority is a validator of an external network
|
||||||
|
let authority_discovery = if role.is_authority() {
|
||||||
|
let (worker, service) = sc_authority_discovery::new_worker_and_service_with_config(
|
||||||
|
#[allow(clippy::field_reassign_with_default)]
|
||||||
|
{
|
||||||
|
let mut worker = sc_authority_discovery::WorkerConfig::default();
|
||||||
|
worker.publish_non_global_ips = publish_non_global_ips;
|
||||||
|
worker.strict_record_validation = true;
|
||||||
|
worker
|
||||||
|
},
|
||||||
|
client.clone(),
|
||||||
|
network.clone(),
|
||||||
|
Box::pin(network.event_stream("authority-discovery").filter_map(|e| async move {
|
||||||
|
match e {
|
||||||
|
Event::Dht(e) => Some(e),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
sc_authority_discovery::Role::PublishAndDiscover(keystore.clone()),
|
||||||
|
prometheus_registry.clone(),
|
||||||
|
);
|
||||||
|
task_manager.spawn_handle().spawn(
|
||||||
|
"authority-discovery-worker",
|
||||||
|
Some("networking"),
|
||||||
|
worker.run(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Some(service)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let rpc_builder = {
|
let rpc_builder = {
|
||||||
let client = client.clone();
|
let client = client.clone();
|
||||||
let pool = transaction_pool.clone();
|
let pool = transaction_pool.clone();
|
||||||
|
@ -215,18 +251,15 @@ pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
pool: pool.clone(),
|
pool: pool.clone(),
|
||||||
deny_unsafe,
|
deny_unsafe,
|
||||||
|
authority_discovery: authority_discovery.clone(),
|
||||||
})
|
})
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let enable_grandpa = !config.disable_grandpa;
|
let enable_grandpa = !config.disable_grandpa;
|
||||||
let role = config.role.clone();
|
|
||||||
let force_authoring = config.force_authoring;
|
let force_authoring = config.force_authoring;
|
||||||
let name = config.network.node_name.clone();
|
let name = config.network.node_name.clone();
|
||||||
let prometheus_registry = config.prometheus_registry().cloned();
|
|
||||||
|
|
||||||
let keystore = keystore_container.keystore();
|
|
||||||
|
|
||||||
sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||||
config,
|
config,
|
||||||
|
@ -251,7 +284,7 @@ pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
|
||||||
select_chain,
|
select_chain,
|
||||||
env: sc_basic_authorship::ProposerFactory::new(
|
env: sc_basic_authorship::ProposerFactory::new(
|
||||||
task_manager.spawn_handle(),
|
task_manager.spawn_handle(),
|
||||||
client.clone(),
|
client,
|
||||||
transaction_pool.clone(),
|
transaction_pool.clone(),
|
||||||
prometheus_registry.as_ref(),
|
prometheus_registry.as_ref(),
|
||||||
telemetry.as_ref().map(Telemetry::handle),
|
telemetry.as_ref().map(Telemetry::handle),
|
||||||
|
@ -277,33 +310,6 @@ pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if role.is_authority() {
|
|
||||||
task_manager.spawn_handle().spawn(
|
|
||||||
"authority-discovery-worker",
|
|
||||||
Some("networking"),
|
|
||||||
sc_authority_discovery::new_worker_and_service_with_config(
|
|
||||||
#[allow(clippy::field_reassign_with_default)]
|
|
||||||
{
|
|
||||||
let mut worker = sc_authority_discovery::WorkerConfig::default();
|
|
||||||
worker.publish_non_global_ips = publish_non_global_ips;
|
|
||||||
worker
|
|
||||||
},
|
|
||||||
client,
|
|
||||||
network.clone(),
|
|
||||||
Box::pin(network.event_stream("authority-discovery").filter_map(|e| async move {
|
|
||||||
match e {
|
|
||||||
Event::Dht(e) => Some(e),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
})),
|
|
||||||
sc_authority_discovery::Role::PublishAndDiscover(keystore.clone()),
|
|
||||||
prometheus_registry.clone(),
|
|
||||||
)
|
|
||||||
.0
|
|
||||||
.run(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if enable_grandpa {
|
if enable_grandpa {
|
||||||
task_manager.spawn_essential_handle().spawn_blocking(
|
task_manager.spawn_essential_handle().spawn_blocking(
|
||||||
"grandpa-voter",
|
"grandpa-voter",
|
||||||
|
|
|
@ -19,6 +19,8 @@ ignored = ["scale", "scale-info"]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
hashbrown = { version = "0.14", default-features = false, features = ["ahash", "inline-more"] }
|
||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||||
scale-info = { version = "2", default-features = false, features = ["derive"] }
|
scale-info = { version = "2", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ use core::marker::PhantomData;
|
||||||
// Re-export all components
|
// Re-export all components
|
||||||
pub use serai_primitives as primitives;
|
pub use serai_primitives as primitives;
|
||||||
pub use primitives::{BlockNumber, Header};
|
pub use primitives::{BlockNumber, Header};
|
||||||
|
use primitives::{NetworkId, NETWORKS};
|
||||||
|
|
||||||
pub use frame_system as system;
|
pub use frame_system as system;
|
||||||
pub use frame_support as support;
|
pub use frame_support as support;
|
||||||
|
@ -43,7 +44,7 @@ use sp_runtime::{
|
||||||
create_runtime_str, generic, impl_opaque_keys, KeyTypeId,
|
create_runtime_str, generic, impl_opaque_keys, KeyTypeId,
|
||||||
traits::{Convert, BlakeTwo256, Block as BlockT},
|
traits::{Convert, BlakeTwo256, Block as BlockT},
|
||||||
transaction_validity::{TransactionSource, TransactionValidity},
|
transaction_validity::{TransactionSource, TransactionValidity},
|
||||||
Perbill, ApplyExtrinsicResult,
|
BoundedVec, Perbill, ApplyExtrinsicResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
use primitives::{PublicKey, AccountLookup, SubstrateAmount};
|
use primitives::{PublicKey, AccountLookup, SubstrateAmount};
|
||||||
|
@ -377,6 +378,13 @@ mod benches {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sp_api::decl_runtime_apis! {
|
||||||
|
#[api_version(1)]
|
||||||
|
pub trait SeraiRuntimeApi {
|
||||||
|
fn validators(network_id: NetworkId) -> Vec<PublicKey>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sp_api::impl_runtime_apis! {
|
sp_api::impl_runtime_apis! {
|
||||||
impl sp_api::Core<Block> for Runtime {
|
impl sp_api::Core<Block> for Runtime {
|
||||||
fn version() -> RuntimeVersion {
|
fn version() -> RuntimeVersion {
|
||||||
|
@ -561,10 +569,41 @@ sp_api::impl_runtime_apis! {
|
||||||
|
|
||||||
impl sp_authority_discovery::AuthorityDiscoveryApi<Block> for Runtime {
|
impl sp_authority_discovery::AuthorityDiscoveryApi<Block> for Runtime {
|
||||||
fn authorities() -> Vec<AuthorityDiscoveryId> {
|
fn authorities() -> Vec<AuthorityDiscoveryId> {
|
||||||
Babe::authorities()
|
// Converts to `[u8; 32]` so it can be hashed
|
||||||
|
let serai_validators = Babe::authorities()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, _)| AuthorityDiscoveryId::from(id.into_inner()))
|
.map(|(id, _)| id.into_inner().0)
|
||||||
.collect()
|
.collect::<hashbrown::HashSet<_>>();
|
||||||
|
let mut all = serai_validators;
|
||||||
|
for network in NETWORKS {
|
||||||
|
if network == NetworkId::Serai {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let participants =
|
||||||
|
ValidatorSets::participants_for_latest_decided_set(network)
|
||||||
|
.map_or(vec![], BoundedVec::into_inner);
|
||||||
|
for (participant, _) in participants {
|
||||||
|
all.insert(participant.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
all.into_iter().map(|id| AuthorityDiscoveryId::from(PublicKey::from_raw(id))).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::SeraiRuntimeApi<Block> for Runtime {
|
||||||
|
fn validators(network_id: NetworkId) -> Vec<PublicKey> {
|
||||||
|
if network_id == NetworkId::Serai {
|
||||||
|
Babe::authorities()
|
||||||
|
.into_iter()
|
||||||
|
.map(|(id, _)| id.into_inner())
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
ValidatorSets::participants_for_latest_decided_set(network_id)
|
||||||
|
.map_or(
|
||||||
|
vec![],
|
||||||
|
|vec| vec.into_inner().into_iter().map(|(validator, _)| validator).collect()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,8 +124,9 @@ pub mod pallet {
|
||||||
#[pallet::getter(fn allocation_per_key_share)]
|
#[pallet::getter(fn allocation_per_key_share)]
|
||||||
pub type AllocationPerKeyShare<T: Config> =
|
pub type AllocationPerKeyShare<T: Config> =
|
||||||
StorageMap<_, Identity, NetworkId, Amount, OptionQuery>;
|
StorageMap<_, Identity, NetworkId, Amount, OptionQuery>;
|
||||||
/// The validators selected to be in-set who haven't been removed.
|
/// The validators selected to be in-set.
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
|
#[pallet::getter(fn participants_for_latest_decided_set)]
|
||||||
pub(crate) type Participants<T: Config> = StorageMap<
|
pub(crate) type Participants<T: Config> = StorageMap<
|
||||||
_,
|
_,
|
||||||
Identity,
|
Identity,
|
||||||
|
|
|
@ -19,6 +19,8 @@ workspace = true
|
||||||
[dependencies]
|
[dependencies]
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
|
||||||
|
async-trait = "0.1"
|
||||||
|
async-recursion = "1"
|
||||||
zeroize = { version = "1", default-features = false }
|
zeroize = { version = "1", default-features = false }
|
||||||
rand_core = { version = "0.6", default-features = false }
|
rand_core = { version = "0.6", default-features = false }
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#![allow(clippy::needless_pass_by_ref_mut)] // False positives
|
#![allow(clippy::needless_pass_by_ref_mut)] // False positives
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
sync::{OnceLock, Arc, Mutex},
|
sync::{OnceLock, Arc},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
fs,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use tokio::{task::AbortHandle, sync::Mutex as AsyncMutex};
|
use tokio::{task::AbortHandle, sync::Mutex as AsyncMutex};
|
||||||
|
@ -27,16 +26,11 @@ use serai_message_queue::{Service, Metadata, client::MessageQueue};
|
||||||
|
|
||||||
use serai_client::{primitives::Signature, Serai};
|
use serai_client::{primitives::Signature, Serai};
|
||||||
|
|
||||||
use dockertest::{
|
use dockertest::{PullPolicy, Image, TestBodySpecification, DockerOperations};
|
||||||
PullPolicy, Image, LogAction, LogPolicy, LogSource, LogOptions, StartPolicy,
|
|
||||||
TestBodySpecification, DockerOperations,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
static UNIQUE_ID: OnceLock<Mutex<u16>> = OnceLock::new();
|
|
||||||
|
|
||||||
pub fn coordinator_instance(
|
pub fn coordinator_instance(
|
||||||
name: &str,
|
name: &str,
|
||||||
message_queue_key: <Ristretto as Ciphersuite>::F,
|
message_queue_key: <Ristretto as Ciphersuite>::F,
|
||||||
|
@ -81,78 +75,6 @@ pub fn serai_composition(name: &str) -> TestBodySpecification {
|
||||||
.set_publish_all_ports(true)
|
.set_publish_all_ports(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Handles = (String, String, String);
|
|
||||||
pub fn coordinator_stack(
|
|
||||||
name: &str,
|
|
||||||
) -> (Handles, <Ristretto as Ciphersuite>::F, Vec<TestBodySpecification>) {
|
|
||||||
let serai_composition = serai_composition(name);
|
|
||||||
|
|
||||||
let (coord_key, message_queue_keys, message_queue_composition) =
|
|
||||||
serai_message_queue_tests::instance();
|
|
||||||
|
|
||||||
let coordinator_composition = coordinator_instance(name, coord_key);
|
|
||||||
|
|
||||||
// Give every item in this stack a unique ID
|
|
||||||
// Uses a Mutex as we can't generate a 8-byte random ID without hitting hostname length limits
|
|
||||||
let (first, unique_id) = {
|
|
||||||
let unique_id_mutex = UNIQUE_ID.get_or_init(|| Mutex::new(0));
|
|
||||||
let mut unique_id_lock = unique_id_mutex.lock().unwrap();
|
|
||||||
let first = *unique_id_lock == 0;
|
|
||||||
let unique_id = *unique_id_lock;
|
|
||||||
*unique_id_lock += 1;
|
|
||||||
(first, unique_id)
|
|
||||||
};
|
|
||||||
|
|
||||||
let logs_path = [std::env::current_dir().unwrap().to_str().unwrap(), ".test-logs", "coordinator"]
|
|
||||||
.iter()
|
|
||||||
.collect::<std::path::PathBuf>();
|
|
||||||
if first {
|
|
||||||
let _ = fs::remove_dir_all(&logs_path);
|
|
||||||
fs::create_dir_all(&logs_path).expect("couldn't create logs directory");
|
|
||||||
assert!(
|
|
||||||
fs::read_dir(&logs_path).expect("couldn't read the logs folder").next().is_none(),
|
|
||||||
"logs folder wasn't empty, despite removing it at the start of the run",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let logs_path = logs_path.to_str().unwrap().to_string();
|
|
||||||
|
|
||||||
let mut compositions = vec![];
|
|
||||||
let mut handles = vec![];
|
|
||||||
for (name, composition) in [
|
|
||||||
("serai_node", serai_composition),
|
|
||||||
("message_queue", message_queue_composition),
|
|
||||||
("coordinator", coordinator_composition),
|
|
||||||
] {
|
|
||||||
let handle = format!("coordinator-{name}-{unique_id}");
|
|
||||||
|
|
||||||
compositions.push(
|
|
||||||
composition.set_start_policy(StartPolicy::Strict).set_handle(handle.clone()).set_log_options(
|
|
||||||
Some(LogOptions {
|
|
||||||
action: if std::env::var("GITHUB_CI") == Ok("true".to_string()) {
|
|
||||||
LogAction::Forward
|
|
||||||
} else {
|
|
||||||
LogAction::ForwardToFile { path: logs_path.clone() }
|
|
||||||
},
|
|
||||||
policy: LogPolicy::Always,
|
|
||||||
source: LogSource::Both,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
handles.push(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
let coordinator_composition = compositions.last_mut().unwrap();
|
|
||||||
coordinator_composition.inject_container_name(handles[0].clone(), "SERAI_HOSTNAME");
|
|
||||||
coordinator_composition.inject_container_name(handles[1].clone(), "MESSAGE_QUEUE_RPC");
|
|
||||||
|
|
||||||
(
|
|
||||||
(handles[0].clone(), handles[1].clone(), handles[2].clone()),
|
|
||||||
message_queue_keys[&NetworkId::Bitcoin],
|
|
||||||
compositions,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_cosign_message(msg: &CoordinatorMessage) -> bool {
|
fn is_cosign_message(msg: &CoordinatorMessage) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
msg,
|
msg,
|
||||||
|
@ -176,15 +98,19 @@ fn is_cosign_message(msg: &CoordinatorMessage) -> bool {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub struct Handles {
|
||||||
|
pub(crate) serai: String,
|
||||||
|
pub(crate) message_queue: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Processor {
|
pub struct Processor {
|
||||||
network: NetworkId,
|
network: NetworkId,
|
||||||
|
|
||||||
serai_rpc: String,
|
serai_rpc: String,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
message_queue_handle: String,
|
handles: Handles,
|
||||||
#[allow(unused)]
|
|
||||||
coordinator_handle: String,
|
|
||||||
|
|
||||||
queue: Arc<AsyncMutex<(u64, u64, MessageQueue)>>,
|
queue: Arc<AsyncMutex<(u64, u64, MessageQueue)>>,
|
||||||
abort_handle: Option<Arc<AbortHandle>>,
|
abort_handle: Option<Arc<AbortHandle>>,
|
||||||
|
@ -205,14 +131,14 @@ impl Processor {
|
||||||
raw_i: u8,
|
raw_i: u8,
|
||||||
network: NetworkId,
|
network: NetworkId,
|
||||||
ops: &DockerOperations,
|
ops: &DockerOperations,
|
||||||
handles: (String, String, String),
|
handles: Handles,
|
||||||
processor_key: <Ristretto as Ciphersuite>::F,
|
processor_key: <Ristretto as Ciphersuite>::F,
|
||||||
) -> Processor {
|
) -> Processor {
|
||||||
let message_queue_rpc = ops.handle(&handles.1).host_port(2287).unwrap();
|
let message_queue_rpc = ops.handle(&handles.message_queue).host_port(2287).unwrap();
|
||||||
let message_queue_rpc = format!("{}:{}", message_queue_rpc.0, message_queue_rpc.1);
|
let message_queue_rpc = format!("{}:{}", message_queue_rpc.0, message_queue_rpc.1);
|
||||||
|
|
||||||
// Sleep until the Substrate RPC starts
|
// Sleep until the Substrate RPC starts
|
||||||
let serai_rpc = ops.handle(&handles.0).host_port(9944).unwrap();
|
let serai_rpc = ops.handle(&handles.serai).host_port(9944).unwrap();
|
||||||
let serai_rpc = format!("http://{}:{}", serai_rpc.0, serai_rpc.1);
|
let serai_rpc = format!("http://{}:{}", serai_rpc.0, serai_rpc.1);
|
||||||
// Bound execution to 60 seconds
|
// Bound execution to 60 seconds
|
||||||
for _ in 0 .. 60 {
|
for _ in 0 .. 60 {
|
||||||
|
@ -231,8 +157,7 @@ impl Processor {
|
||||||
network,
|
network,
|
||||||
|
|
||||||
serai_rpc,
|
serai_rpc,
|
||||||
message_queue_handle: handles.1,
|
handles,
|
||||||
coordinator_handle: handles.2,
|
|
||||||
|
|
||||||
queue: Arc::new(AsyncMutex::new((
|
queue: Arc::new(AsyncMutex::new((
|
||||||
0,
|
0,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::{
|
use std::{
|
||||||
sync::Mutex,
|
|
||||||
time::Duration,
|
time::Duration,
|
||||||
collections::{HashSet, HashMap},
|
collections::{HashSet, HashMap},
|
||||||
};
|
};
|
||||||
|
@ -261,43 +260,21 @@ pub async fn batch(
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn batch_test() {
|
async fn batch_test() {
|
||||||
let _one_at_a_time = ONE_AT_A_TIME.get_or_init(|| Mutex::new(())).lock();
|
new_test(|mut processors: Vec<Processor>| async move {
|
||||||
let (processors, test) = new_test();
|
let (processor_is, substrate_key, _) = key_gen::<Secp256k1>(&mut processors).await;
|
||||||
|
batch(
|
||||||
test
|
&mut processors,
|
||||||
.run_async(|ops| async move {
|
&processor_is,
|
||||||
// Wait for the Serai node to boot, and for the Tendermint chain to get past the first block
|
Session(0),
|
||||||
// TODO: Replace this with a Coordinator RPC
|
&substrate_key,
|
||||||
tokio::time::sleep(Duration::from_secs(150)).await;
|
Batch {
|
||||||
|
network: NetworkId::Bitcoin,
|
||||||
// Sleep even longer if in the CI due to it being slower than commodity hardware
|
id: 0,
|
||||||
if std::env::var("GITHUB_CI") == Ok("true".to_string()) {
|
block: BlockHash([0x22; 32]),
|
||||||
tokio::time::sleep(Duration::from_secs(120)).await;
|
instructions: vec![],
|
||||||
}
|
},
|
||||||
|
)
|
||||||
// Connect to the Message Queues as the processor
|
|
||||||
let mut new_processors: Vec<Processor> = vec![];
|
|
||||||
for (i, (handles, key)) in processors.into_iter().enumerate() {
|
|
||||||
new_processors.push(
|
|
||||||
Processor::new(i.try_into().unwrap(), NetworkId::Bitcoin, &ops, handles, key).await,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut processors = new_processors;
|
|
||||||
|
|
||||||
let (processor_is, substrate_key, _) = key_gen::<Secp256k1>(&mut processors).await;
|
|
||||||
batch(
|
|
||||||
&mut processors,
|
|
||||||
&processor_is,
|
|
||||||
Session(0),
|
|
||||||
&substrate_key,
|
|
||||||
Batch {
|
|
||||||
network: NetworkId::Bitcoin,
|
|
||||||
id: 0,
|
|
||||||
block: BlockHash([0x22; 32]),
|
|
||||||
instructions: vec![],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
})
|
|
||||||
.await;
|
.await;
|
||||||
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::{
|
use std::{
|
||||||
sync::Mutex,
|
|
||||||
time::{Duration, SystemTime},
|
time::{Duration, SystemTime},
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
};
|
};
|
||||||
|
@ -221,30 +220,8 @@ pub async fn key_gen<C: Ciphersuite>(
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn key_gen_test() {
|
async fn key_gen_test() {
|
||||||
let _one_at_a_time = ONE_AT_A_TIME.get_or_init(|| Mutex::new(())).lock();
|
new_test(|mut processors: Vec<Processor>| async move {
|
||||||
let (processors, test) = new_test();
|
key_gen::<Secp256k1>(&mut processors).await;
|
||||||
|
})
|
||||||
test
|
.await;
|
||||||
.run_async(|ops| async move {
|
|
||||||
// Wait for the Serai node to boot, and for the Tendermint chain to get past the first block
|
|
||||||
// TODO: Replace this with a Coordinator RPC
|
|
||||||
tokio::time::sleep(Duration::from_secs(150)).await;
|
|
||||||
|
|
||||||
// Sleep even longer if in the CI due to it being slower than commodity hardware
|
|
||||||
if std::env::var("GITHUB_CI") == Ok("true".to_string()) {
|
|
||||||
tokio::time::sleep(Duration::from_secs(120)).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect to the Message Queues as the processor
|
|
||||||
let mut new_processors: Vec<Processor> = vec![];
|
|
||||||
for (i, (handles, key)) in processors.into_iter().enumerate() {
|
|
||||||
new_processors.push(
|
|
||||||
Processor::new(i.try_into().unwrap(), NetworkId::Bitcoin, &ops, handles, key).await,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut processors = new_processors;
|
|
||||||
|
|
||||||
key_gen::<Secp256k1>(&mut processors).await;
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
use std::sync::OnceLock;
|
use core::future::Future;
|
||||||
|
use std::{sync::OnceLock, collections::HashMap};
|
||||||
|
|
||||||
use ciphersuite::Ristretto;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use dockertest::DockerTest;
|
use dockertest::{
|
||||||
|
LogAction, LogPolicy, LogSource, LogOptions, StartPolicy, TestBodySpecification,
|
||||||
|
DockerOperations, DockerTest,
|
||||||
|
};
|
||||||
|
|
||||||
|
use serai_docker_tests::fresh_logs_folder;
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
|
@ -19,13 +25,28 @@ pub use sign::sign;
|
||||||
pub(crate) const COORDINATORS: usize = 4;
|
pub(crate) const COORDINATORS: usize = 4;
|
||||||
pub(crate) const THRESHOLD: usize = ((COORDINATORS * 2) / 3) + 1;
|
pub(crate) const THRESHOLD: usize = ((COORDINATORS * 2) / 3) + 1;
|
||||||
|
|
||||||
pub(crate) static ONE_AT_A_TIME: OnceLock<Mutex<()>> = OnceLock::new();
|
// Provide a unique ID and ensures only one invocation occurs at a time.
|
||||||
|
static UNIQUE_ID: OnceLock<Mutex<u16>> = OnceLock::new();
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
pub(crate) trait TestBody: 'static + Send + Sync {
|
||||||
|
async fn body(&self, processors: Vec<Processor>);
|
||||||
|
}
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<F: Send + Future, TB: 'static + Send + Sync + Fn(Vec<Processor>) -> F> TestBody for TB {
|
||||||
|
async fn body(&self, processors: Vec<Processor>) {
|
||||||
|
(self)(processors).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn new_test(test_body: impl TestBody) {
|
||||||
|
let mut unique_id_lock = UNIQUE_ID.get_or_init(|| Mutex::new(0)).lock().await;
|
||||||
|
|
||||||
pub(crate) fn new_test() -> (Vec<(Handles, <Ristretto as Ciphersuite>::F)>, DockerTest) {
|
|
||||||
let mut coordinators = vec![];
|
let mut coordinators = vec![];
|
||||||
let mut test = DockerTest::new().with_network(dockertest::Network::Isolated);
|
let mut test = DockerTest::new().with_network(dockertest::Network::Isolated);
|
||||||
|
let mut coordinator_compositions = vec![];
|
||||||
for i in 0 .. COORDINATORS {
|
for i in 0 .. COORDINATORS {
|
||||||
let (handles, coord_key, compositions) = coordinator_stack(match i {
|
let name = match i {
|
||||||
0 => "Alice",
|
0 => "Alice",
|
||||||
1 => "Bob",
|
1 => "Bob",
|
||||||
2 => "Charlie",
|
2 => "Charlie",
|
||||||
|
@ -33,13 +54,158 @@ pub(crate) fn new_test() -> (Vec<(Handles, <Ristretto as Ciphersuite>::F)>, Dock
|
||||||
4 => "Eve",
|
4 => "Eve",
|
||||||
5 => "Ferdie",
|
5 => "Ferdie",
|
||||||
_ => panic!("needed a 7th name for a serai node"),
|
_ => panic!("needed a 7th name for a serai node"),
|
||||||
});
|
};
|
||||||
coordinators.push((handles, coord_key));
|
let serai_composition = serai_composition(name);
|
||||||
|
|
||||||
|
let (processor_key, message_queue_keys, message_queue_composition) =
|
||||||
|
serai_message_queue_tests::instance();
|
||||||
|
|
||||||
|
let coordinator_composition = coordinator_instance(name, processor_key);
|
||||||
|
|
||||||
|
// Give every item in this stack a unique ID
|
||||||
|
// Uses a Mutex as we can't generate a 8-byte random ID without hitting hostname length limits
|
||||||
|
let (first, unique_id) = {
|
||||||
|
let first = *unique_id_lock == 0;
|
||||||
|
let unique_id = *unique_id_lock;
|
||||||
|
*unique_id_lock += 1;
|
||||||
|
(first, unique_id)
|
||||||
|
};
|
||||||
|
|
||||||
|
let logs_path = fresh_logs_folder(first, "coordinator");
|
||||||
|
|
||||||
|
let mut compositions = vec![];
|
||||||
|
let mut handles = HashMap::new();
|
||||||
|
for (name, composition) in [
|
||||||
|
("serai_node", serai_composition),
|
||||||
|
("message_queue", message_queue_composition),
|
||||||
|
("coordinator", coordinator_composition),
|
||||||
|
] {
|
||||||
|
let handle = format!("coordinator-{name}-{unique_id}");
|
||||||
|
|
||||||
|
compositions.push(
|
||||||
|
composition
|
||||||
|
.set_start_policy(StartPolicy::Strict)
|
||||||
|
.set_handle(handle.clone())
|
||||||
|
.set_log_options(Some(LogOptions {
|
||||||
|
action: if std::env::var("GITHUB_CI") == Ok("true".to_string()) {
|
||||||
|
LogAction::Forward
|
||||||
|
} else {
|
||||||
|
LogAction::ForwardToFile { path: logs_path.clone() }
|
||||||
|
},
|
||||||
|
policy: LogPolicy::Always,
|
||||||
|
source: LogSource::Both,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
|
handles.insert(name, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
let processor_key = message_queue_keys[&NetworkId::Bitcoin];
|
||||||
|
|
||||||
|
coordinators.push((
|
||||||
|
Handles {
|
||||||
|
serai: handles.remove("serai_node").unwrap(),
|
||||||
|
message_queue: handles.remove("message_queue").unwrap(),
|
||||||
|
},
|
||||||
|
processor_key,
|
||||||
|
));
|
||||||
|
coordinator_compositions.push(compositions.pop().unwrap());
|
||||||
for composition in compositions {
|
for composition in compositions {
|
||||||
test.provide_container(composition);
|
test.provide_container(composition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(coordinators, test)
|
|
||||||
|
struct Context {
|
||||||
|
pending_coordinator_compositions: Mutex<Vec<TestBodySpecification>>,
|
||||||
|
handles_and_keys: Vec<(Handles, <Ristretto as Ciphersuite>::F)>,
|
||||||
|
test_body: Box<dyn TestBody>,
|
||||||
|
}
|
||||||
|
static CONTEXT: OnceLock<Mutex<Option<Context>>> = OnceLock::new();
|
||||||
|
*CONTEXT.get_or_init(|| Mutex::new(None)).lock().await = Some(Context {
|
||||||
|
pending_coordinator_compositions: Mutex::new(coordinator_compositions),
|
||||||
|
handles_and_keys: coordinators,
|
||||||
|
test_body: Box::new(test_body),
|
||||||
|
});
|
||||||
|
|
||||||
|
// The DockerOperations from the first invocation, containing the Message Queue servers and the
|
||||||
|
// Serai nodes.
|
||||||
|
static OUTER_OPS: OnceLock<Mutex<Option<DockerOperations>>> = OnceLock::new();
|
||||||
|
|
||||||
|
// Reset OUTER_OPS
|
||||||
|
*OUTER_OPS.get_or_init(|| Mutex::new(None)).lock().await = None;
|
||||||
|
|
||||||
|
// Spawns a coordinator, if one has yet to be spawned, or else runs the test.
|
||||||
|
#[async_recursion::async_recursion]
|
||||||
|
async fn spawn_coordinator_or_run_test(inner_ops: DockerOperations) {
|
||||||
|
// If the outer operations have yet to be set, these *are* the outer operations
|
||||||
|
let outer_ops = OUTER_OPS.get().unwrap();
|
||||||
|
if outer_ops.lock().await.is_none() {
|
||||||
|
*outer_ops.lock().await = Some(inner_ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
let context_lock = CONTEXT.get().unwrap().lock().await;
|
||||||
|
let Context { pending_coordinator_compositions, handles_and_keys: coordinators, test_body } =
|
||||||
|
context_lock.as_ref().unwrap();
|
||||||
|
|
||||||
|
// Check if there is a coordinator left
|
||||||
|
let maybe_coordinator = {
|
||||||
|
let mut remaining = pending_coordinator_compositions.lock().await;
|
||||||
|
let maybe_coordinator = if !remaining.is_empty() {
|
||||||
|
let handles = coordinators[coordinators.len() - remaining.len()].0.clone();
|
||||||
|
let composition = remaining.remove(0);
|
||||||
|
Some((composition, handles))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
drop(remaining);
|
||||||
|
maybe_coordinator
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some((mut composition, handles)) = maybe_coordinator {
|
||||||
|
let network = {
|
||||||
|
let outer_ops = outer_ops.lock().await;
|
||||||
|
let outer_ops = outer_ops.as_ref().unwrap();
|
||||||
|
// Spawn it by building another DockerTest which recursively calls this function
|
||||||
|
// TODO: Spawn this outside of DockerTest so we can remove the recursion
|
||||||
|
let serai_container = outer_ops.handle(&handles.serai);
|
||||||
|
composition.modify_env("SERAI_HOSTNAME", serai_container.ip());
|
||||||
|
let message_queue_container = outer_ops.handle(&handles.message_queue);
|
||||||
|
composition.modify_env("MESSAGE_QUEUE_RPC", message_queue_container.ip());
|
||||||
|
|
||||||
|
format!("container:{}", serai_container.name())
|
||||||
|
};
|
||||||
|
let mut test = DockerTest::new().with_network(dockertest::Network::External(network));
|
||||||
|
test.provide_container(composition);
|
||||||
|
|
||||||
|
drop(context_lock);
|
||||||
|
test.run_async(spawn_coordinator_or_run_test).await;
|
||||||
|
} else {
|
||||||
|
let outer_ops = outer_ops.lock().await.take().unwrap();
|
||||||
|
|
||||||
|
// Wait for the Serai node to boot, and for the Tendermint chain to get past the first block
|
||||||
|
// TODO: Replace this with a Coordinator RPC we can query
|
||||||
|
tokio::time::sleep(Duration::from_secs(60)).await;
|
||||||
|
|
||||||
|
// Connect to the Message Queues as the processor
|
||||||
|
let mut processors: Vec<Processor> = vec![];
|
||||||
|
for (i, (handles, key)) in coordinators.iter().enumerate() {
|
||||||
|
processors.push(
|
||||||
|
Processor::new(
|
||||||
|
i.try_into().unwrap(),
|
||||||
|
NetworkId::Bitcoin,
|
||||||
|
&outer_ops,
|
||||||
|
handles.clone(),
|
||||||
|
*key,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_body.body(processors).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test.run_async(spawn_coordinator_or_run_test).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Don't use a pessimistic sleep
|
// TODO: Don't use a pessimistic sleep
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::{
|
use std::{
|
||||||
sync::Mutex,
|
|
||||||
time::Duration,
|
time::Duration,
|
||||||
collections::{HashSet, HashMap},
|
collections::{HashSet, HashMap},
|
||||||
};
|
};
|
||||||
|
@ -169,186 +168,161 @@ pub async fn sign(
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn sign_test() {
|
async fn sign_test() {
|
||||||
let _one_at_a_time = ONE_AT_A_TIME.get_or_init(|| Mutex::new(())).lock();
|
new_test(|mut processors: Vec<Processor>| async move {
|
||||||
let (processors, test) = new_test();
|
let (participant_is, substrate_key, _) = key_gen::<Secp256k1>(&mut processors).await;
|
||||||
|
|
||||||
test
|
// 'Send' external coins into Serai
|
||||||
.run_async(|ops| async move {
|
let serai = processors[0].serai().await;
|
||||||
// Wait for the Serai node to boot, and for the Tendermint chain to get past the first block
|
let (serai_pair, serai_addr) = {
|
||||||
// TODO: Replace this with a Coordinator RPC
|
let mut name = [0; 4];
|
||||||
tokio::time::sleep(Duration::from_secs(150)).await;
|
OsRng.fill_bytes(&mut name);
|
||||||
|
let pair = insecure_pair_from_name(&hex::encode(name));
|
||||||
|
let address = SeraiAddress::from(pair.public());
|
||||||
|
|
||||||
// Sleep even longer if in the CI due to it being slower than commodity hardware
|
// Fund the new account to pay for fees
|
||||||
if std::env::var("GITHUB_CI") == Ok("true".to_string()) {
|
let balance = Balance { coin: Coin::Serai, amount: Amount(1_000_000_000) };
|
||||||
tokio::time::sleep(Duration::from_secs(120)).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect to the Message Queues as the processor
|
|
||||||
let mut new_processors: Vec<Processor> = vec![];
|
|
||||||
for (i, (handles, key)) in processors.into_iter().enumerate() {
|
|
||||||
new_processors.push(
|
|
||||||
Processor::new(i.try_into().unwrap(), NetworkId::Bitcoin, &ops, handles, key).await,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut processors = new_processors;
|
|
||||||
|
|
||||||
let (participant_is, substrate_key, _) = key_gen::<Secp256k1>(&mut processors).await;
|
|
||||||
|
|
||||||
// 'Send' external coins into Serai
|
|
||||||
let serai = processors[0].serai().await;
|
|
||||||
let (serai_pair, serai_addr) = {
|
|
||||||
let mut name = [0; 4];
|
|
||||||
OsRng.fill_bytes(&mut name);
|
|
||||||
let pair = insecure_pair_from_name(&hex::encode(name));
|
|
||||||
let address = SeraiAddress::from(pair.public());
|
|
||||||
|
|
||||||
// Fund the new account to pay for fees
|
|
||||||
let balance = Balance { coin: Coin::Serai, amount: Amount(1_000_000_000) };
|
|
||||||
serai
|
|
||||||
.publish(&serai.sign(
|
|
||||||
&insecure_pair_from_name("Ferdie"),
|
|
||||||
SeraiCoins::transfer(address, balance),
|
|
||||||
0,
|
|
||||||
Default::default(),
|
|
||||||
))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
(pair, address)
|
|
||||||
};
|
|
||||||
|
|
||||||
#[allow(clippy::inconsistent_digit_grouping)]
|
|
||||||
let amount = Amount(1_000_000_00);
|
|
||||||
let balance = Balance { coin: Coin::Bitcoin, amount };
|
|
||||||
|
|
||||||
let coin_block = BlockHash([0x33; 32]);
|
|
||||||
let block_included_in = batch(
|
|
||||||
&mut processors,
|
|
||||||
&participant_is,
|
|
||||||
Session(0),
|
|
||||||
&substrate_key,
|
|
||||||
Batch {
|
|
||||||
network: NetworkId::Bitcoin,
|
|
||||||
id: 0,
|
|
||||||
block: coin_block,
|
|
||||||
instructions: vec![InInstructionWithBalance {
|
|
||||||
instruction: InInstruction::Transfer(serai_addr),
|
|
||||||
balance,
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
{
|
|
||||||
let block_included_in_hash =
|
|
||||||
serai.finalized_block_by_number(block_included_in).await.unwrap().unwrap().hash();
|
|
||||||
|
|
||||||
let serai = serai.as_of(block_included_in_hash);
|
|
||||||
let serai = serai.coins();
|
|
||||||
assert_eq!(
|
|
||||||
serai.coin_balance(Coin::Serai, serai_addr).await.unwrap(),
|
|
||||||
Amount(1_000_000_000)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify the mint occurred as expected
|
|
||||||
assert_eq!(
|
|
||||||
serai.mint_events().await.unwrap(),
|
|
||||||
vec![CoinsEvent::Mint { to: serai_addr, balance }]
|
|
||||||
);
|
|
||||||
assert_eq!(serai.coin_supply(Coin::Bitcoin).await.unwrap(), amount);
|
|
||||||
assert_eq!(serai.coin_balance(Coin::Bitcoin, serai_addr).await.unwrap(), amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger a burn
|
|
||||||
let out_instruction = OutInstructionWithBalance {
|
|
||||||
balance,
|
|
||||||
instruction: OutInstruction {
|
|
||||||
address: ExternalAddress::new(b"external".to_vec()).unwrap(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
serai
|
serai
|
||||||
.publish(&serai.sign(
|
.publish(&serai.sign(
|
||||||
&serai_pair,
|
&insecure_pair_from_name("Ferdie"),
|
||||||
SeraiCoins::burn_with_instruction(out_instruction.clone()),
|
SeraiCoins::transfer(address, balance),
|
||||||
0,
|
0,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
))
|
))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// TODO: We *really* need a helper for this pattern
|
(pair, address)
|
||||||
let mut last_serai_block = block_included_in;
|
};
|
||||||
'outer: for _ in 0 .. 20 {
|
|
||||||
tokio::time::sleep(Duration::from_secs(6)).await;
|
|
||||||
if std::env::var("GITHUB_CI") == Ok("true".to_string()) {
|
|
||||||
tokio::time::sleep(Duration::from_secs(6)).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
while last_serai_block <= serai.latest_finalized_block().await.unwrap().number() {
|
#[allow(clippy::inconsistent_digit_grouping)]
|
||||||
let burn_events = serai
|
let amount = Amount(1_000_000_00);
|
||||||
.as_of(serai.finalized_block_by_number(last_serai_block).await.unwrap().unwrap().hash())
|
let balance = Balance { coin: Coin::Bitcoin, amount };
|
||||||
.coins()
|
|
||||||
.burn_with_instruction_events()
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if !burn_events.is_empty() {
|
let coin_block = BlockHash([0x33; 32]);
|
||||||
assert_eq!(burn_events.len(), 1);
|
let block_included_in = batch(
|
||||||
assert_eq!(
|
&mut processors,
|
||||||
burn_events[0],
|
&participant_is,
|
||||||
CoinsEvent::BurnWithInstruction {
|
Session(0),
|
||||||
from: serai_addr,
|
&substrate_key,
|
||||||
instruction: out_instruction.clone()
|
Batch {
|
||||||
}
|
network: NetworkId::Bitcoin,
|
||||||
);
|
id: 0,
|
||||||
break 'outer;
|
block: coin_block,
|
||||||
}
|
instructions: vec![InInstructionWithBalance {
|
||||||
last_serai_block += 1;
|
instruction: InInstruction::Transfer(serai_addr),
|
||||||
}
|
balance,
|
||||||
}
|
}],
|
||||||
|
},
|
||||||
let last_serai_block =
|
)
|
||||||
serai.finalized_block_by_number(last_serai_block).await.unwrap().unwrap();
|
|
||||||
let last_serai_block_hash = last_serai_block.hash();
|
|
||||||
let serai = serai.as_of(last_serai_block_hash);
|
|
||||||
let serai = serai.coins();
|
|
||||||
assert_eq!(serai.coin_supply(Coin::Bitcoin).await.unwrap(), Amount(0));
|
|
||||||
assert_eq!(serai.coin_balance(Coin::Bitcoin, serai_addr).await.unwrap(), Amount(0));
|
|
||||||
|
|
||||||
let mut plan_id = [0; 32];
|
|
||||||
OsRng.fill_bytes(&mut plan_id);
|
|
||||||
let plan_id = plan_id;
|
|
||||||
|
|
||||||
// We should now get a SubstrateBlock
|
|
||||||
for processor in &mut processors {
|
|
||||||
assert_eq!(
|
|
||||||
processor.recv_message().await,
|
|
||||||
messages::CoordinatorMessage::Substrate(
|
|
||||||
messages::substrate::CoordinatorMessage::SubstrateBlock {
|
|
||||||
context: SubstrateContext {
|
|
||||||
serai_time: last_serai_block.time().unwrap() / 1000,
|
|
||||||
network_latest_finalized_block: coin_block,
|
|
||||||
},
|
|
||||||
block: last_serai_block.number(),
|
|
||||||
burns: vec![out_instruction.clone()],
|
|
||||||
batches: vec![],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Send the ACK, claiming there's a plan to sign
|
|
||||||
processor
|
|
||||||
.send_message(messages::ProcessorMessage::Coordinator(
|
|
||||||
messages::coordinator::ProcessorMessage::SubstrateBlockAck {
|
|
||||||
block: last_serai_block.number(),
|
|
||||||
plans: vec![PlanMeta { session: Session(0), id: plan_id }],
|
|
||||||
},
|
|
||||||
))
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
sign(&mut processors, &participant_is, Session(0), plan_id).await;
|
|
||||||
})
|
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
{
|
||||||
|
let block_included_in_hash =
|
||||||
|
serai.finalized_block_by_number(block_included_in).await.unwrap().unwrap().hash();
|
||||||
|
|
||||||
|
let serai = serai.as_of(block_included_in_hash);
|
||||||
|
let serai = serai.coins();
|
||||||
|
assert_eq!(serai.coin_balance(Coin::Serai, serai_addr).await.unwrap(), Amount(1_000_000_000));
|
||||||
|
|
||||||
|
// Verify the mint occurred as expected
|
||||||
|
assert_eq!(
|
||||||
|
serai.mint_events().await.unwrap(),
|
||||||
|
vec![CoinsEvent::Mint { to: serai_addr, balance }]
|
||||||
|
);
|
||||||
|
assert_eq!(serai.coin_supply(Coin::Bitcoin).await.unwrap(), amount);
|
||||||
|
assert_eq!(serai.coin_balance(Coin::Bitcoin, serai_addr).await.unwrap(), amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger a burn
|
||||||
|
let out_instruction = OutInstructionWithBalance {
|
||||||
|
balance,
|
||||||
|
instruction: OutInstruction {
|
||||||
|
address: ExternalAddress::new(b"external".to_vec()).unwrap(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
serai
|
||||||
|
.publish(&serai.sign(
|
||||||
|
&serai_pair,
|
||||||
|
SeraiCoins::burn_with_instruction(out_instruction.clone()),
|
||||||
|
0,
|
||||||
|
Default::default(),
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// TODO: We *really* need a helper for this pattern
|
||||||
|
let mut last_serai_block = block_included_in;
|
||||||
|
'outer: for _ in 0 .. 20 {
|
||||||
|
tokio::time::sleep(Duration::from_secs(6)).await;
|
||||||
|
if std::env::var("GITHUB_CI") == Ok("true".to_string()) {
|
||||||
|
tokio::time::sleep(Duration::from_secs(6)).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
while last_serai_block <= serai.latest_finalized_block().await.unwrap().number() {
|
||||||
|
let burn_events = serai
|
||||||
|
.as_of(serai.finalized_block_by_number(last_serai_block).await.unwrap().unwrap().hash())
|
||||||
|
.coins()
|
||||||
|
.burn_with_instruction_events()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if !burn_events.is_empty() {
|
||||||
|
assert_eq!(burn_events.len(), 1);
|
||||||
|
assert_eq!(
|
||||||
|
burn_events[0],
|
||||||
|
CoinsEvent::BurnWithInstruction {
|
||||||
|
from: serai_addr,
|
||||||
|
instruction: out_instruction.clone()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
last_serai_block += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let last_serai_block =
|
||||||
|
serai.finalized_block_by_number(last_serai_block).await.unwrap().unwrap();
|
||||||
|
let last_serai_block_hash = last_serai_block.hash();
|
||||||
|
let serai = serai.as_of(last_serai_block_hash);
|
||||||
|
let serai = serai.coins();
|
||||||
|
assert_eq!(serai.coin_supply(Coin::Bitcoin).await.unwrap(), Amount(0));
|
||||||
|
assert_eq!(serai.coin_balance(Coin::Bitcoin, serai_addr).await.unwrap(), Amount(0));
|
||||||
|
|
||||||
|
let mut plan_id = [0; 32];
|
||||||
|
OsRng.fill_bytes(&mut plan_id);
|
||||||
|
let plan_id = plan_id;
|
||||||
|
|
||||||
|
// We should now get a SubstrateBlock
|
||||||
|
for processor in &mut processors {
|
||||||
|
assert_eq!(
|
||||||
|
processor.recv_message().await,
|
||||||
|
messages::CoordinatorMessage::Substrate(
|
||||||
|
messages::substrate::CoordinatorMessage::SubstrateBlock {
|
||||||
|
context: SubstrateContext {
|
||||||
|
serai_time: last_serai_block.time().unwrap() / 1000,
|
||||||
|
network_latest_finalized_block: coin_block,
|
||||||
|
},
|
||||||
|
block: last_serai_block.number(),
|
||||||
|
burns: vec![out_instruction.clone()],
|
||||||
|
batches: vec![],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Send the ACK, claiming there's a plan to sign
|
||||||
|
processor
|
||||||
|
.send_message(messages::ProcessorMessage::Coordinator(
|
||||||
|
messages::coordinator::ProcessorMessage::SubstrateBlockAck {
|
||||||
|
block: last_serai_block.number(),
|
||||||
|
plans: vec![PlanMeta { session: Session(0), id: plan_id }],
|
||||||
|
},
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
sign(&mut processors, &participant_is, Session(0), plan_id).await;
|
||||||
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,21 @@ use std::{
|
||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn fresh_logs_folder(first: bool, label: &str) -> String {
|
||||||
|
let logs_path = [std::env::current_dir().unwrap().to_str().unwrap(), ".test-logs", label]
|
||||||
|
.iter()
|
||||||
|
.collect::<std::path::PathBuf>();
|
||||||
|
if first {
|
||||||
|
let _ = fs::remove_dir_all(&logs_path);
|
||||||
|
fs::create_dir_all(&logs_path).expect("couldn't create logs directory");
|
||||||
|
assert!(
|
||||||
|
fs::read_dir(&logs_path).expect("couldn't read the logs folder").next().is_none(),
|
||||||
|
"logs folder wasn't empty, despite removing it at the start of the run",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
logs_path.to_str().unwrap().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
static BUILT: OnceLock<Mutex<HashMap<String, bool>>> = OnceLock::new();
|
static BUILT: OnceLock<Mutex<HashMap<String, bool>>> = OnceLock::new();
|
||||||
pub fn build(name: String) {
|
pub fn build(name: String) {
|
||||||
let built = BUILT.get_or_init(|| Mutex::new(HashMap::new()));
|
let built = BUILT.get_or_init(|| Mutex::new(HashMap::new()));
|
||||||
|
|
|
@ -19,6 +19,9 @@ workspace = true
|
||||||
[dependencies]
|
[dependencies]
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
|
||||||
|
async-trait = "0.1"
|
||||||
|
async-recursion = "1"
|
||||||
|
|
||||||
zeroize = { version = "1", default-features = false }
|
zeroize = { version = "1", default-features = false }
|
||||||
rand_core = { version = "0.6", default-features = false }
|
rand_core = { version = "0.6", default-features = false }
|
||||||
|
|
||||||
|
@ -38,6 +41,7 @@ serai-client = { path = "../../substrate/client", features = ["serai"] }
|
||||||
tokio = { version = "1", features = ["time"] }
|
tokio = { version = "1", features = ["time"] }
|
||||||
|
|
||||||
dockertest = "0.4"
|
dockertest = "0.4"
|
||||||
|
serai-docker-tests = { path = "../docker" }
|
||||||
serai-message-queue-tests = { path = "../message-queue" }
|
serai-message-queue-tests = { path = "../message-queue" }
|
||||||
serai-processor-tests = { path = "../processor" }
|
serai-processor-tests = { path = "../processor" }
|
||||||
serai-coordinator-tests = { path = "../coordinator" }
|
serai-coordinator-tests = { path = "../coordinator" }
|
||||||
|
|
|
@ -1,24 +1,14 @@
|
||||||
use std::{
|
use std::time::Duration;
|
||||||
sync::{OnceLock, Mutex},
|
|
||||||
time::Duration,
|
|
||||||
fs,
|
|
||||||
};
|
|
||||||
|
|
||||||
use serai_client::{primitives::NetworkId, Serai};
|
use serai_client::Serai;
|
||||||
|
|
||||||
use dockertest::{
|
use dockertest::DockerOperations;
|
||||||
LogAction, LogPolicy, LogSource, LogOptions, StartPolicy, TestBodySpecification, DockerOperations,
|
|
||||||
};
|
use serai_processor_tests::{RPC_USER, RPC_PASS};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
static UNIQUE_ID: OnceLock<Mutex<u16>> = OnceLock::new();
|
|
||||||
|
|
||||||
use serai_processor_tests::{RPC_USER, RPC_PASS, network_instance, processor_instance};
|
|
||||||
use serai_message_queue_tests::instance as message_queue_instance;
|
|
||||||
use serai_coordinator_tests::{coordinator_instance, serai_composition};
|
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Handles {
|
pub struct Handles {
|
||||||
|
@ -27,108 +17,9 @@ pub struct Handles {
|
||||||
monero: (String, u32),
|
monero: (String, u32),
|
||||||
monero_processor: String,
|
monero_processor: String,
|
||||||
message_queue: String,
|
message_queue: String,
|
||||||
coordinator: String,
|
|
||||||
serai: String,
|
serai: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn full_stack(name: &str) -> (Handles, Vec<TestBodySpecification>) {
|
|
||||||
let (coord_key, message_queue_keys, message_queue_composition) = message_queue_instance();
|
|
||||||
|
|
||||||
let (bitcoin_composition, bitcoin_port) = network_instance(NetworkId::Bitcoin);
|
|
||||||
let bitcoin_processor_composition =
|
|
||||||
processor_instance(NetworkId::Bitcoin, bitcoin_port, message_queue_keys[&NetworkId::Bitcoin]);
|
|
||||||
|
|
||||||
let (monero_composition, monero_port) = network_instance(NetworkId::Monero);
|
|
||||||
let monero_processor_composition =
|
|
||||||
processor_instance(NetworkId::Monero, monero_port, message_queue_keys[&NetworkId::Monero]);
|
|
||||||
|
|
||||||
let coordinator_composition = coordinator_instance(name, coord_key);
|
|
||||||
let serai_composition = serai_composition(name);
|
|
||||||
|
|
||||||
// Give every item in this stack a unique ID
|
|
||||||
// Uses a Mutex as we can't generate a 8-byte random ID without hitting hostname length limits
|
|
||||||
let (first, unique_id) = {
|
|
||||||
let unique_id_mutex = UNIQUE_ID.get_or_init(|| Mutex::new(0));
|
|
||||||
let mut unique_id_lock = unique_id_mutex.lock().unwrap();
|
|
||||||
let first = *unique_id_lock == 0;
|
|
||||||
let unique_id = *unique_id_lock;
|
|
||||||
*unique_id_lock += 1;
|
|
||||||
(first, unique_id)
|
|
||||||
};
|
|
||||||
|
|
||||||
let logs_path = [std::env::current_dir().unwrap().to_str().unwrap(), ".test-logs", "full-stack"]
|
|
||||||
.iter()
|
|
||||||
.collect::<std::path::PathBuf>();
|
|
||||||
if first {
|
|
||||||
let _ = fs::remove_dir_all(&logs_path);
|
|
||||||
fs::create_dir_all(&logs_path).expect("couldn't create logs directory");
|
|
||||||
assert!(
|
|
||||||
fs::read_dir(&logs_path).expect("couldn't read the logs folder").next().is_none(),
|
|
||||||
"logs folder wasn't empty, despite removing it at the start of the run",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let logs_path = logs_path.to_str().unwrap().to_string();
|
|
||||||
|
|
||||||
let mut compositions = vec![];
|
|
||||||
let mut handles = vec![];
|
|
||||||
for (name, composition) in [
|
|
||||||
("message_queue", message_queue_composition),
|
|
||||||
("bitcoin", bitcoin_composition),
|
|
||||||
("bitcoin_processor", bitcoin_processor_composition),
|
|
||||||
("monero", monero_composition),
|
|
||||||
("monero_processor", monero_processor_composition),
|
|
||||||
("coordinator", coordinator_composition),
|
|
||||||
("serai", serai_composition),
|
|
||||||
] {
|
|
||||||
let handle = format!("full_stack-{name}-{unique_id}");
|
|
||||||
compositions.push(
|
|
||||||
composition.set_start_policy(StartPolicy::Strict).set_handle(handle.clone()).set_log_options(
|
|
||||||
Some(LogOptions {
|
|
||||||
action: if std::env::var("GITHUB_CI") == Ok("true".to_string()) {
|
|
||||||
LogAction::Forward
|
|
||||||
} else {
|
|
||||||
LogAction::ForwardToFile { path: logs_path.clone() }
|
|
||||||
},
|
|
||||||
policy: LogPolicy::Always,
|
|
||||||
source: LogSource::Both,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
handles.push(handle);
|
|
||||||
}
|
|
||||||
let handles = Handles {
|
|
||||||
message_queue: handles[0].clone(),
|
|
||||||
bitcoin: (handles[1].clone(), bitcoin_port),
|
|
||||||
bitcoin_processor: handles[2].clone(),
|
|
||||||
monero: (handles[3].clone(), monero_port),
|
|
||||||
monero_processor: handles[4].clone(),
|
|
||||||
coordinator: handles[5].clone(),
|
|
||||||
serai: handles[6].clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
let bitcoin_processor_composition = compositions.get_mut(2).unwrap();
|
|
||||||
bitcoin_processor_composition
|
|
||||||
.inject_container_name(handles.message_queue.clone(), "MESSAGE_QUEUE_RPC");
|
|
||||||
bitcoin_processor_composition
|
|
||||||
.inject_container_name(handles.bitcoin.0.clone(), "NETWORK_RPC_HOSTNAME");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let monero_processor_composition = compositions.get_mut(4).unwrap();
|
|
||||||
monero_processor_composition
|
|
||||||
.inject_container_name(handles.message_queue.clone(), "MESSAGE_QUEUE_RPC");
|
|
||||||
monero_processor_composition
|
|
||||||
.inject_container_name(handles.monero.0.clone(), "NETWORK_RPC_HOSTNAME");
|
|
||||||
}
|
|
||||||
|
|
||||||
let coordinator_composition = compositions.get_mut(5).unwrap();
|
|
||||||
coordinator_composition.inject_container_name(handles.message_queue.clone(), "MESSAGE_QUEUE_RPC");
|
|
||||||
coordinator_composition.inject_container_name(handles.serai.clone(), "SERAI_HOSTNAME");
|
|
||||||
|
|
||||||
(handles, compositions)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Handles {
|
impl Handles {
|
||||||
pub async fn serai(&self, ops: &DockerOperations) -> Serai {
|
pub async fn serai(&self, ops: &DockerOperations) -> Serai {
|
||||||
let serai_rpc = ops.handle(&self.serai).host_port(9944).unwrap();
|
let serai_rpc = ops.handle(&self.serai).host_port(9944).unwrap();
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,19 @@
|
||||||
use std::sync::OnceLock;
|
use core::future::Future;
|
||||||
|
use std::{sync::OnceLock, collections::HashMap};
|
||||||
|
|
||||||
use dockertest::DockerTest;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
use serai_client::primitives::NetworkId;
|
||||||
|
|
||||||
|
use dockertest::{
|
||||||
|
LogAction, LogPolicy, LogSource, LogOptions, StartPolicy, TestBodySpecification,
|
||||||
|
DockerOperations, DockerTest,
|
||||||
|
};
|
||||||
|
|
||||||
|
use serai_docker_tests::fresh_logs_folder;
|
||||||
|
use serai_processor_tests::{network_instance, processor_instance};
|
||||||
|
use serai_message_queue_tests::instance as message_queue_instance;
|
||||||
|
use serai_coordinator_tests::{coordinator_instance, serai_composition};
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
|
@ -9,13 +22,29 @@ mod mint_and_burn;
|
||||||
pub(crate) const VALIDATORS: usize = 4;
|
pub(crate) const VALIDATORS: usize = 4;
|
||||||
// pub(crate) const THRESHOLD: usize = ((VALIDATORS * 2) / 3) + 1;
|
// pub(crate) const THRESHOLD: usize = ((VALIDATORS * 2) / 3) + 1;
|
||||||
|
|
||||||
pub(crate) static ONE_AT_A_TIME: OnceLock<Mutex<()>> = OnceLock::new();
|
static UNIQUE_ID: OnceLock<Mutex<u16>> = OnceLock::new();
|
||||||
|
|
||||||
pub(crate) fn new_test() -> (Vec<Handles>, DockerTest) {
|
#[async_trait::async_trait]
|
||||||
let mut validators = vec![];
|
pub(crate) trait TestBody: 'static + Send + Sync {
|
||||||
|
async fn body(&self, ops: DockerOperations, handles: Vec<Handles>);
|
||||||
|
}
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl<F: Send + Future, TB: 'static + Send + Sync + Fn(DockerOperations, Vec<Handles>) -> F> TestBody
|
||||||
|
for TB
|
||||||
|
{
|
||||||
|
async fn body(&self, ops: DockerOperations, handles: Vec<Handles>) {
|
||||||
|
(self)(ops, handles).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn new_test(test_body: impl TestBody) {
|
||||||
|
let mut unique_id_lock = UNIQUE_ID.get_or_init(|| Mutex::new(0)).lock().await;
|
||||||
|
|
||||||
|
let mut all_handles = vec![];
|
||||||
let mut test = DockerTest::new().with_network(dockertest::Network::Isolated);
|
let mut test = DockerTest::new().with_network(dockertest::Network::Isolated);
|
||||||
|
let mut coordinator_compositions = vec![];
|
||||||
for i in 0 .. VALIDATORS {
|
for i in 0 .. VALIDATORS {
|
||||||
let (handles, compositions) = full_stack(match i {
|
let name = match i {
|
||||||
0 => "Alice",
|
0 => "Alice",
|
||||||
1 => "Bob",
|
1 => "Bob",
|
||||||
2 => "Charlie",
|
2 => "Charlie",
|
||||||
|
@ -23,11 +52,164 @@ pub(crate) fn new_test() -> (Vec<Handles>, DockerTest) {
|
||||||
4 => "Eve",
|
4 => "Eve",
|
||||||
5 => "Ferdie",
|
5 => "Ferdie",
|
||||||
_ => panic!("needed a 7th name for a serai node"),
|
_ => panic!("needed a 7th name for a serai node"),
|
||||||
});
|
};
|
||||||
validators.push(handles);
|
|
||||||
for composition in compositions {
|
let (coord_key, message_queue_keys, message_queue_composition) = message_queue_instance();
|
||||||
|
|
||||||
|
let (bitcoin_composition, bitcoin_port) = network_instance(NetworkId::Bitcoin);
|
||||||
|
let bitcoin_processor_composition =
|
||||||
|
processor_instance(NetworkId::Bitcoin, bitcoin_port, message_queue_keys[&NetworkId::Bitcoin]);
|
||||||
|
|
||||||
|
let (monero_composition, monero_port) = network_instance(NetworkId::Monero);
|
||||||
|
let monero_processor_composition =
|
||||||
|
processor_instance(NetworkId::Monero, monero_port, message_queue_keys[&NetworkId::Monero]);
|
||||||
|
|
||||||
|
let coordinator_composition = coordinator_instance(name, coord_key);
|
||||||
|
let serai_composition = serai_composition(name);
|
||||||
|
|
||||||
|
// Give every item in this stack a unique ID
|
||||||
|
// Uses a Mutex as we can't generate a 8-byte random ID without hitting hostname length limits
|
||||||
|
let (first, unique_id) = {
|
||||||
|
let first = *unique_id_lock == 0;
|
||||||
|
let unique_id = *unique_id_lock;
|
||||||
|
*unique_id_lock += 1;
|
||||||
|
(first, unique_id)
|
||||||
|
};
|
||||||
|
|
||||||
|
let logs_path = fresh_logs_folder(first, "full-stack");
|
||||||
|
|
||||||
|
let mut compositions = HashMap::new();
|
||||||
|
let mut handles = HashMap::new();
|
||||||
|
for (name, composition) in [
|
||||||
|
("message_queue", message_queue_composition),
|
||||||
|
("bitcoin", bitcoin_composition),
|
||||||
|
("bitcoin_processor", bitcoin_processor_composition),
|
||||||
|
("monero", monero_composition),
|
||||||
|
("monero_processor", monero_processor_composition),
|
||||||
|
("coordinator", coordinator_composition),
|
||||||
|
("serai", serai_composition),
|
||||||
|
] {
|
||||||
|
let handle = format!("full_stack-{name}-{unique_id}");
|
||||||
|
compositions.insert(
|
||||||
|
name,
|
||||||
|
composition
|
||||||
|
.set_start_policy(StartPolicy::Strict)
|
||||||
|
.set_handle(handle.clone())
|
||||||
|
.set_log_options(Some(LogOptions {
|
||||||
|
action: if std::env::var("GITHUB_CI") == Ok("true".to_string()) {
|
||||||
|
LogAction::Forward
|
||||||
|
} else {
|
||||||
|
LogAction::ForwardToFile { path: logs_path.clone() }
|
||||||
|
},
|
||||||
|
policy: LogPolicy::Always,
|
||||||
|
source: LogSource::Both,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
handles.insert(name, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
let handles = Handles {
|
||||||
|
message_queue: handles.remove("message_queue").unwrap(),
|
||||||
|
bitcoin: (handles.remove("bitcoin").unwrap(), bitcoin_port),
|
||||||
|
bitcoin_processor: handles.remove("bitcoin_processor").unwrap(),
|
||||||
|
monero: (handles.remove("monero").unwrap(), monero_port),
|
||||||
|
monero_processor: handles.remove("monero_processor").unwrap(),
|
||||||
|
serai: handles.remove("serai").unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let bitcoin_processor_composition = compositions.get_mut("bitcoin_processor").unwrap();
|
||||||
|
bitcoin_processor_composition
|
||||||
|
.inject_container_name(handles.message_queue.clone(), "MESSAGE_QUEUE_RPC");
|
||||||
|
bitcoin_processor_composition
|
||||||
|
.inject_container_name(handles.bitcoin.0.clone(), "NETWORK_RPC_HOSTNAME");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let monero_processor_composition = compositions.get_mut("monero_processor").unwrap();
|
||||||
|
monero_processor_composition
|
||||||
|
.inject_container_name(handles.message_queue.clone(), "MESSAGE_QUEUE_RPC");
|
||||||
|
monero_processor_composition
|
||||||
|
.inject_container_name(handles.monero.0.clone(), "NETWORK_RPC_HOSTNAME");
|
||||||
|
}
|
||||||
|
|
||||||
|
coordinator_compositions.push(compositions.remove("coordinator").unwrap());
|
||||||
|
|
||||||
|
all_handles.push(handles);
|
||||||
|
for (_, composition) in compositions {
|
||||||
test.provide_container(composition);
|
test.provide_container(composition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(validators, test)
|
|
||||||
|
struct Context {
|
||||||
|
pending_coordinator_compositions: Mutex<Vec<TestBodySpecification>>,
|
||||||
|
handles: Vec<Handles>,
|
||||||
|
test_body: Box<dyn TestBody>,
|
||||||
|
}
|
||||||
|
static CONTEXT: OnceLock<Mutex<Option<Context>>> = OnceLock::new();
|
||||||
|
*CONTEXT.get_or_init(|| Mutex::new(None)).lock().await = Some(Context {
|
||||||
|
pending_coordinator_compositions: Mutex::new(coordinator_compositions),
|
||||||
|
handles: all_handles,
|
||||||
|
test_body: Box::new(test_body),
|
||||||
|
});
|
||||||
|
|
||||||
|
// The DockerOperations from the first invocation, containing the Message Queue servers and the
|
||||||
|
// Serai nodes.
|
||||||
|
static OUTER_OPS: OnceLock<Mutex<Option<DockerOperations>>> = OnceLock::new();
|
||||||
|
|
||||||
|
// Reset OUTER_OPS
|
||||||
|
*OUTER_OPS.get_or_init(|| Mutex::new(None)).lock().await = None;
|
||||||
|
|
||||||
|
// Spawns a coordinator, if one has yet to be spawned, or else runs the test.
|
||||||
|
#[async_recursion::async_recursion]
|
||||||
|
async fn spawn_coordinator_or_run_test(inner_ops: DockerOperations) {
|
||||||
|
// If the outer operations have yet to be set, these *are* the outer operations
|
||||||
|
let outer_ops = OUTER_OPS.get().unwrap();
|
||||||
|
if outer_ops.lock().await.is_none() {
|
||||||
|
*outer_ops.lock().await = Some(inner_ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
let context_lock = CONTEXT.get().unwrap().lock().await;
|
||||||
|
let Context { pending_coordinator_compositions, handles, test_body } =
|
||||||
|
context_lock.as_ref().unwrap();
|
||||||
|
|
||||||
|
// Check if there is a coordinator left
|
||||||
|
let maybe_coordinator = {
|
||||||
|
let mut remaining = pending_coordinator_compositions.lock().await;
|
||||||
|
let maybe_coordinator = if !remaining.is_empty() {
|
||||||
|
let handles = handles[handles.len() - remaining.len()].clone();
|
||||||
|
let composition = remaining.remove(0);
|
||||||
|
Some((composition, handles))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
drop(remaining);
|
||||||
|
maybe_coordinator
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some((mut composition, handles)) = maybe_coordinator {
|
||||||
|
let network = {
|
||||||
|
let outer_ops = outer_ops.lock().await;
|
||||||
|
let outer_ops = outer_ops.as_ref().unwrap();
|
||||||
|
// Spawn it by building another DockerTest which recursively calls this function
|
||||||
|
// TODO: Spawn this outside of DockerTest so we can remove the recursion
|
||||||
|
let serai_container = outer_ops.handle(&handles.serai);
|
||||||
|
composition.modify_env("SERAI_HOSTNAME", serai_container.ip());
|
||||||
|
let message_queue_container = outer_ops.handle(&handles.message_queue);
|
||||||
|
composition.modify_env("MESSAGE_QUEUE_RPC", message_queue_container.ip());
|
||||||
|
|
||||||
|
format!("container:{}", serai_container.name())
|
||||||
|
};
|
||||||
|
let mut test = DockerTest::new().with_network(dockertest::Network::External(network));
|
||||||
|
test.provide_container(composition);
|
||||||
|
|
||||||
|
drop(context_lock);
|
||||||
|
test.run_async(spawn_coordinator_or_run_test).await;
|
||||||
|
} else {
|
||||||
|
let outer_ops = outer_ops.lock().await.take().unwrap();
|
||||||
|
test_body.body(outer_ops, handles.clone()).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test.run_async(spawn_coordinator_or_run_test).await;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue