33 Commits

Author SHA1 Message Date
Luke Parker
2ba6d77ee7 Reduce target peers a bit 2024-04-23 12:59:34 -04:00
Luke Parker
67a0ff825b Correct recv to try_recv when exhausting channel 2024-04-23 12:41:10 -04:00
Luke Parker
6518379981 Correct selection of to-try peers to prevent infinite loops when to-try < target 2024-04-23 12:41:00 -04:00
Luke Parker
0c6ab50e35 Use a constant for the target amount of peer 2024-04-23 12:40:50 -04:00
Luke Parker
f73ce37e18 Use a HashSet for which networks to try peer finding for
Prevents a flood of retries from individually failed attempts within a batch of
peer connection attempts.
2024-04-23 12:40:41 -04:00
Luke Parker
973dcf065e Correct port forward in orchestration 2024-04-23 09:47:11 -04:00
Luke Parker
8f5aaa8492 New coordinator port, genesis 2024-04-23 09:32:44 -04:00
Luke Parker
93ba8d840a Remove cbor 2024-04-23 09:31:33 -04:00
Luke Parker
485e454680 Inline broadcast_raw now that it doesn't have multiple callers 2024-04-23 09:31:17 -04:00
Luke Parker
c3b6abf020 Properly diversify ReqResMessageKind/GossipMessageKind 2024-04-23 09:31:09 -04:00
Luke Parker
f3ccf1cab0 Move keep alive, heartbeat, block to request/response 2024-04-23 09:30:58 -04:00
Luke Parker
0deee0ec6b Line for prior commit 2024-04-21 08:55:50 -04:00
Luke Parker
6b428948d4 Comment the insanely aggressive timeout future trace log 2024-04-21 08:55:32 -04:00
Luke Parker
6986257d4f Add missing continue to prevent dialing a node we're connected to 2024-04-21 08:37:06 -04:00
Luke Parker
a3c37cba21 Replace expect with debug log 2024-04-21 08:03:01 -04:00
Luke Parker
b5f2ff1397 Correct boolean NOT on is_fresh_dial 2024-04-21 07:30:18 -04:00
Luke Parker
c84931c6ae Retry if initial dials fail, not just upon disconnect 2024-04-21 07:26:29 -04:00
Luke Parker
63abf2d022 Restart coordinator peer finding upon disconnections 2024-04-21 07:03:03 -04:00
Luke Parker
a62d2d05ad Correct log which didn't work as intended 2024-04-20 19:55:17 -04:00
Luke Parker
967cc16748 Correct log targets in tendermint-machine 2024-04-20 19:55:06 -04:00
Luke Parker
ab4b8cc2d5 Better logs in tendermint-machine 2024-04-20 18:13:57 -04:00
Luke Parker
387ccbad3a Extend time in sync test 2024-04-18 16:39:16 -04:00
Luke Parker
26cdfdd824 fmt 2024-04-18 16:39:03 -04:00
Luke Parker
68e77384ac Don't broadcast added blocks
Online validators should inherently have them. Offline validators will receive
from the sync protocol.

This does somewhat eliminate the class of nodes who would follow the blockchain
(without validating it), yet that's fine for the performance benefit.
2024-04-18 16:38:52 -04:00
Luke Parker
68da88c1f3 Only reply to heartbeats after a certain distance 2024-04-18 16:38:43 -04:00
Luke Parker
2b481ab71e Ensure we don't reply to stale heartbeats 2024-04-18 16:38:21 -04:00
Luke Parker
05e6d81948 Only have some nodes respond to latent heartbeats
Also only respond if they're more than 2 blocks behind to minimize redundant
sending of blocks.
2024-04-18 16:38:16 -04:00
Luke Parker
e426cd00bd Correct protocol ID -> ID 2024-04-11 23:11:23 -04:00
Luke Parker
09e3881b7d Add worksmarter at the last minute 2024-04-11 16:08:14 -04:00
Luke Parker
10124ac4a8 Add Testnet 2 Config
Starts Tuesday, April 16th, with confirmed keys/boot nodes.
2024-04-11 15:49:32 -04:00
Luke Parker
1987983f88 Add bootnode code prior used in testnet-internal
Also performs the devnet/testnet differentation done since the testnet branch.
2024-04-11 14:37:09 -04:00
Luke Parker
fcad402186 cargo update
Resolves deny error caused by h2.
2024-04-10 06:34:01 -04:00
Boog900
ab4d79628d fix CLSAG verification.
We were not setting c1 to the last calculated c during verification, instead keeping it set to the one provided in the signature.
2024-04-10 05:59:06 -04:00
47 changed files with 998 additions and 1518 deletions

316
Cargo.lock generated
View File

@@ -173,9 +173,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.81"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
[[package]]
name = "approx"
@@ -287,7 +287,7 @@ checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b"
dependencies = [
"event-listener 4.0.3",
"event-listener-strategy",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
]
[[package]]
@@ -298,7 +298,7 @@ checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -322,7 +322,7 @@ dependencies = [
"futures-sink",
"futures-util",
"memchr",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
]
[[package]]
@@ -344,7 +344,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -449,14 +449,14 @@ dependencies = [
"regex",
"rustc-hash",
"shlex",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
name = "bitcoin"
version = "0.31.1"
version = "0.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd00f3c09b5f21fb357abe32d29946eb8bb7a0862bae62c0b5e4a692acbbe73c"
checksum = "6c85783c2fe40083ea54a33aa2f0ba58831d90fcd190f5bdc47e74e84d2a96ae"
dependencies = [
"bech32",
"bitcoin-internals",
@@ -633,7 +633,7 @@ dependencies = [
"hyper 0.14.28",
"hyperlocal",
"log",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"serde",
"serde_derive",
"serde_json",
@@ -677,7 +677,7 @@ dependencies = [
"proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
"syn_derive",
]
@@ -723,9 +723,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.15.4"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "byte-slice-cast"
@@ -964,7 +964,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -1301,14 +1301,14 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
name = "cxx"
version = "1.0.120"
version = "1.0.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff4dc7287237dd438b926a81a1a5605dad33d286870e5eee2db17bf2bcd9e92a"
checksum = "21db378d04296a84d8b7d047c36bb3954f0b46529db725d7e62fb02f9ba53ccc"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -1318,9 +1318,9 @@ dependencies = [
[[package]]
name = "cxx-build"
version = "1.0.120"
version = "1.0.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f47c6c8ad7c1a10d3ef0fe3ff6733f4db0d78f08ef0b13121543163ef327058b"
checksum = "3e5262a7fa3f0bae2a55b767c223ba98032d7c328f5c13fa5cdc980b77fc0658"
dependencies = [
"cc",
"codespan-reporting",
@@ -1328,24 +1328,24 @@ dependencies = [
"proc-macro2",
"quote",
"scratch",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.120"
version = "1.0.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "701a1ac7a697e249cdd8dc026d7a7dafbfd0dbcd8bd24ec55889f2bc13dd6287"
checksum = "be8dcadd2e2fb4a501e1d9e93d6e88e6ea494306d8272069c92d5a9edf8855c0"
[[package]]
name = "cxxbridge-macro"
version = "1.0.120"
version = "1.0.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b404f596046b0bb2d903a9c786b875a126261b52b7c3a64bbb66382c41c771df"
checksum = "ad08a837629ad949b73d032c637653d069e909cffe4ee7870b02301939ce39cc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -1401,9 +1401,9 @@ dependencies = [
[[package]]
name = "der"
version = "0.7.8"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
dependencies = [
"const-oid",
"zeroize",
@@ -1531,7 +1531,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -1718,9 +1718,9 @@ dependencies = [
[[package]]
name = "encoding_rs"
version = "0.8.33"
version = "0.8.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
dependencies = [
"cfg-if",
]
@@ -1764,7 +1764,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -1907,7 +1907,7 @@ dependencies = [
"regex",
"serde",
"serde_json",
"syn 2.0.55",
"syn 2.0.58",
"toml 0.7.8",
"walkdir",
]
@@ -1925,7 +1925,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_json",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -1951,7 +1951,7 @@ dependencies = [
"serde",
"serde_json",
"strum 0.25.0",
"syn 2.0.55",
"syn 2.0.58",
"tempfile",
"thiserror",
"tiny-keccak",
@@ -2008,7 +2008,7 @@ checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e"
dependencies = [
"concurrent-queue",
"parking",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
]
[[package]]
@@ -2018,7 +2018,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
dependencies = [
"event-listener 4.0.3",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
]
[[package]]
@@ -2040,7 +2040,7 @@ dependencies = [
"fs-err",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -2314,7 +2314,7 @@ dependencies = [
"proc-macro-warning",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -2326,7 +2326,7 @@ dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -2336,7 +2336,7 @@ source = "git+https://github.com/serai-dex/substrate#6e3f07bf5c98a6a3ec15f2b1a46
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -2484,7 +2484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
dependencies = [
"futures-core",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
]
[[package]]
@@ -2495,7 +2495,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -2554,7 +2554,7 @@ dependencies = [
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"pin-utils",
"slab",
]
@@ -2616,9 +2616,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.12"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
dependencies = [
"cfg-if",
"libc",
@@ -2696,9 +2696,9 @@ dependencies = [
[[package]]
name = "h2"
version = "0.3.25"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb"
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
dependencies = [
"bytes",
"fnv",
@@ -2875,7 +2875,7 @@ checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
dependencies = [
"bytes",
"http 0.2.12",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
]
[[package]]
@@ -2898,7 +2898,7 @@ dependencies = [
"futures-core",
"http 1.1.0",
"http-body 1.0.0",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
]
[[package]]
@@ -2941,7 +2941,7 @@ dependencies = [
"httparse",
"httpdate",
"itoa",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"socket2 0.4.10",
"tokio",
"tower-service",
@@ -2962,7 +2962,7 @@ dependencies = [
"http-body 1.0.0",
"httparse",
"itoa",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"smallvec",
"tokio",
"want",
@@ -2998,7 +2998,7 @@ dependencies = [
"http 1.1.0",
"http-body 1.0.0",
"hyper 1.2.0",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"socket2 0.5.6",
"tokio",
"tower",
@@ -3822,7 +3822,7 @@ dependencies = [
"proc-macro-warning",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -4075,7 +4075,7 @@ dependencies = [
"macro_magic_core",
"macro_magic_macros",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -4089,7 +4089,7 @@ dependencies = [
"macro_magic_core_macros",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -4100,7 +4100,7 @@ checksum = "d710e1214dffbab3b5dacb21475dde7d6ed84c69ff722b3a47a782668d44fbac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -4111,7 +4111,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a"
dependencies = [
"macro_magic_core",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -4164,9 +4164,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.7.1"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "memfd"
@@ -4518,9 +4518,9 @@ dependencies = [
[[package]]
name = "nalgebra"
version = "0.32.4"
version = "0.32.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4541eb06dce09c0241ebbaab7102f0a01a0c8994afed2e5d0d66775016e25ac2"
checksum = "3ea4908d4f23254adda3daa60ffef0f1ac7b8c3e9a864cf3cc154b251908a2ef"
dependencies = [
"approx",
"matrixmultiply",
@@ -4607,9 +4607,9 @@ dependencies = [
[[package]]
name = "netlink-sys"
version = "0.8.5"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411"
checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307"
dependencies = [
"bytes",
"futures",
@@ -4750,7 +4750,7 @@ dependencies = [
"proc-macro-crate 3.1.0",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -5219,7 +5219,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -5230,9 +5230,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777"
[[package]]
name = "pin-project-lite"
version = "0.2.13"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "pin-utils"
@@ -5271,7 +5271,7 @@ dependencies = [
"cfg-if",
"concurrent-queue",
"hermit-abi",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"rustix",
"tracing",
"windows-sys 0.52.0",
@@ -5359,7 +5359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
dependencies = [
"proc-macro2",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -5443,7 +5443,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -5489,7 +5489,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -5602,7 +5602,7 @@ checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75"
dependencies = [
"bytes",
"futures-io",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"quinn-proto",
"quinn-udp",
"rustc-hash",
@@ -5644,9 +5644,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.35"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
@@ -5790,7 +5790,7 @@ checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -5871,7 +5871,7 @@ dependencies = [
"mime",
"once_cell",
"percent-encoding",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"serde",
"serde_json",
"serde_urlencoded",
@@ -6119,9 +6119,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
version = "1.4.0"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "868e20fada228fefaf6b652e00cc73623d54f8171e7352c18bb281571f2d92da"
checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247"
[[package]]
name = "rustls-webpki"
@@ -6146,9 +6146,9 @@ dependencies = [
[[package]]
name = "rustversion"
version = "1.0.14"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
[[package]]
name = "rw-stream-sink"
@@ -6289,7 +6289,7 @@ dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -7050,7 +7050,7 @@ dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -7112,9 +7112,9 @@ dependencies = [
[[package]]
name = "scale-info"
version = "2.11.1"
version = "2.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "788745a868b0e751750388f4e6546eb921ef714a4317fa6954f7cde114eb2eb7"
checksum = "7c453e59a955f81fb62ee5d596b450383d699f152d350e9d23a0db2adb78e4c0"
dependencies = [
"bitvec",
"cfg-if",
@@ -7126,9 +7126,9 @@ dependencies = [
[[package]]
name = "scale-info-derive"
version = "2.11.1"
version = "2.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dc2f4e8bc344b9fc3d5f74f72c2e55bfc38d28dc2ebc69c194a3df424e4d9ac"
checksum = "18cf6c6447f813ef19eb450e985bcce6705f9ce7660db221b59093d15c79c4b7"
dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro2",
@@ -7263,9 +7263,9 @@ dependencies = [
[[package]]
name = "security-framework"
version = "2.9.2"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
@@ -7276,9 +7276,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
version = "2.9.1"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef"
dependencies = [
"core-foundation-sys",
"libc",
@@ -7487,30 +7487,6 @@ dependencies = [
"chrono",
]
[[package]]
name = "serai-emissions-pallet"
version = "0.1.0"
dependencies = [
"frame-support",
"frame-system",
"pallet-babe",
"parity-scale-codec",
"scale-info",
"serai-coins-pallet",
"serai-dex-pallet",
"serai-emissions-primitives",
"serai-primitives",
"serai-validator-sets-pallet",
"serai-validator-sets-primitives",
"sp-runtime",
"sp-session",
"sp-std",
]
[[package]]
name = "serai-emissions-primitives"
version = "0.1.0"
[[package]]
name = "serai-env"
version = "0.1.0"
@@ -7539,28 +7515,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "serai-genesis-liquidity-pallet"
version = "0.1.0"
dependencies = [
"frame-support",
"frame-system",
"parity-scale-codec",
"scale-info",
"serai-coins-pallet",
"serai-dex-pallet",
"serai-genesis-liquidity-primitives",
"serai-primitives",
"sp-std",
]
[[package]]
name = "serai-genesis-liquidity-primitives"
version = "0.1.0"
dependencies = [
"serai-primitives",
]
[[package]]
name = "serai-in-instructions-pallet"
version = "0.1.0"
@@ -7571,7 +7525,6 @@ dependencies = [
"scale-info",
"serai-coins-pallet",
"serai-dex-pallet",
"serai-genesis-liquidity-pallet",
"serai-in-instructions-primitives",
"serai-primitives",
"serai-validator-sets-pallet",
@@ -7660,6 +7613,7 @@ dependencies = [
"futures-util",
"hex",
"jsonrpsee",
"libp2p",
"pallet-transaction-payment-rpc",
"rand_core",
"sc-authority-discovery",
@@ -7833,8 +7787,6 @@ dependencies = [
"scale-info",
"serai-coins-pallet",
"serai-dex-pallet",
"serai-emissions-pallet",
"serai-genesis-liquidity-pallet",
"serai-in-instructions-pallet",
"serai-primitives",
"serai-signals-pallet",
@@ -7949,7 +7901,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -7965,13 +7917,13 @@ dependencies = [
[[package]]
name = "serde_repr"
version = "0.1.18"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -8248,7 +8200,7 @@ dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -8444,7 +8396,7 @@ source = "git+https://github.com/serai-dex/substrate#6e3f07bf5c98a6a3ec15f2b1a46
dependencies = [
"quote",
"sp-core-hashing",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -8463,7 +8415,7 @@ source = "git+https://github.com/serai-dex/substrate#6e3f07bf5c98a6a3ec15f2b1a46
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -8635,7 +8587,7 @@ dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -8788,7 +8740,7 @@ dependencies = [
"parity-scale-codec",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -8925,9 +8877,9 @@ dependencies = [
[[package]]
name = "strsim"
version = "0.11.0"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "strum"
@@ -8967,7 +8919,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -9055,9 +9007,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.55"
version = "2.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0"
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
dependencies = [
"proc-macro2",
"quote",
@@ -9073,7 +9025,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -9180,7 +9132,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -9276,9 +9228,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.36.0"
version = "1.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
dependencies = [
"backtrace",
"bytes",
@@ -9286,7 +9238,7 @@ dependencies = [
"mio",
"num_cpus",
"parking_lot 0.12.1",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"signal-hook-registry",
"socket2 0.5.6",
"tokio-macros",
@@ -9301,7 +9253,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -9322,7 +9274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
dependencies = [
"futures-core",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"tokio",
"tokio-util",
]
@@ -9337,7 +9289,7 @@ dependencies = [
"futures-core",
"futures-io",
"futures-sink",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"tokio",
"tracing",
]
@@ -9405,7 +9357,7 @@ dependencies = [
"futures-core",
"futures-util",
"pin-project",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"tokio",
"tower-layer",
"tower-service",
@@ -9425,7 +9377,7 @@ dependencies = [
"http 0.2.12",
"http-body 0.4.6",
"http-range-header",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"tower-layer",
"tower-service",
]
@@ -9449,7 +9401,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
"log",
"pin-project-lite 0.2.13",
"pin-project-lite 0.2.14",
"tracing-attributes",
"tracing-core",
]
@@ -9462,7 +9414,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -9867,7 +9819,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
"wasm-bindgen-shared",
]
@@ -9901,7 +9853,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -10210,7 +10162,7 @@ checksum = "ca7af9bb3ee875c4907835e607a275d10b04d15623d3aebe01afe8fbd3f85050"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -10253,9 +10205,9 @@ dependencies = [
[[package]]
name = "widestring"
version = "1.0.2"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
[[package]]
name = "winapi"
@@ -10526,9 +10478,9 @@ dependencies = [
[[package]]
name = "xml-rs"
version = "0.8.19"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193"
[[package]]
name = "xmltree"
@@ -10587,7 +10539,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
@@ -10607,14 +10559,14 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.55",
"syn 2.0.58",
]
[[package]]
name = "zstd"
version = "0.11.2+zstd.1.5.2"
dependencies = [
"zstd 0.13.0",
"zstd 0.13.1",
]
[[package]]
@@ -10628,11 +10580,11 @@ dependencies = [
[[package]]
name = "zstd"
version = "0.13.0"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110"
checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a"
dependencies = [
"zstd-safe 7.0.0",
"zstd-safe 7.1.0",
]
[[package]]
@@ -10647,18 +10599,18 @@ dependencies = [
[[package]]
name = "zstd-safe"
version = "7.0.0"
version = "7.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e"
checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.9+zstd.1.5.5"
version = "2.0.10+zstd.1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656"
checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa"
dependencies = [
"cc",
"pkg-config",

View File

@@ -9,7 +9,7 @@ use std_shims::{
use rand_core::{RngCore, CryptoRng};
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
use subtle::{ConstantTimeEq, Choice, CtOption};
use subtle::{ConstantTimeEq, ConditionallySelectable};
use curve25519_dalek::{
constants::ED25519_BASEPOINT_TABLE,
@@ -169,13 +169,8 @@ fn core(
}
// Perform the core loop
let mut c1 = CtOption::new(Scalar::ZERO, Choice::from(0));
let mut c1 = c;
for i in (start .. end).map(|i| i % n) {
// This will only execute once and shouldn't need to be constant time. Making it constant time
// removes the risk of branch prediction creating timing differences depending on ring index
// however
c1 = c1.or_else(|| CtOption::new(c, i.ct_eq(&0)));
let c_p = mu_P * c;
let c_c = mu_C * c;
@@ -188,10 +183,15 @@ fn core(
to_hash.extend(L.compress().to_bytes());
to_hash.extend(R.compress().to_bytes());
c = hash_to_scalar(&to_hash);
// This will only execute once and shouldn't need to be constant time. Making it constant time
// removes the risk of branch prediction creating timing differences depending on ring index
// however
c1.conditional_assign(&c, i.ct_eq(&(n - 1)));
}
// This first tuple is needed to continue signing, the latter is the c to be tested/worked with
((D, c * mu_P, c * mu_C), c1.unwrap_or(c))
((D, c * mu_P, c * mu_C), c1)
}
/// CLSAG signature, as used in Monero.

View File

@@ -57,7 +57,7 @@ fn clsag() {
}
let image = generate_key_image(&secrets.0);
let (clsag, pseudo_out) = Clsag::sign(
let (mut clsag, pseudo_out) = Clsag::sign(
&mut OsRng,
vec![(
secrets.0,
@@ -76,7 +76,12 @@ fn clsag() {
msg,
)
.swap_remove(0);
clsag.verify(&ring, &image, &pseudo_out, &msg).unwrap();
// make sure verification fails if we throw a random `c1` at it.
clsag.c1 = random_scalar(&mut OsRng);
assert!(clsag.verify(&ring, &image, &pseudo_out, &msg).is_err());
}
}

View File

@@ -51,7 +51,7 @@ env_logger = { version = "0.10", default-features = false, features = ["humantim
futures-util = { version = "0.3", default-features = false, features = ["std"] }
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", "macros"] }
libp2p = { version = "0.52", default-features = false, features = ["tokio", "tcp", "noise", "yamux", "request-response", "gossipsub", "macros"] }
[dev-dependencies]
tributary = { package = "tributary-chain", path = "./tributary", features = ["tests"] }

View File

@@ -22,7 +22,7 @@ use serai_db::{Get, DbTxn, Db, create_db};
use processor_messages::coordinator::cosign_block_msg;
use crate::{
p2p::{CosignedBlock, P2pMessageKind, P2p},
p2p::{CosignedBlock, GossipMessageKind, P2p},
substrate::LatestCosignedBlock,
};
@@ -323,7 +323,7 @@ impl<D: Db> CosignEvaluator<D> {
for cosign in cosigns {
let mut buf = vec![];
cosign.serialize(&mut buf).unwrap();
P2p::broadcast(&p2p, P2pMessageKind::CosignedBlock, buf).await;
P2p::broadcast(&p2p, GossipMessageKind::CosignedBlock, buf).await;
}
sleep(Duration::from_secs(60)).await;
}

View File

@@ -260,7 +260,7 @@ async fn handle_processor_message<D: Db, P: P2p>(
cosign_channel.send(cosigned_block).unwrap();
let mut buf = vec![];
cosigned_block.serialize(&mut buf).unwrap();
P2p::broadcast(p2p, P2pMessageKind::CosignedBlock, buf).await;
P2p::broadcast(p2p, GossipMessageKind::CosignedBlock, buf).await;
None
}
// This causes an action on Substrate yet not on any Tributary

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,7 @@ use tokio::sync::RwLock;
use crate::{
processors::{Message, Processors},
TributaryP2p, P2pMessageKind, P2p,
TributaryP2p, ReqResMessageKind, GossipMessageKind, P2pMessageKind, Message as P2pMessage, P2p,
};
pub mod tributary;
@@ -45,7 +45,10 @@ impl Processors for MemProcessors {
#[allow(clippy::type_complexity)]
#[derive(Clone, Debug)]
pub struct LocalP2p(usize, pub Arc<RwLock<(HashSet<Vec<u8>>, Vec<VecDeque<(usize, Vec<u8>)>>)>>);
pub struct LocalP2p(
usize,
pub Arc<RwLock<(HashSet<Vec<u8>>, Vec<VecDeque<(usize, P2pMessageKind, Vec<u8>)>>)>>,
);
impl LocalP2p {
pub fn new(validators: usize) -> Vec<LocalP2p> {
@@ -65,11 +68,13 @@ impl P2p for LocalP2p {
async fn subscribe(&self, _set: ValidatorSet, _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>) {
self.1.write().await.1[to].push_back((self.0, msg));
async fn send_raw(&self, to: Self::Id, msg: Vec<u8>) {
let mut msg_ref = msg.as_slice();
let kind = ReqResMessageKind::read(&mut msg_ref).unwrap();
self.1.write().await.1[to].push_back((self.0, P2pMessageKind::ReqRes(kind), msg_ref.to_vec()));
}
async fn broadcast_raw(&self, _genesis: Option<[u8; 32]>, msg: Vec<u8>) {
async fn broadcast_raw(&self, kind: P2pMessageKind, msg: Vec<u8>) {
// Content-based deduplication
let mut lock = self.1.write().await;
{
@@ -81,19 +86,26 @@ impl P2p for LocalP2p {
}
let queues = &mut lock.1;
let kind_len = (match kind {
P2pMessageKind::ReqRes(kind) => kind.serialize(),
P2pMessageKind::Gossip(kind) => kind.serialize(),
})
.len();
let msg = msg[kind_len ..].to_vec();
for (i, msg_queue) in queues.iter_mut().enumerate() {
if i == self.0 {
continue;
}
msg_queue.push_back((self.0, msg.clone()));
msg_queue.push_back((self.0, kind, msg.clone()));
}
}
async fn receive_raw(&self) -> (Self::Id, Vec<u8>) {
async fn receive(&self) -> P2pMessage<Self> {
// This is a cursed way to implement an async read from a Vec
loop {
if let Some(res) = self.1.write().await.1[self.0].pop_front() {
return res;
if let Some((sender, kind, msg)) = self.1.write().await.1[self.0].pop_front() {
return P2pMessage { sender, kind, msg };
}
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
}
@@ -103,6 +115,11 @@ impl P2p for LocalP2p {
#[async_trait]
impl TributaryP2p for LocalP2p {
async fn broadcast(&self, genesis: [u8; 32], msg: Vec<u8>) {
<Self as P2p>::broadcast(self, P2pMessageKind::Tributary(genesis), msg).await
<Self as P2p>::broadcast(
self,
P2pMessageKind::Gossip(GossipMessageKind::Tributary(genesis)),
msg,
)
.await
}
}

View File

@@ -26,7 +26,7 @@ use serai_db::MemDb;
use tributary::Tributary;
use crate::{
P2pMessageKind, P2p,
GossipMessageKind, P2pMessageKind, P2p,
tributary::{Transaction, TributarySpec},
tests::LocalP2p,
};
@@ -98,7 +98,7 @@ pub async fn run_tributaries(
for (p2p, tributary) in &mut tributaries {
while let Poll::Ready(msg) = poll!(p2p.receive()) {
match msg.kind {
P2pMessageKind::Tributary(genesis) => {
P2pMessageKind::Gossip(GossipMessageKind::Tributary(genesis)) => {
assert_eq!(genesis, tributary.genesis());
if tributary.handle_message(&msg.msg).await {
p2p.broadcast(msg.kind, msg.msg).await;
@@ -173,7 +173,7 @@ async fn tributary_test() {
for (p2p, tributary) in &mut tributaries {
while let Poll::Ready(msg) = poll!(p2p.receive()) {
match msg.kind {
P2pMessageKind::Tributary(genesis) => {
P2pMessageKind::Gossip(GossipMessageKind::Tributary(genesis)) => {
assert_eq!(genesis, tributary.genesis());
tributary.handle_message(&msg.msg).await;
}
@@ -199,7 +199,7 @@ async fn tributary_test() {
for (p2p, tributary) in &mut tributaries {
while let Poll::Ready(msg) = poll!(p2p.receive()) {
match msg.kind {
P2pMessageKind::Tributary(genesis) => {
P2pMessageKind::Gossip(GossipMessageKind::Tributary(genesis)) => {
assert_eq!(genesis, tributary.genesis());
tributary.handle_message(&msg.msg).await;
}

View File

@@ -116,8 +116,8 @@ async fn sync_test() {
.map_err(|_| "failed to send ActiveTributary to heartbeat")
.unwrap();
// The heartbeat is once every 10 blocks
sleep(Duration::from_secs(10 * block_time)).await;
// The heartbeat is once every 10 blocks, with some limitations
sleep(Duration::from_secs(20 * block_time)).await;
assert!(syncer_tributary.tip().await != spec.genesis());
// Verify it synced to the tip

View File

@@ -74,7 +74,7 @@ impl TributarySpec {
pub fn genesis(&self) -> [u8; 32] {
// Calculate the genesis for this Tributary
let mut genesis = RecommendedTranscript::new(b"Serai Tributary Genesis");
let mut genesis = RecommendedTranscript::new(b"Serai Tributary Genesis Testnet 2.1");
// This locks it to a specific Serai chain
genesis.append_message(b"serai_block", self.serai_block);
genesis.append_message(b"session", self.set.session.0.to_le_bytes());

View File

@@ -59,8 +59,7 @@ pub const ACCOUNT_MEMPOOL_LIMIT: u32 = 50;
pub const BLOCK_SIZE_LIMIT: usize = 3_001_000;
pub(crate) const TENDERMINT_MESSAGE: u8 = 0;
pub(crate) const BLOCK_MESSAGE: u8 = 1;
pub(crate) const TRANSACTION_MESSAGE: u8 = 2;
pub(crate) const TRANSACTION_MESSAGE: u8 = 2; // TODO: Normalize to 1
#[allow(clippy::large_enum_variant)]
#[derive(Clone, PartialEq, Eq, Debug)]
@@ -336,9 +335,6 @@ impl<D: Db, T: TransactionTrait, P: P2p> Tributary<D, T, P> {
// Return true if the message should be rebroadcasted.
pub async fn handle_message(&self, msg: &[u8]) -> bool {
// Acquire the lock now to prevent sync_block from being run at the same time
let mut sync_block = self.synced_block_result.write().await;
match msg.first() {
Some(&TRANSACTION_MESSAGE) => {
let Ok(tx) = Transaction::read::<&[u8]>(&mut &msg[1 ..]) else {
@@ -370,19 +366,6 @@ impl<D: Db, T: TransactionTrait, P: P2p> Tributary<D, T, P> {
false
}
Some(&BLOCK_MESSAGE) => {
let mut msg_ref = &msg[1 ..];
let Ok(block) = Block::<T>::read(&mut msg_ref) else {
log::error!("received invalid block message");
return false;
};
let commit = msg[(msg.len() - msg_ref.len()) ..].to_vec();
if self.sync_block_internal(block, commit, &mut sync_block).await {
log::debug!("synced block over p2p net instead of building the commit ourselves");
}
false
}
_ => false,
}
}

View File

@@ -41,9 +41,8 @@ use tendermint::{
use tokio::sync::RwLock;
use crate::{
TENDERMINT_MESSAGE, TRANSACTION_MESSAGE, BLOCK_MESSAGE, ReadWrite,
transaction::Transaction as TransactionTrait, Transaction, BlockHeader, Block, BlockError,
Blockchain, P2p,
TENDERMINT_MESSAGE, TRANSACTION_MESSAGE, ReadWrite, transaction::Transaction as TransactionTrait,
Transaction, BlockHeader, Block, BlockError, Blockchain, P2p,
};
pub mod tx;
@@ -414,12 +413,7 @@ impl<D: Db, T: TransactionTrait, P: P2p> Network for TendermintNetwork<D, T, P>
);
match block_res {
Ok(()) => {
// If we successfully added this block, broadcast it
// TODO: Move this under the coordinator once we set up on new block notifications?
let mut msg = serialized_block.0;
msg.insert(0, BLOCK_MESSAGE);
msg.extend(encoded_commit);
self.p2p.broadcast(self.genesis, msg).await;
// If we successfully added this block, break
break;
}
Err(BlockError::NonLocalProvided(hash)) => {
@@ -428,6 +422,7 @@ impl<D: Db, T: TransactionTrait, P: P2p> Network for TendermintNetwork<D, T, P>
hex::encode(hash),
hex::encode(self.genesis)
);
tokio::time::sleep(core::time::Duration::from_secs(5)).await;
}
_ => return invalid_block(),
}

View File

@@ -313,11 +313,16 @@ impl<N: Network + 'static> TendermintMachine<N> {
let time_until_round_end = round_end.instant().saturating_duration_since(Instant::now());
if time_until_round_end == Duration::ZERO {
log::trace!(
target: "tendermint",
"resetting when prior round ended {}ms ago",
Instant::now().saturating_duration_since(round_end.instant()).as_millis(),
);
}
log::trace!("sleeping until round ends in {}ms", time_until_round_end.as_millis());
log::trace!(
target: "tendermint",
"sleeping until round ends in {}ms",
time_until_round_end.as_millis(),
);
sleep(time_until_round_end).await;
// Clear our outbound message queue
@@ -598,7 +603,11 @@ impl<N: Network + 'static> TendermintMachine<N> {
);
let id = block.id();
let proposal = self.network.add_block(block, commit).await;
log::trace!("added block {} (produced by machine)", hex::encode(id.as_ref()));
log::trace!(
target: "tendermint",
"added block {} (produced by machine)",
hex::encode(id.as_ref()),
);
self.reset(msg.round, proposal).await;
}
Err(TendermintError::Malicious(sender, evidence)) => {
@@ -692,7 +701,12 @@ impl<N: Network + 'static> TendermintMachine<N> {
(msg.round == self.block.round().number) &&
(msg.data.step() == Step::Propose)
{
log::trace!("received Propose for block {}, round {}", msg.block.0, msg.round.0);
log::trace!(
target: "tendermint",
"received Propose for block {}, round {}",
msg.block.0,
msg.round.0,
);
}
// If this is a precommit, verify its signature
@@ -710,7 +724,13 @@ impl<N: Network + 'static> TendermintMachine<N> {
if !self.block.log.log(signed.clone())? {
return Err(TendermintError::AlreadyHandled);
}
log::debug!(target: "tendermint", "received new tendermint message");
log::debug!(
target: "tendermint",
"received new tendermint message (block: {}, round: {}, step: {:?})",
msg.block.0,
msg.round.0,
msg.data.step(),
);
// All functions, except for the finalizer and the jump, are locked to the current round
@@ -757,6 +777,13 @@ impl<N: Network + 'static> TendermintMachine<N> {
// 55-56
// Jump, enabling processing by the below code
if self.block.log.round_participation(msg.round) > self.weights.fault_threshold() {
log::debug!(
target: "tendermint",
"jumping from round {} to round {}",
self.block.round().number.0,
msg.round.0,
);
// Jump to the new round.
let proposer = self.round(msg.round, None);
@@ -814,13 +841,26 @@ impl<N: Network + 'static> TendermintMachine<N> {
if (self.block.round().step == Step::Prevote) && matches!(msg.data, Data::Prevote(_)) {
let (participation, weight) =
self.block.log.message_instances(self.block.round().number, &Data::Prevote(None));
let threshold_weight = self.weights.threshold();
if participation < threshold_weight {
log::trace!(
target: "tendermint",
"progess towards setting prevote timeout, participation: {}, needed: {}",
participation,
threshold_weight,
);
}
// 34-35
if participation >= self.weights.threshold() {
if participation >= threshold_weight {
log::trace!(
target: "tendermint",
"setting timeout for prevote due to sufficient participation",
);
self.block.round_mut().set_timeout(Step::Prevote);
}
// 44-46
if weight >= self.weights.threshold() {
if weight >= threshold_weight {
self.broadcast(Data::Precommit(None));
return Ok(None);
}
@@ -830,6 +870,10 @@ impl<N: Network + 'static> TendermintMachine<N> {
if matches!(msg.data, Data::Precommit(_)) &&
self.block.log.has_participation(self.block.round().number, Step::Precommit)
{
log::trace!(
target: "tendermint",
"setting timeout for precommit due to sufficient participation",
);
self.block.round_mut().set_timeout(Step::Precommit);
}

View File

@@ -1,6 +1,5 @@
use std::{sync::Arc, collections::HashMap};
use log::debug;
use parity_scale_codec::Encode;
use crate::{ext::*, RoundNumber, Step, DataFor, TendermintError, SignedMessageFor, Evidence};
@@ -27,7 +26,7 @@ impl<N: Network> MessageLog<N> {
let step = msg.data.step();
if let Some(existing) = msgs.get(&step) {
if existing.msg.data != msg.data {
debug!(
log::debug!(
target: "tendermint",
"Validator sent multiple messages for the same block + round + step"
);

View File

@@ -57,6 +57,7 @@ impl<N: Network> RoundData<N> {
// Poll all set timeouts, returning the Step whose timeout has just expired
pub(crate) async fn timeout_future(&self) -> Step {
/*
let now = Instant::now();
log::trace!(
target: "tendermint",
@@ -64,6 +65,7 @@ impl<N: Network> RoundData<N> {
self.step,
self.timeouts.iter().map(|(k, v)| (k, v.duration_since(now))).collect::<HashMap<_, _>>()
);
*/
let timeout_future = |step| {
let timeout = self.timeouts.get(&step).copied();

View File

@@ -55,8 +55,6 @@ exceptions = [
{ allow = ["AGPL-3.0"], name = "serai-coins-pallet" },
{ allow = ["AGPL-3.0"], name = "serai-dex-pallet" },
{ allow = ["AGPL-3.0"], name = "serai-genesis-liquidity-pallet" },
{ allow = ["AGPL-3.0"], name = "serai-in-instructions-pallet" },

View File

@@ -511,7 +511,7 @@ fn start(network: Network, services: HashSet<String>) {
command
} else {
// Publish the port
command.arg("-p").arg("30563:30563")
command.arg("-p").arg("30564:30564")
}
}
"serai" => {

View File

@@ -1,14 +0,0 @@
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Call {
// This call is just a place holder so that abi works as expected.
empty_call,
}
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Event {
empty_event,
}

View File

@@ -1,19 +0,0 @@
use serai_primitives::*;
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Call {
// This call is just a place holder so that abi works as expected.
empty_call,
}
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Event {
GenesisLiquidityAdded { by: SeraiAddress, balance: Balance },
GenesisLiquidityRemoved { by: SeraiAddress, balance: Balance },
GenesisLiquidityAddedToPool { coin1: Balance, coin2: Balance },
EconomicSecurityReached { network: NetworkId },
}

View File

@@ -11,9 +11,6 @@ pub mod validator_sets;
pub mod in_instructions;
pub mod signals;
pub mod genesis_liquidity;
pub mod emissions;
pub mod babe;
pub mod grandpa;
@@ -28,8 +25,6 @@ pub enum Call {
LiquidityTokens(coins::Call),
Dex(dex::Call),
ValidatorSets(validator_sets::Call),
GenesisLiquidity(genesis_liquidity::Call),
Emissions(emissions::Call),
InInstructions(in_instructions::Call),
Signals(signals::Call),
Babe(babe::Call),
@@ -51,8 +46,6 @@ pub enum Event {
LiquidityTokens(coins::Event),
Dex(dex::Event),
ValidatorSets(validator_sets::Event),
GenesisLiquidity(genesis_liquidity::Event),
Emissions(emissions::Event),
InInstructions(in_instructions::Event),
Signals(signals::Event),
Babe,

View File

@@ -159,9 +159,11 @@ pub mod pallet {
///
/// Errors if any amount overflows.
pub fn mint(to: Public, balance: Balance) -> Result<(), Error<T, I>> {
/*
if !T::AllowMint::is_allowed(&balance) {
Err(Error::<T, I>::MintNotAllowed)?;
}
*/
// update the balance
Self::increase_balance_internal(to, balance)?;

View File

@@ -194,11 +194,6 @@ pub mod pallet {
#[pallet::getter(fn security_oracle_value)]
pub type SecurityOracleValue<T: Config> = StorageMap<_, Identity, Coin, Amount, OptionQuery>;
/// Current length of the `SpotPrices` map.
#[pallet::storage]
#[pallet::getter(fn swap_volume)]
pub type SwapVolume<T: Config> = StorageMap<_, Identity, Coin, u64, OptionQuery>;
impl<T: Config> Pallet<T> {
fn restore_median(
coin: Coin,
@@ -895,20 +890,6 @@ pub mod pallet {
}
i += 1;
}
// update the volume, SRI amount is always at index 1 if the path len is 2 or 3.
// path len 1 is not allowed and 3 is already the maximum.
let swap_volume = amounts.get(1).ok_or(Error::<T>::CorrespondenceError)?;
let existing = SwapVolume::<T>::get(coin1).unwrap_or(0);
let new_volume = existing.saturating_add(*swap_volume);
SwapVolume::<T>::set(coin1, Some(new_volume));
// if we did 2 pools, update the volume for second coin as well.
if u32::try_from(path.len()).unwrap() == T::MaxSwapPathLength::get() {
let existing = SwapVolume::<T>::get(path.last().unwrap()).unwrap_or(0);
let new_volume = existing.saturating_add(*swap_volume);
SwapVolume::<T>::set(path.last().unwrap(), Some(new_volume));
}
Self::deposit_event(Event::SwapExecuted {
who: sender,
send_to,

View File

@@ -1,65 +0,0 @@
[package]
name = "serai-emissions-pallet"
version = "0.1.0"
description = "Emissions pallet for Serai"
license = "AGPL-3.0-only"
repository = "https://github.com/serai-dex/serai/tree/develop/substrate/emissions/pallet"
authors = ["Akil Demir <aeg_asd@hotmail.com>"]
edition = "2021"
rust-version = "1.77"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.cargo-machete]
ignored = ["scale", "scale-info"]
[lints]
workspace = true
[dependencies]
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2", default-features = false, features = ["derive"] }
frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false }
frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-session = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false }
pallet-babe = { git = "https://github.com/serai-dex/substrate", default-features = false }
coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false }
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../../validator-sets/pallet", default-features = false }
dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-features = false }
serai-primitives = { path = "../../primitives", default-features = false }
serai-validator-sets-primitives = { path = "../../validator-sets/primitives", default-features = false }
emissions-primitives = { package = "serai-emissions-primitives", path = "../primitives", default-features = false }
[features]
std = [
"scale/std",
"scale-info/std",
"frame-system/std",
"frame-support/std",
"sp-std/std",
"sp-session/std",
"sp-runtime/std",
"pallet-babe/std",
"coins-pallet/std",
"validator-sets-pallet/std",
"dex-pallet/std",
"serai-primitives/std",
"emissions-primitives/std",
]
default = ["std"]

View File

@@ -1,15 +0,0 @@
AGPL-3.0-only license
Copyright (c) 2024 Luke Parker
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License Version 3 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

View File

@@ -1,306 +0,0 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[allow(clippy::cast_possible_truncation, clippy::no_effect_underscore_binding)]
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_system::pallet_prelude::*;
use frame_support::{pallet_prelude::*, sp_runtime::SaturatedConversion};
use sp_std::{vec, vec::Vec, collections::btree_map::BTreeMap};
use sp_session::ShouldEndSession;
use sp_runtime;
use coins_pallet::{Config as CoinsConfig, Pallet as Coins, AllowMint};
use dex_pallet::{Config as DexConfig, Pallet as Dex};
use validator_sets_pallet::{Pallet as ValidatorSets, Config as ValidatorSetsConfig};
use pallet_babe::{Pallet as Babe, Config as BabeConfig};
use serai_primitives::{NetworkId, NETWORKS, *};
use serai_validator_sets_primitives::MAX_KEY_SHARES_PER_SET;
use emissions_primitives::*;
#[pallet::config]
pub trait Config:
frame_system::Config<AccountId = PublicKey>
+ ValidatorSetsConfig
+ BabeConfig
+ CoinsConfig
+ DexConfig
{
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
}
#[pallet::genesis_config]
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)]
pub struct GenesisConfig<T: Config> {
/// Networks to spawn Serai with.
pub networks: Vec<NetworkId>,
/// List of participants to place in the initial validator sets.
pub participants: Vec<T::AccountId>,
}
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
GenesisConfig { networks: Default::default(), participants: Default::default() }
}
}
#[pallet::error]
pub enum Error<T> {
GenesisPeriodEnded,
AmountOverflowed,
NotEnoughLiquidity,
CanOnlyRemoveFullAmount,
}
#[pallet::event]
pub enum Event<T: Config> {}
#[pallet::pallet]
pub struct Pallet<T>(PhantomData<T>);
#[pallet::storage]
#[pallet::getter(fn participants)]
pub(crate) type Participants<T: Config> = StorageMap<
_,
Identity,
NetworkId,
BoundedVec<(PublicKey, u64), ConstU32<{ MAX_KEY_SHARES_PER_SET }>>,
OptionQuery,
>;
#[pallet::storage]
#[pallet::getter(fn epoch_begin_block)]
pub(crate) type EpochBeginBlock<T: Config> = StorageMap<_, Identity, u64, u64, ValueQuery>;
#[pallet::storage]
#[pallet::getter(fn economic_security_reached)]
pub(crate) type EconomicSecurityReached<T: Config> =
StorageMap<_, Identity, NetworkId, BlockNumberFor<T>, ValueQuery>;
#[pallet::storage]
#[pallet::getter(fn last_swap_volume)]
pub(crate) type LastSwapVolume<T: Config> = StorageMap<_, Identity, NetworkId, u64, OptionQuery>;
#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
for id in self.networks.clone() {
let mut participants = vec![];
for p in self.participants.clone() {
participants.push((p, 0u64));
}
Participants::<T>::set(id, Some(participants.try_into().unwrap()));
}
EpochBeginBlock::<T>::set(0, 0);
}
}
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
/// Since we are on `on_finalize`, session should have already rotated.
/// We can distribute the rewards for the last set.
fn on_finalize(n: BlockNumberFor<T>) {
// we accept we reached economic security once we can mint smallest amount of a network's coin
for coin in COINS {
let existing = EconomicSecurityReached::<T>::get(coin.network());
if existing == 0u32.into() &&
<T as CoinsConfig>::AllowMint::is_allowed(&Balance { coin, amount: Amount(1) })
{
EconomicSecurityReached::<T>::set(coin.network(), n);
}
}
// emissions start only after genesis period and happens once per epoch
// so we don't do anything before that time.
if !(n >= BLOCKS_PER_MONTH.into() && T::ShouldEndSession::should_end_session(n)) {
return;
}
// figure out the amount of blocks in the last epoch
// TODO: we use epoch index here but should we use SessionIndex since this is how we decide
// whether time to distribute the rewards or not? Because apparently epochs != Sessions
// since we can skip some epochs if the chain is offline more than epoch duration??
let epoch = Babe::<T>::current_epoch().epoch_index - 1;
let block_count = n.saturated_into::<u64>() - Self::epoch_begin_block(epoch);
// get total reward for this epoch
let pre_ec_security = Self::pre_ec_security();
let mut distances = BTreeMap::new();
let mut total_distance: u64 = 0;
let reward_this_epoch = if Self::initial_period(n) {
// rewards are fixed for initial period
block_count * INITIAL_REWARD_PER_BLOCK
} else if pre_ec_security {
// calculate distance to economic security per network
let mut total_required: u64 = 0;
let mut total_current: u64 = 0;
for n in NETWORKS {
if n == NetworkId::Serai {
continue;
}
let required = ValidatorSets::<T>::required_stake_for_network(n);
let mut current = ValidatorSets::<T>::total_allocated_stake(n).unwrap_or(Amount(0)).0;
if current > required {
current = required;
}
distances.insert(n, required - current);
total_required = total_required.saturating_add(required);
total_current = total_current.saturating_add(current);
}
total_distance = total_required.saturating_sub(total_current);
// add serai network portion(20%)
let new_total_distance =
total_distance.saturating_mul(10) / (10 - SERAI_VALIDATORS_DESIRED_PERCENTAGE);
distances.insert(NetworkId::Serai, new_total_distance - total_distance);
total_distance = new_total_distance;
// rewards for pre-economic security is
// (STAKE_REQUIRED - CURRENT_STAKE) / blocks_until(SECURE_BY).
let block_reward = total_distance / Self::blocks_until(SECURE_BY);
block_count * block_reward
} else {
// post ec security
block_count * REWARD_PER_BLOCK
};
// get swap volumes
let mut volume_per_network: BTreeMap<NetworkId, u64> = BTreeMap::new();
for c in COINS {
// this should return 0 for SRI and so it shouldn't affect the total volume.
let current_volume = Dex::<T>::swap_volume(c).unwrap_or(0);
volume_per_network.insert(
c.network(),
(*volume_per_network.get(&c.network()).unwrap_or(&0)).saturating_add(current_volume),
);
}
// map current volumes to epoch volumes
let mut total_volume = 0u64;
for (n, vol) in &mut volume_per_network {
let last_volume = Self::last_swap_volume(n).unwrap_or(0);
let vol_this_epoch = vol.saturating_sub(last_volume);
// update the current volume
LastSwapVolume::<T>::set(n, Some(*vol));
total_volume = total_volume.saturating_add(vol_this_epoch);
*vol = vol_this_epoch;
}
// map epoch ec-security-distance/volume to rewards
let rewards_per_network = distances
.into_iter()
.map(|(n, distance)| {
let reward = if pre_ec_security {
// calculate how much each network gets based on distance to ec-security
reward_this_epoch.saturating_mul(distance) / total_distance
} else {
// 20% of the reward goes to the Serai network and rest is distributed among others
// based on swap-volume.
if n == NetworkId::Serai {
reward_this_epoch / 5
} else {
let reward = reward_this_epoch - (reward_this_epoch / 5);
reward.saturating_mul(*volume_per_network.get(&n).unwrap_or(&0)) / total_volume
}
};
(n, reward)
})
.collect::<BTreeMap<NetworkId, u64>>();
// distribute the rewards within the network
for (n, reward) in rewards_per_network {
// calculate pool vs validator share
let capacity = ValidatorSets::<T>::total_allocated_stake(n).unwrap_or(Amount(0)).0;
let required = ValidatorSets::<T>::required_stake_for_network(n);
let unused_capacity = capacity.saturating_sub(required);
let distribution = unused_capacity.saturating_mul(ACCURACY_MULTIPLIER) / capacity;
let total = DESIRED_DISTRIBUTION.saturating_add(distribution);
let validators_reward = DESIRED_DISTRIBUTION.saturating_mul(reward) / total;
let pool_reward = total - validators_reward;
// distribute validators rewards
Self::distribute_to_validators(n, validators_reward);
// send the rest to the pool
let coin_count = u64::try_from(n.coins().len()).unwrap();
for c in n.coins() {
// TODO: we just print a warning here instead of unwrap?
// assumes reward is equally distributed between network coins.
Coins::<T>::mint(
Dex::<T>::get_pool_account(*c),
Balance { coin: Coin::Serai, amount: Amount(pool_reward / coin_count) },
)
.unwrap();
}
}
// set the begin block and participants
EpochBeginBlock::<T>::set(epoch, n.saturated_into::<u64>());
for n in NETWORKS {
// TODO: `participants_for_latest_decided_set` returns keys with key shares but we
// store keys with actual stake amounts. Pr https://github.com/serai-dex/serai/pull/518
// supposed to change that and so this pr relies and that pr.
Participants::<T>::set(n, ValidatorSets::<T>::participants_for_latest_decided_set(n));
}
}
}
impl<T: Config> Pallet<T> {
fn blocks_until(block: u64) -> u64 {
let current = <frame_system::Pallet<T>>::block_number().saturated_into::<u64>();
block.saturating_sub(current)
}
fn initial_period(n: BlockNumberFor<T>) -> bool {
n >= BLOCKS_PER_MONTH.into() && n < (3 * BLOCKS_PER_MONTH).into()
}
/// Returns true if any of the external networks haven't reached economic security yet.
fn pre_ec_security() -> bool {
for n in NETWORKS {
if n == NetworkId::Serai {
continue;
}
if Self::economic_security_reached(n) == 0u32.into() {
return true;
}
}
false
}
fn distribute_to_validators(n: NetworkId, reward: u64) {
// distribute among network's set based on
// -> (key shares * stake per share) + ((stake % stake per share) / 2)
let stake_per_share = ValidatorSets::<T>::allocation_per_key_share(n).unwrap().0;
let mut scores = vec![];
let mut total_score = 0u64;
for (p, amount) in Self::participants(n).unwrap() {
let remainder = amount % stake_per_share;
let score = (amount - remainder) + (remainder / 2);
total_score = total_score.saturating_add(score);
scores.push((p, score));
}
// stake the rewards
for (p, score) in scores {
let p_reward = reward.saturating_mul(score) / total_score;
// TODO: print a warning here?
let _ = ValidatorSets::<T>::deposit_stake(n, p, Amount(p_reward));
}
}
}
}
pub use pallet::*;

View File

@@ -1,22 +0,0 @@
[package]
name = "serai-emissions-primitives"
version = "0.1.0"
description = "Serai emissions primitives"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/substrate/emissions/primitives"
authors = ["Akil Demir <aeg_asd@hotmail.com>"]
edition = "2021"
rust-version = "1.77"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[lints]
workspace = true
[dependencies]
[features]
std = []
default = ["std"]

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024 Luke Parker
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,24 +0,0 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
/// Amount of blocks in 30 days for 6s per block.
pub const BLOCKS_PER_MONTH: u32 = 10 * 60 * 24 * 30;
/// INITIAL_REWARD = 100,000 SRI / BLOCKS_PER_DAY for 60 days
pub const INITIAL_REWARD_PER_BLOCK: u64 = 100_000 * 10u64.pow(8) / ((BLOCKS_PER_MONTH as u64) / 30);
/// REWARD = 20M SRI / BLOCKS_PER_YEAR
pub const REWARD_PER_BLOCK: u64 = 20_000_000 * 10u64.pow(8) / ((BLOCKS_PER_MONTH as u64) * 12);
/// 20% of all stake desired to be for Serai network(2/10)
pub const SERAI_VALIDATORS_DESIRED_PERCENTAGE: u64 = 2;
/// Desired unused capacity ratio for a network assuming capacity is 10,000.
pub const DESIRED_DISTRIBUTION: u64 = 1_000;
/// Percentage scale for the validator vs. pool reward distribution.
pub const ACCURACY_MULTIPLIER: u64 = 10_000;
/// The block to target for economic security
pub const SECURE_BY: u64 = (BLOCKS_PER_MONTH as u64) * 12;

View File

@@ -1,54 +0,0 @@
[package]
name = "serai-genesis-liquidity-pallet"
version = "0.1.0"
description = "Genesis liquidity pallet for Serai"
license = "AGPL-3.0-only"
repository = "https://github.com/serai-dex/serai/tree/develop/substrate/genesis-liquidity/pallet"
authors = ["Akil Demir <aeg_asd@hotmail.com>"]
edition = "2021"
rust-version = "1.77"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.cargo-machete]
ignored = ["scale", "scale-info"]
[lints]
workspace = true
[dependencies]
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2", default-features = false, features = ["derive"] }
frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false }
frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false }
sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false }
dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-features = false }
coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false }
serai-primitives = { path = "../../primitives", default-features = false }
genesis-liquidity-primitives = { package = "serai-genesis-liquidity-primitives", path = "../primitives", default-features = false }
[features]
std = [
"scale/std",
"scale-info/std",
"frame-system/std",
"frame-support/std",
"sp-std/std",
"coins-pallet/std",
"dex-pallet/std",
"serai-primitives/std",
"genesis-liquidity-primitives/std",
]
default = ["std"]

View File

@@ -1,15 +0,0 @@
AGPL-3.0-only license
Copyright (c) 2024 Luke Parker
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License Version 3 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

View File

@@ -1,276 +0,0 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[allow(clippy::cast_possible_truncation, clippy::no_effect_underscore_binding)]
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_system::{pallet_prelude::*, RawOrigin};
use frame_support::{pallet_prelude::*, sp_runtime::SaturatedConversion};
use sp_std::{vec, collections::btree_map::BTreeMap};
use dex_pallet::{Pallet as Dex, Config as DexConfig};
use coins_pallet::{
primitives::{OutInstructionWithBalance, OutInstruction},
Config as CoinsConfig, Pallet as Coins, AllowMint,
};
use serai_primitives::*;
pub use genesis_liquidity_primitives as primitives;
use primitives::*;
/// LiquidityTokens Pallet as an instance of coins pallet.
pub type LiquidityTokens<T> = coins_pallet::Pallet<T, coins_pallet::Instance1>;
#[pallet::config]
pub trait Config:
frame_system::Config + DexConfig + CoinsConfig + coins_pallet::Config<coins_pallet::Instance1>
{
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
}
#[pallet::error]
pub enum Error<T> {
GenesisPeriodEnded,
AmountOverflowed,
NotEnoughLiquidity,
CanOnlyRemoveFullAmount,
}
#[pallet::event]
#[pallet::generate_deposit(fn deposit_event)]
pub enum Event<T: Config> {
GenesisLiquidityAdded { by: SeraiAddress, balance: Balance },
GenesisLiquidityRemoved { by: SeraiAddress, balance: Balance },
GenesisLiquidityAddedToPool { coin1: Balance, coin2: Balance },
EconomicSecurityReached { network: NetworkId },
}
#[pallet::pallet]
pub struct Pallet<T>(PhantomData<T>);
#[pallet::storage]
pub(crate) type Liquidity<T: Config> =
StorageDoubleMap<_, Identity, Coin, Blake2_128Concat, PublicKey, SubstrateAmount, OptionQuery>;
#[pallet::storage]
pub(crate) type LiquidityTokensPerAddress<T: Config> =
StorageDoubleMap<_, Identity, Coin, Blake2_128Concat, PublicKey, SubstrateAmount, OptionQuery>;
#[pallet::storage]
pub(crate) type EconomicSecurityReached<T: Config> =
StorageMap<_, Identity, NetworkId, BlockNumberFor<T>, ValueQuery>;
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_finalize(n: BlockNumberFor<T>) {
// Distribute the genesis sri to pools after a month
if n == BLOCKS_PER_MONTH.into() {
// mint the SRI
Coins::<T>::mint(
GENESIS_LIQUIDITY_ACCOUNT.into(),
Balance { coin: Coin::Serai, amount: Amount(GENESIS_SRI) },
)
.unwrap();
// get coin values & total
let mut account_values = BTreeMap::new();
let mut pool_values = BTreeMap::new();
let mut total_value: u64 = 0;
for coin in COINS {
// TODO: following line is just a place holder till we get the actual coin value
// in terms of btc.
let value = Dex::<T>::security_oracle_value(coin).unwrap_or(Amount(0)).0;
account_values.insert(coin, vec![]);
let mut pool_amount: u64 = 0;
for (account, amount) in Liquidity::<T>::iter_prefix(coin) {
pool_amount = pool_amount.saturating_add(amount);
let value_this_addr = amount.saturating_mul(value);
account_values.get_mut(&coin).unwrap().push((account, value_this_addr))
}
let pool_value = pool_amount.saturating_mul(value);
total_value = total_value.saturating_add(pool_value);
pool_values.insert(coin, (pool_amount, pool_value));
}
// add the liquidity per pool
for (coin, (amount, value)) in &pool_values {
let sri_amount = GENESIS_SRI.saturating_mul(*value) / total_value;
let origin = RawOrigin::Signed(GENESIS_LIQUIDITY_ACCOUNT.into());
Dex::<T>::add_liquidity(
origin.into(),
*coin,
*amount,
sri_amount,
*amount,
sri_amount,
GENESIS_LIQUIDITY_ACCOUNT.into(),
)
.unwrap();
Self::deposit_event(Event::GenesisLiquidityAddedToPool {
coin1: Balance { coin: *coin, amount: Amount(*amount) },
coin2: Balance { coin: Coin::Serai, amount: Amount(sri_amount) },
});
// set liquidity tokens per account
let tokens = LiquidityTokens::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), *coin).0;
let mut total_tokens_this_coin: u64 = 0;
for (acc, value) in account_values.get(coin).unwrap() {
let liq_tokens_this_acc =
tokens.saturating_mul(*value) / pool_values.get(coin).unwrap().1;
total_tokens_this_coin = total_tokens_this_coin.saturating_add(liq_tokens_this_acc);
LiquidityTokensPerAddress::<T>::set(coin, acc, Some(liq_tokens_this_acc));
}
assert_eq!(tokens, total_tokens_this_coin);
}
// we shouldn't have any coin left in our account at this moment, including SRI.
for coin in COINS {
assert_eq!(Coins::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), coin), Amount(0));
}
}
// we accept we reached economic security once we can mint smallest amount of a network's coin
for coin in COINS {
let existing = EconomicSecurityReached::<T>::get(coin.network());
if existing == 0u32.into() &&
<T as CoinsConfig>::AllowMint::is_allowed(&Balance { coin, amount: Amount(1) })
{
EconomicSecurityReached::<T>::set(coin.network(), n);
Self::deposit_event(Event::EconomicSecurityReached { network: coin.network() });
}
}
}
}
impl<T: Config> Pallet<T> {
/// Add genesis liquidity for the given account. All accounts that provide liquidity
/// will receive the genesis SRI according to their liquidity ratio.
pub fn add_coin_liquidity(account: PublicKey, balance: Balance) -> DispatchResult {
// check we are still in genesis period
if Self::genesis_ended() {
Err(Error::<T>::GenesisPeriodEnded)?;
}
// mint the coins
Coins::<T>::mint(GENESIS_LIQUIDITY_ACCOUNT.into(), balance)?;
// save
let existing = Liquidity::<T>::get(balance.coin, account).unwrap_or(0);
let new = existing.checked_add(balance.amount.0).ok_or(Error::<T>::AmountOverflowed)?;
Liquidity::<T>::set(balance.coin, account, Some(new));
Self::deposit_event(Event::GenesisLiquidityAdded { by: account.into(), balance });
Ok(())
}
/// Remove the provided genesis liquidity for an account. If called pre-economic security era,
pub fn remove_coin_liquidity(
account: PublicKey,
balance: Balance,
out_address: ExternalAddress,
) -> DispatchResult {
let origin = RawOrigin::Signed(GENESIS_LIQUIDITY_ACCOUNT.into());
// check we are still in genesis period
if Self::genesis_ended() {
// check user have enough to remove
let existing = LiquidityTokensPerAddress::<T>::get(balance.coin, account).unwrap_or(0);
if balance.amount.0 > existing {
Err(Error::<T>::NotEnoughLiquidity)?;
}
// remove liquidity from pool
let prev_sri = Coins::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), Coin::Serai);
let prev_coin = Coins::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), balance.coin);
Dex::<T>::remove_liquidity(
origin.clone().into(),
balance.coin,
balance.amount.0,
1,
1,
GENESIS_LIQUIDITY_ACCOUNT.into(),
)?;
let current_sri = Coins::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), Coin::Serai);
let current_coin = Coins::<T>::balance(GENESIS_LIQUIDITY_ACCOUNT.into(), balance.coin);
// burn the SRI if necessary
let mut sri = current_sri.0.saturating_sub(prev_sri.0);
let distance_to_full_pay =
GENESIS_SRI_TRICKLE_FEED - Self::blocks_since_ec_security(&balance.coin);
let burn_sri_amount = sri.saturating_mul(distance_to_full_pay) / GENESIS_SRI_TRICKLE_FEED;
Coins::<T>::burn(
origin.clone().into(),
Balance { coin: Coin::Serai, amount: Amount(burn_sri_amount) },
)?;
sri -= burn_sri_amount;
// transfer to owner
let coin_out = current_coin.0 - prev_coin.0;
Coins::<T>::transfer(
origin.clone().into(),
account,
Balance { coin: balance.coin, amount: Amount(coin_out) },
)?;
Coins::<T>::transfer(
origin.into(),
account,
Balance { coin: Coin::Serai, amount: Amount(sri) },
)?;
// save
let existing = LiquidityTokensPerAddress::<T>::get(balance.coin, account).unwrap_or(0);
let new = existing.checked_sub(balance.amount.0).ok_or(Error::<T>::AmountOverflowed)?;
LiquidityTokensPerAddress::<T>::set(balance.coin, account, Some(new));
} else {
let existing = Liquidity::<T>::get(balance.coin, account).unwrap_or(0);
if balance.amount.0 > existing || balance.amount.0 == 0 {
Err(Error::<T>::NotEnoughLiquidity)?;
}
if balance.amount.0 < existing {
Err(Error::<T>::CanOnlyRemoveFullAmount)?;
}
// TODO: do internal transfer instead?
let origin = RawOrigin::Signed(GENESIS_LIQUIDITY_ACCOUNT.into());
let instruction = OutInstructionWithBalance {
instruction: OutInstruction { address: out_address, data: None },
balance,
};
Coins::<T>::burn_with_instruction(origin.into(), instruction)?;
// save
Liquidity::<T>::set(balance.coin, account, None);
}
Self::deposit_event(Event::GenesisLiquidityRemoved { by: account.into(), balance });
Ok(())
}
/// Returns the number of blocks since the coin's network reached economic security first time.
/// If the network is yet to be reached that threshold, 0 is returned. And maximum of
/// `GENESIS_SRI_TRICKLE_FEED` returned.
fn blocks_since_ec_security(coin: &Coin) -> u64 {
let ec_security_block =
EconomicSecurityReached::<T>::get(coin.network()).saturated_into::<u64>();
let current = <frame_system::Pallet<T>>::block_number().saturated_into::<u64>();
if ec_security_block > 0 {
let diff = current - ec_security_block;
if diff > GENESIS_SRI_TRICKLE_FEED {
return GENESIS_SRI_TRICKLE_FEED;
}
return diff;
}
0
}
fn genesis_ended() -> bool {
<frame_system::Pallet<T>>::block_number() >= BLOCKS_PER_MONTH.into()
}
}
}
pub use pallet::*;

View File

@@ -1,25 +0,0 @@
[package]
name = "serai-genesis-liquidity-primitives"
version = "0.1.0"
description = "Serai genesis liquidity primitives"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/substrate/genesis-liquidity/primitives"
authors = ["Akil Demir <aeg_asd@hotmail.com>"]
edition = "2021"
rust-version = "1.77"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[lints]
workspace = true
[dependencies]
serai-primitives = { path = "../../primitives", default-features = false }
[features]
std = [
"serai-primitives/std",
]
default = ["std"]

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024 Luke Parker
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,17 +0,0 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
use serai_primitives::*;
// amount of blocks in 30 days for 6s per block.
pub const BLOCKS_PER_MONTH: u32 = 10 * 60 * 24 * 30;
/// 180 days of blocks
pub const GENESIS_SRI_TRICKLE_FEED: u64 = 10 * 60 * 24 * 180;
// 100 Million SRI
pub const GENESIS_SRI: u64 = 100_000_000 * 10_u64.pow(8);
// This is the account to hold and manage the genesis liquidity.
pub const GENESIS_LIQUIDITY_ACCOUNT: SeraiAddress = system_address(b"Genesis-liquidity-account");

View File

@@ -37,7 +37,6 @@ in-instructions-primitives = { package = "serai-in-instructions-primitives", pat
coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false }
dex-pallet = { package = "serai-dex-pallet", path = "../../dex/pallet", default-features = false }
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../../validator-sets/pallet", default-features = false }
genesis-liquidity-pallet = { package = "serai-genesis-liquidity-pallet", path = "../../genesis-liquidity/pallet", default-features = false }
[features]
std = [
@@ -59,6 +58,5 @@ std = [
"coins-pallet/std",
"dex-pallet/std",
"validator-sets-pallet/std",
"genesis-liquidity-pallet/std",
]
default = ["std"]

View File

@@ -33,14 +33,10 @@ pub mod pallet {
Config as ValidatorSetsConfig, Pallet as ValidatorSets,
};
use genesis_liquidity_pallet::{Pallet as GenesisLiq, Config as GenesisLiqConfig};
use super::*;
#[pallet::config]
pub trait Config:
frame_system::Config + CoinsConfig + DexConfig + ValidatorSetsConfig + GenesisLiqConfig
{
pub trait Config: frame_system::Config + CoinsConfig + DexConfig + ValidatorSetsConfig {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
}
@@ -204,14 +200,6 @@ pub mod pallet {
}
}
}
InInstruction::GenesisLiquidity(ops) => match ops {
GenesisLiquidityOperation::Add(address, balance) => {
GenesisLiq::<T>::add_coin_liquidity(address.into(), balance)?;
}
GenesisLiquidityOperation::Remove(address, balance, out_address) => {
GenesisLiq::<T>::remove_coin_liquidity(address.into(), balance, out_address)?;
}
},
}
Ok(())
}

View File

@@ -71,15 +71,6 @@ pub enum DexCall {
Swap(Balance, OutAddress),
}
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
#[cfg_attr(feature = "std", derive(Zeroize))]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum GenesisLiquidityOperation {
Add(SeraiAddress, Balance),
Remove(SeraiAddress, Balance, ExternalAddress),
}
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
#[cfg_attr(feature = "std", derive(Zeroize))]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
@@ -87,7 +78,6 @@ pub enum GenesisLiquidityOperation {
pub enum InInstruction {
Transfer(SeraiAddress),
Dex(DexCall),
GenesisLiquidity(GenesisLiquidityOperation),
}
#[derive(Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebug)]

View File

@@ -26,6 +26,8 @@ hex = "0.4"
rand_core = "0.6"
schnorrkel = "0.11"
libp2p = "0.52"
sp-core = { git = "https://github.com/serai-dex/substrate" }
sp-keystore = { git = "https://github.com/serai-dex/substrate" }
sp-timestamp = { git = "https://github.com/serai-dex/substrate" }

View File

@@ -1,13 +1,13 @@
use core::marker::PhantomData;
use std::collections::HashSet;
use sp_core::Pair as PairTrait;
use sp_core::{Decode, Pair as PairTrait, sr25519::Public};
use sc_service::ChainType;
use serai_runtime::{
primitives::*, WASM_BINARY, BABE_GENESIS_EPOCH_CONFIG, RuntimeGenesisConfig, SystemConfig,
CoinsConfig, DexConfig, ValidatorSetsConfig, SignalsConfig, BabeConfig, GrandpaConfig,
EmissionsConfig,
};
pub type ChainSpec = sc_service::GenericChainSpec<RuntimeGenesisConfig>;
@@ -24,7 +24,7 @@ fn wasm_binary() -> Vec<u8> {
WASM_BINARY.ok_or("compiled in wasm not available").unwrap().to_vec()
}
fn testnet_genesis(
fn devnet_genesis(
wasm_binary: &[u8],
validators: &[&'static str],
endowed_accounts: Vec<PublicKey>,
@@ -60,8 +60,55 @@ fn testnet_genesis(
.collect(),
participants: validators.clone(),
},
emissions: EmissionsConfig {
networks: serai_runtime::primitives::NETWORKS.to_vec(),
signals: SignalsConfig::default(),
babe: BabeConfig {
authorities: validators.iter().map(|validator| ((*validator).into(), 1)).collect(),
epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG),
_config: PhantomData,
},
grandpa: GrandpaConfig {
authorities: validators.into_iter().map(|validator| (validator.into(), 1)).collect(),
_config: PhantomData,
},
}
}
fn testnet_genesis(wasm_binary: &[u8], validators: Vec<&'static str>) -> RuntimeGenesisConfig {
let validators = validators
.into_iter()
.map(|validator| Public::decode(&mut hex::decode(validator).unwrap().as_slice()).unwrap())
.collect::<Vec<_>>();
assert_eq!(validators.iter().collect::<HashSet<_>>().len(), validators.len());
RuntimeGenesisConfig {
system: SystemConfig { code: wasm_binary.to_vec(), _config: PhantomData },
transaction_payment: Default::default(),
coins: CoinsConfig {
accounts: validators
.iter()
.map(|a| (*a, Balance { coin: Coin::Serai, amount: Amount(5_000_000 * 10_u64.pow(8)) }))
.collect(),
_ignore: Default::default(),
},
dex: DexConfig {
pools: vec![Coin::Bitcoin, Coin::Ether, Coin::Dai, Coin::Monero],
_ignore: Default::default(),
},
validator_sets: ValidatorSetsConfig {
networks: serai_runtime::primitives::NETWORKS
.iter()
.map(|network| match network {
NetworkId::Serai => (NetworkId::Serai, Amount(50_000 * 10_u64.pow(8))),
NetworkId::Bitcoin => (NetworkId::Bitcoin, Amount(1_000_000 * 10_u64.pow(8))),
NetworkId::Ethereum => (NetworkId::Ethereum, Amount(1_000_000 * 10_u64.pow(8))),
NetworkId::Monero => (NetworkId::Monero, Amount(100_000 * 10_u64.pow(8))),
})
.collect(),
participants: validators.clone(),
},
signals: SignalsConfig::default(),
@@ -87,7 +134,7 @@ pub fn development_config() -> ChainSpec {
"devnet",
ChainType::Development,
move || {
testnet_genesis(
devnet_genesis(
&wasm_binary,
&["Alice"],
vec![
@@ -105,7 +152,7 @@ pub fn development_config() -> ChainSpec {
// Telemetry
None,
// Protocol ID
Some("serai"),
Some("serai-devnet"),
// Fork ID
None,
// Properties
@@ -115,7 +162,7 @@ pub fn development_config() -> ChainSpec {
)
}
pub fn testnet_config() -> ChainSpec {
pub fn local_config() -> ChainSpec {
let wasm_binary = wasm_binary();
ChainSpec::from_genesis(
@@ -125,7 +172,7 @@ pub fn testnet_config() -> ChainSpec {
"local",
ChainType::Local,
move || {
testnet_genesis(
devnet_genesis(
&wasm_binary,
&["Alice", "Bob", "Charlie", "Dave"],
vec![
@@ -143,7 +190,7 @@ pub fn testnet_config() -> ChainSpec {
// Telemetry
None,
// Protocol ID
Some("serai"),
Some("serai-local"),
// Fork ID
None,
// Properties
@@ -152,3 +199,137 @@ pub fn testnet_config() -> ChainSpec {
None,
)
}
pub fn testnet_config() -> ChainSpec {
{
use std::time::{Duration, SystemTime};
let secs_since_epoch = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.expect("current time is before the epoch")
.as_secs();
let secs_till_start = 1713283200_u64.saturating_sub(secs_since_epoch);
std::thread::sleep(Duration::from_secs(secs_till_start));
}
let wasm_binary = wasm_binary();
ChainSpec::from_genesis(
// Name
"Test Network 2",
// ID
"testnet-2",
ChainType::Live,
move || {
testnet_genesis(
&wasm_binary,
vec![
// Kayaba
"4cef4080d00c6ff5ad93d61d1ca631cc10f8c9bd733e8c0c873a85b5fbe5c625",
// CommunityStaking
"587723d333049d9f4e6f027bbd701d603544a422329ea4e1027d60f7947e1074",
// SHossain
"6e30ec71b331d73992307fa7c53719ff238666d7d895487a1b691cc1e4481344",
// StormyCloud
"b0ebef6d712b3eb0f01e69a80519e55feff4be8b226fa64d84691e4b3ca2fb38",
// Yangu
"c692a906f9c63b7e4d12ad3cde204c6715b9a96b5b8ce565794917b7eaaa5f08",
// t-900
"6a9d5a3ca9422baec670e47238decf4a8515f2de0060b0a566a56dfd72686e52",
// tappokone
"36acb4be05513bed670ef3b43dc3a0fdfde8dc45339f81c80b53b2289dc3730c",
// Sleipnir
"0e87d766c9acec45b39445579cd3f40c8a4b42e9a34049bdbef0da83d000410e",
"c2f96300a956e949883a5e8952270fb8193154a68533d0dd6b10076224e30167",
"7a66312c53dfb153e842456f4e9a38dcda7e1788a3366df3e54125e29821f870",
// jberman
"b6e23eec7dbdb2bf72a087e335b44464cedfcc11c669033d6e520b3bc8de1650",
// krytie
"82815723c498d2aaaead050e63b979bb49a94a00c97b971c22340dffeaa36829",
// toplel
"4243da92918333bfc46f4d17ddeda0c3420d920231627dca1b6049f2f13cac6d",
// clamking
"941a6efa9e4dee6c3015cc42339fe56f43c2230133787746828befcee957cb1f",
// Helios
"56a0e89cffe57337e9e232e41dca0ad7306a17fa0ca63fbac048190fdd45d511",
// akil
"1caffa33b0ea1c7ed95c8450c0baf57baf9e1c1f43af3e28a722ef6d3d4db27e",
// Eumaios
"9ec7b5edf854f6285205468ed7402e40e5bed8238dc226dd4fd718a40efdce44",
// pigeons
"66c71ebf040542ab467def0ad935ec30ea693953d4322b3b168f6f4e9fcacb63",
// joe_land1
"94e25d8247b2f0e718bee169213052c693b78743dd91f403398a8837c34e0e6a",
// rlking1255
"82592430fe65e353510d3c1018cebc9806290e2d9098a94a1190f120f471c52b",
// Seth For Privacy
"f8ebbdb8ff2a77527528577bad6fd3297017f7b35a0613ba31d8af8e7e78cd7b",
// lemon_respector
"ce4a4cd996e4601a0226f3c8d9c9cae84519a1a7277b4822e1694b4a8c3ef10b",
// tuxsudo
"c6804a561d07d77c2806844a59c24bb9472df16043767721aae0caa20e82391e",
// Awakeninghumanity.eth
"5046c9f55a65e08df86c132c142f055db0376563fabc190f47a6851e0ff2af2b",
// ART3MIS.CLOUD
"5c1793880b0c06a5ce232288c7789cf4451ab20a8da49b84c88789965bc67356",
// michnovka
"98db8174ec40046b1bae39cad69ea0000d67e120524d46bc298d167407410618",
// kgminer
"8eca72a4bf684d7c4a20a34048003b504a046bce1289d3ae79a3b4422afaf808",
// Benny
"74b4f2d2347a4426c536e6ba48efa14b989b05f03c0ea9b1c67b23696c1a831d",
// Argo
"4025bbbe9c9be72769a27e5e6a3749782f4c9b2a47624bdcb0bfbd29f5e2056a",
// vdo
"1c87bbcd666099abc1ee2ec3f065abd073c237f95c4d0658b945e9d66d67622d",
// PotR
"b29ffbb4a4c0f14eb8c22fabaaacb43f92a62214ff45f0b4f50b7031c3a61a5a",
// Ghalleb
"48f903ed592638cee1c7f239a6ac14cbb0224a3153cff0f85eb0873113cf163f",
// monerobull
"56a2e3b410cb87bdb8125ae19d76a7be042de49693dc27f03e7a0dcc72b42f6c",
// Adorid
"3430222157262d6187c4537b026bcbaeb133695bbb512a7be8f25cc5a082d933",
// KeepKey
"a0ce13fb50c3d56548334af703b6ffb9a1b2f66e9dccf4a3688140b77fa58a06",
// Username
"b0e62f04f625447673a840d9c5f0e5867b355a67b0dee322334dc00925547b71",
// R0BC0D3R
"7e32cebc21b7979c36e477f0a849df1830cc052c879baf13107888654c0be654",
// worksmarter
"c4f2f6ffead84fcaa2e3c894d57c342a24c461eab5d1d17cae3d1a9e61d73e46",
],
)
},
// Bootnodes
vec![],
// Telemetry
None,
// Protocol ID
Some("serai-testnet-2"),
// Fork ID
None,
// Properties
None,
// Extensions
None,
)
}
pub fn bootnode_multiaddrs(id: &str) -> Vec<libp2p::Multiaddr> {
match id {
"local" | "devnet" => vec![],
"testnet-2" => vec![
// Kayaba
"/ip4/107.161.20.133/tcp/30333".parse().unwrap(),
// lemon_respector
"/ip4/188.66.62.11/tcp/30333".parse().unwrap(),
// Ghalleb
"/ip4/65.21.156.202/tcp/30333".parse().unwrap(),
// ART3MIS.CLOUD
"/ip4/51.195.60.217/tcp/30333".parse().unwrap(),
// worksmarter
"/ip4/37.60.255.101/tcp/30333".parse().unwrap(),
],
_ => panic!("requesting bootnodes for an unrecognized network"),
}
}

View File

@@ -40,7 +40,8 @@ impl SubstrateCli for Cli {
fn load_spec(&self, id: &str) -> Result<Box<dyn sc_service::ChainSpec>, String> {
match id {
"dev" | "devnet" => Ok(Box::new(chain_spec::development_config())),
"local" => Ok(Box::new(chain_spec::testnet_config())),
"local" => Ok(Box::new(chain_spec::local_config())),
"testnet" => Ok(Box::new(chain_spec::testnet_config())),
_ => panic!("Unknown network ID"),
}
}

View File

@@ -19,6 +19,7 @@ pub use sc_rpc_api::DenyUnsafe;
use sc_transaction_pool_api::TransactionPool;
pub struct FullDeps<C, P> {
pub id: String,
pub client: Arc<C>,
pub pool: Arc<P>,
pub deny_unsafe: DenyUnsafe,
@@ -46,18 +47,19 @@ where
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
let mut module = RpcModule::new(());
let FullDeps { client, pool, deny_unsafe, authority_discovery } = deps;
let FullDeps { id, client, pool, deny_unsafe, authority_discovery } = deps;
module.merge(System::new(client.clone(), pool, deny_unsafe).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)));
let mut authority_discovery_module =
RpcModule::new((id, 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 (id, client, authority_discovery) = &*context;
let latest_block = client.info().best_hash;
let validators = client.runtime_api().validators(latest_block, network).map_err(|_| {
@@ -66,7 +68,9 @@ where
"please report this at https://github.com/serai-dex/serai",
)))
})?;
let mut all_p2p_addresses = vec![];
// Always return the protocol's bootnodes
let mut all_p2p_addresses = crate::chain_spec::bootnode_multiaddrs(id);
// Additionally returns validators found over the DHT
for validator in validators {
let mut returned_addresses = authority_discovery
.write()

View File

@@ -161,7 +161,7 @@ pub fn new_partial(
))
}
pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError> {
let (
sc_service::PartialComponents {
client,
@@ -176,6 +176,11 @@ pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
keystore_container,
) = new_partial(&config)?;
config.network.node_name = "serai".to_string();
config.network.client_version = "0.1.0".to_string();
config.network.listen_addresses =
vec!["/ip4/0.0.0.0/tcp/30333".parse().unwrap(), "/ip6/::/tcp/30333".parse().unwrap()];
let mut net_config = sc_network::config::FullNetworkConfiguration::new(&config.network);
let grandpa_protocol_name =
grandpa::protocol_standard_name(&client.block_hash(0).unwrap().unwrap(), &config.chain_spec);
@@ -203,6 +208,59 @@ pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
warp_sync_params: Some(WarpSyncParams::WithProvider(warp_sync)),
})?;
task_manager.spawn_handle().spawn("bootnodes", "bootnodes", {
let network = network.clone();
let id = config.chain_spec.id().to_string();
async move {
// Transforms the above Multiaddrs into MultiaddrWithPeerIds
// While the PeerIds *should* be known in advance and hardcoded, that data wasn't collected in
// time and this fine for a testnet
let bootnodes = || async {
use libp2p::{Transport as TransportTrait, tcp::tokio::Transport, noise::Config};
let bootnode_multiaddrs = crate::chain_spec::bootnode_multiaddrs(&id);
let mut tasks = vec![];
for multiaddr in bootnode_multiaddrs {
tasks.push(tokio::time::timeout(
core::time::Duration::from_secs(10),
tokio::task::spawn(async move {
let Ok(noise) = Config::new(&sc_network::Keypair::generate_ed25519()) else { None? };
let mut transport = Transport::default()
.upgrade(libp2p::core::upgrade::Version::V1)
.authenticate(noise)
.multiplex(libp2p::yamux::Config::default());
let Ok(transport) = transport.dial(multiaddr.clone()) else { None? };
let Ok((peer_id, _)) = transport.await else { None? };
Some(sc_network::config::MultiaddrWithPeerId { multiaddr, peer_id })
}),
));
}
let mut res = vec![];
for task in tasks {
if let Ok(Ok(Some(bootnode))) = task.await {
res.push(bootnode);
}
}
res
};
use sc_network::{NetworkStatusProvider, NetworkPeers};
loop {
if let Ok(status) = network.status().await {
if status.num_connected_peers < 3 {
for bootnode in bootnodes().await {
let _ = network.add_reserved_peer(bootnode);
}
}
}
tokio::time::sleep(core::time::Duration::from_secs(60)).await;
}
}
});
if config.offchain_worker.enabled {
task_manager.spawn_handle().spawn(
"offchain-workers-runner",
@@ -258,11 +316,13 @@ pub fn new_full(config: Configuration) -> Result<TaskManager, ServiceError> {
};
let rpc_builder = {
let id = config.chain_spec.id().to_string();
let client = client.clone();
let pool = transaction_pool.clone();
Box::new(move |deny_unsafe, _| {
crate::rpc::create_full(crate::rpc::FullDeps {
id: id.clone(),
client: client.clone(),
pool: pool.clone(),
deny_unsafe,

View File

@@ -15,9 +15,7 @@ use sp_core::{ConstU32, bounded::BoundedVec};
use crate::{borsh_serialize_bounded_vec, borsh_deserialize_bounded_vec};
/// The type used to identify networks.
#[derive(
Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, PartialOrd, Ord, MaxEncodedLen, TypeInfo,
)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
#[cfg_attr(feature = "std", derive(Zeroize))]
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

View File

@@ -59,8 +59,6 @@ coins-pallet = { package = "serai-coins-pallet", path = "../coins/pallet", defau
dex-pallet = { package = "serai-dex-pallet", path = "../dex/pallet", default-features = false }
validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets/pallet", default-features = false }
genesis-liquidity-pallet = { package = "serai-genesis-liquidity-pallet", path = "../genesis-liquidity/pallet", default-features = false }
emissions-pallet = { package = "serai-emissions-pallet", path = "../emissions/pallet", default-features = false }
in-instructions-pallet = { package = "serai-in-instructions-pallet", path = "../in-instructions/pallet", default-features = false }
@@ -114,8 +112,6 @@ std = [
"dex-pallet/std",
"validator-sets-pallet/std",
"genesis-liquidity-pallet/std",
"emissions-pallet/std",
"in-instructions-pallet/std",

View File

@@ -32,9 +32,6 @@ pub use signals_pallet as signals;
pub use pallet_babe as babe;
pub use pallet_grandpa as grandpa;
pub use genesis_liquidity_pallet as genesis_liquidity;
pub use emissions_pallet as emissions;
// Actually used by the runtime
use sp_core::OpaqueMetadata;
use sp_std::prelude::*;
@@ -291,14 +288,6 @@ impl in_instructions::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
}
impl genesis_liquidity::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
}
impl emissions::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
}
// for publishing equivocation evidences.
impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime
where
@@ -375,8 +364,6 @@ construct_runtime!(
Dex: dex,
ValidatorSets: validator_sets,
GenesisLiquidity: genesis_liquidity,
Emissions: emissions,
InInstructions: in_instructions,

View File

@@ -489,12 +489,11 @@ pub mod pallet {
network: NetworkId,
account: T::AccountId,
amount: Amount,
block_reward: bool,
) -> DispatchResult {
let old_allocation = Self::allocation((network, account)).unwrap_or(Amount(0)).0;
let new_allocation = old_allocation + amount.0;
let allocation_per_key_share = Self::allocation_per_key_share(network).unwrap().0;
if new_allocation < allocation_per_key_share && !block_reward {
if new_allocation < allocation_per_key_share {
Err(Error::<T>::InsufficientAllocation)?;
}
@@ -797,15 +796,6 @@ pub mod pallet {
total_required
}
pub fn deposit_stake(
network: NetworkId,
account: T::AccountId,
amount: Amount,
) -> DispatchResult {
// TODO: make the increase_allocation public instead?
Self::increase_allocation(network, account, amount, true)
}
fn can_slash_serai_validator(validator: Public) -> bool {
// Checks if they're active or actively deallocating (letting us still slash them)
// We could check if they're upcoming/still allocating, yet that'd mean the equivocation is
@@ -946,7 +936,7 @@ pub mod pallet {
Self::account(),
Balance { coin: Coin::Serai, amount },
)?;
Self::increase_allocation(network, validator, amount, false)
Self::increase_allocation(network, validator, amount)
}
#[pallet::call_index(3)]