From 41d0447b467e1ec73c81696a1fda06611d9f4042 Mon Sep 17 00:00:00 2001 From: 1xstj <106580853+1xstj@users.noreply.github.com> Date: Mon, 18 Dec 2023 16:13:29 +0000 Subject: [PATCH] feat: add sqllite as an option to store signing keys (#723) * fix: updates for light client read * fix: only increment nonce by 1 on force_change_authorities * setup sqlx interface * setup path correctly * cleanup logs --------- Co-authored-by: drewstone --- Cargo.lock | 447 +++++++++++++++++++++++- Cargo.toml | 1 + alice | Bin 0 -> 4096 bytes dkg-gadget/Cargo.toml | 3 +- dkg-gadget/src/async_protocols/types.rs | 2 +- dkg-gadget/src/db/mod.rs | 2 + dkg-gadget/src/db/sql_storage.rs | 199 +++++++++++ dkg-gadget/src/lib.rs | 40 ++- dkg-primitives/src/types.rs | 4 + scripts/run-local-testnet.sh | 10 +- standalone/node/src/cli.rs | 2 + standalone/node/src/command.rs | 1 + standalone/node/src/service.rs | 4 +- 13 files changed, 683 insertions(+), 32 deletions(-) create mode 100644 alice create mode 100644 dkg-gadget/src/db/sql_storage.rs diff --git a/Cargo.lock b/Cargo.lock index 399eb3f37..7ade3247c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1048,6 +1048,15 @@ dependencies = [ "pin-project-lite 0.2.13", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic" version = "0.5.3" @@ -1346,7 +1355,10 @@ checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +dependencies = [ + "serde", +] [[package]] name = "bitflags" @@ -2611,6 +2623,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" dependencies = [ "const-oid", + "pem-rfc7468 0.6.0", "zeroize", ] @@ -2621,6 +2634,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" dependencies = [ "const-oid", + "pem-rfc7468 0.7.0", "zeroize", ] @@ -2828,6 +2842,7 @@ dependencies = [ "itertools 0.10.5", "lazy_static", "linked-hash-map", + "log", "multi-party-ecdsa", "parity-scale-codec", "parking_lot 0.12.1", @@ -2848,9 +2863,10 @@ dependencies = [ "sp-arithmetic", "sp-blockchain", "sp-consensus", - "sp-core", - "sp-keystore", - "sp-runtime", + "sp-core 21.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0)", + "sp-keystore 0.27.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0)", + "sp-runtime 24.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0)", + "sqlx", "strum 0.21.0", "substrate-prometheus-endpoint 0.10.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0)", "sync_wrapper", @@ -3154,6 +3170,12 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "downcast" version = "0.11.0" @@ -3275,6 +3297,9 @@ name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +dependencies = [ + "serde", +] [[package]] name = "elliptic-curve" @@ -3289,6 +3314,8 @@ dependencies = [ "ff 0.12.1", "generic-array 0.14.7", "group 0.12.1", + "hkdf", + "pem-rfc7468 0.6.0", "pkcs8 0.9.0", "rand_core 0.6.4", "sec1 0.3.0", @@ -3431,6 +3458,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + [[package]] name = "eth-keystore" version = "0.5.0" @@ -3972,6 +4010,12 @@ dependencies = [ "scale-info", ] +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" + [[package]] name = "fixed-hash" version = "0.8.0" @@ -4010,6 +4054,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -4416,6 +4471,17 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot 0.12.1", +] + [[package]] name = "futures-io" version = "0.3.29" @@ -4764,6 +4830,15 @@ dependencies = [ "fxhash", ] +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.0", +] + [[package]] name = "heck" version = "0.3.3" @@ -4778,6 +4853,9 @@ name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] [[package]] name = "hermit-abi" @@ -5543,6 +5621,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "lazycell" @@ -5572,6 +5653,12 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libp2p" version = "0.51.4" @@ -6024,6 +6111,17 @@ dependencies = [ "libsecp256k1-core", ] +[[package]] +name = "libsqlite3-sys" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-sys" version = "1.1.12" @@ -6747,6 +6845,23 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm 0.2.8", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + [[package]] name = "num-complex" version = "0.4.4" @@ -6776,6 +6891,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg 1.1.0", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.4.1" @@ -6795,7 +6921,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg 1.1.0", - "libm", + "libm 0.2.8", ] [[package]] @@ -7004,8 +7130,29 @@ dependencies = [ "rand_core 0.6.4", "rustfmt-wrapper", "serde", - "sha2 0.10.8", - "syn 2.0.40", + "sha2 0.10.7", + "syn 2.0.28", +] + +[[package]] +name = "p384" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa" +dependencies = [ + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.7", +] + +[[package]] +name = "packed_simd_2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" +dependencies = [ + "cfg-if", + "libm 0.1.4", ] [[package]] @@ -7778,6 +7925,24 @@ dependencies = [ "base64 0.13.1", ] +[[package]] +name = "pem-rfc7468" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -7939,14 +8104,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "piper" -version = "0.2.1" +name = "pkcs1" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "atomic-waker", - "fastrand 2.0.1", - "futures-io", + "der 0.7.7", + "pkcs8 0.10.2", + "spki 0.7.2", ] [[package]] @@ -8915,7 +9080,7 @@ dependencies = [ "libc", "once_cell", "spin 0.5.2", - "untrusted 0.7.1", + "untrusted", "web-sys", "winapi", ] @@ -8989,6 +9154,28 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "rsa" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" +dependencies = [ + "byteorder", + "const-oid", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "signature 2.1.0", + "spki 0.7.2", + "subtle", + "zeroize", +] + [[package]] name = "rstest" version = "0.12.0" @@ -11847,6 +12034,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spki" @@ -11868,6 +12058,212 @@ dependencies = [ "der 0.7.8", ] +[[package]] +name = "sqlformat" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85" +dependencies = [ + "itertools 0.11.0", + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e50c216e3624ec8e7ecd14c6a6a6370aad6ee5d8cfc3ab30b5162eeeef2ed33" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d6753e460c998bbd4cd8c6f0ed9a64346fcca0723d6e75e52fdc351c5d2169d" +dependencies = [ + "ahash 0.8.3", + "atoi", + "byteorder", + "bytes", + "crc", + "crossbeam-queue", + "dotenvy", + "either", + "event-listener", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashlink", + "hex", + "indexmap 2.0.0", + "log", + "memchr", + "native-tls", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2 0.10.7", + "smallvec", + "sqlformat", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a793bb3ba331ec8359c1853bd39eed32cdd7baaf22c35ccf5c92a7e8d1189ec" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4ee1e104e00dedb6aa5ffdd1343107b0a4702e862a84320ee7cc74782d96fc" +dependencies = [ + "dotenvy", + "either", + "heck 0.4.1", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.7", + "sqlx-core", + "sqlx-mysql", + "sqlx-sqlite", + "syn 1.0.109", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db" +dependencies = [ + "atoi", + "base64 0.21.2", + "bitflags 2.3.3", + "byteorder", + "bytes", + "crc", + "digest 0.10.7", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array 0.14.7", + "hex", + "hkdf", + "hmac 0.12.1", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand 0.8.5", + "rsa", + "serde", + "sha1", + "sha2 0.10.7", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624" +dependencies = [ + "atoi", + "base64 0.21.2", + "bitflags 2.3.3", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac 0.12.1", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha1", + "sha2 0.10.7", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59dc83cf45d89c555a577694534fcd1b55c545a816c816ce51f20bbe56a4f3f" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", +] + [[package]] name = "ss58-registry" version = "1.44.0" @@ -11953,6 +12349,17 @@ dependencies = [ "precomputed-hash", ] +[[package]] +name = "stringprep" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +dependencies = [ + "finl_unicode", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "strsim" version = "0.8.0" @@ -13303,6 +13710,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + [[package]] name = "universal-hash" version = "0.4.1" @@ -14344,6 +14757,12 @@ dependencies = [ "rustix 0.38.28", ] +[[package]] +name = "whoami" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" + [[package]] name = "wide" version = "0.7.13" diff --git a/Cargo.toml b/Cargo.toml index 2e6548cd6..4c7b06019 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -214,6 +214,7 @@ bytes = { version = "1.4.0", default-features = false } bincode2 = { version = "2.0.1", default-features = false } structopt = { version = "0.3.26", default-features = false } hash-db = { version = "0.16.0", default-features = false } +sqlx = { version = "0.7.1", default-features = false, features = ["macros"] } [profile.release] panic = 'unwind' diff --git a/alice b/alice new file mode 100644 index 0000000000000000000000000000000000000000..9a472209435d88229f65ab7a0ca30d67df87a462 GIT binary patch literal 4096 zcmWFz^vNtqRY=P(%1ta$FlG>7U}9o$P*7lCU|@t|AVoG{WY9}{#S79dK(-m98b?E5 nGz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nC=3ArNJIx= literal 0 HcmV?d00001 diff --git a/dkg-gadget/Cargo.toml b/dkg-gadget/Cargo.toml index 69f1ed626..db5844c8d 100644 --- a/dkg-gadget/Cargo.toml +++ b/dkg-gadget/Cargo.toml @@ -58,7 +58,8 @@ itertools = { workspace = true } sync_wrapper = { workspace = true } async-stream = { workspace = true } lazy_static = { workspace = true } - +log = { workspace = true } +sqlx = { workspace = true, features = ["runtime-tokio-native-tls", "sqlite", "json"] } hash-db = { workspace = true, optional = true } webb-proposals = { workspace = true } diff --git a/dkg-gadget/src/async_protocols/types.rs b/dkg-gadget/src/async_protocols/types.rs index 2de372457..eec4a1db1 100644 --- a/dkg-gadget/src/async_protocols/types.rs +++ b/dkg-gadget/src/async_protocols/types.rs @@ -4,6 +4,7 @@ use curv::elliptic::curves::Secp256k1; use dkg_runtime_primitives::{SessionId, StoredUnsignedProposalBatch}; use multi_party_ecdsa::protocols::multi_party_ecdsa::gg_2020::state_machine::keygen::LocalKey; use serde::{Deserialize, Serialize}; +use sqlx::{FromRow, Sqlite}; use std::fmt::{Debug, Formatter}; use wsts::{ common::{PolyCommitment, Signature}, @@ -17,7 +18,6 @@ pub enum LocalKeyType { ECDSA(LocalKey), FROST(Vec, PartyState), } - impl Debug for LocalKeyType { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { diff --git a/dkg-gadget/src/db/mod.rs b/dkg-gadget/src/db/mod.rs index c8bfdd7a5..e15bbb5d0 100644 --- a/dkg-gadget/src/db/mod.rs +++ b/dkg-gadget/src/db/mod.rs @@ -2,10 +2,12 @@ use dkg_primitives::{types::DKGError, SessionId}; mod mem; mod offchain_storage; +mod sql_storage; use crate::async_protocols::types::LocalKeyType; pub use mem::DKGInMemoryDb; pub use offchain_storage::DKGOffchainStorageDb; +pub use sql_storage::{BackendConfig, SqlBackend, SqliteBackendConfig}; /// A Database backend, specifically for the DKG to store and load important state /// diff --git a/dkg-gadget/src/db/sql_storage.rs b/dkg-gadget/src/db/sql_storage.rs new file mode 100644 index 000000000..9c1584c9c --- /dev/null +++ b/dkg-gadget/src/db/sql_storage.rs @@ -0,0 +1,199 @@ +use super::*; +use crate::{async_protocols::types::LocalKeyType, debug_logger::DebugLogger, DKGKeystore}; +use dkg_primitives::{ + types::DKGError, + utils::{decrypt_data, encrypt_data}, + SessionId, +}; +use dkg_runtime_primitives::offchain::crypto::{Pair as AppPair, Public}; +use sc_client_api::Backend; +use sc_keystore::LocalKeystore; +use sp_core::{offchain::OffchainStorage, Pair}; +use sp_runtime::{ + generic::BlockId, + traits::{BlakeTwo256, Block as BlockT, Header as HeaderT, UniqueSaturatedInto, Zero}, +}; +use sqlx::{ + query::Query, + sqlite::{ + SqliteArguments, SqliteConnectOptions, SqlitePool, SqlitePoolOptions, SqliteQueryResult, + }, + ConnectOptions, Error, Execute, QueryBuilder, Row, Sqlite, +}; +use std::{cmp::Ordering, collections::HashSet, num::NonZeroU32, str::FromStr, sync::Arc}; + +// Represents the Sqlite connection options that are +/// used to establish a database connection. +#[derive(Debug)] +pub struct SqliteBackendConfig<'a> { + pub path: &'a str, + pub create_if_missing: bool, + pub thread_count: u32, + pub cache_size: u64, +} + +/// Represents the backend configurations. +#[derive(Debug)] +pub enum BackendConfig<'a> { + Sqlite(SqliteBackendConfig<'a>), +} + +#[derive(Clone)] +pub struct SqlBackend { + /// The Sqlite connection. + pool: SqlitePool, + + /// The number of allowed operations for the Sqlite filter call. + /// A value of `0` disables the timeout. + num_ops_timeout: i32, +} + +impl SqlBackend { + pub fn new( + config: BackendConfig<'_>, + pool_size: u32, + num_ops_timeout: Option, + ) -> Result { + futures::executor::block_on(async { + Self::new_inner(config, pool_size, num_ops_timeout).await + }) + } + /// Creates a new instance of the SQL backend. + pub async fn new_inner( + config: BackendConfig<'_>, + pool_size: u32, + num_ops_timeout: Option, + ) -> Result { + let any_pool = SqlitePoolOptions::new() + .max_connections(pool_size) + .connect_lazy_with(Self::connect_options(&config)?.disable_statement_logging()); + let _ = Self::create_database_if_not_exists(&any_pool).await?; + let _ = Self::create_indexes_if_not_exist(&any_pool).await?; + Ok(Self { + pool: any_pool, + num_ops_timeout: num_ops_timeout + .map(|n| n.get()) + .unwrap_or(0) + .try_into() + .unwrap_or(i32::MAX), + }) + } + + fn connect_options(config: &BackendConfig) -> Result { + match config { + BackendConfig::Sqlite(config) => { + log::info!(target: "dkg-gadget", "📑 Connection configuration: {config:?}"); + let config = sqlx::sqlite::SqliteConnectOptions::from_str(config.path)? + .create_if_missing(config.create_if_missing) + // https://www.sqlite.org/pragma.html#pragma_busy_timeout + .busy_timeout(std::time::Duration::from_secs(8)) + // 200MB, https://www.sqlite.org/pragma.html#pragma_cache_size + .pragma("cache_size", format!("-{}", config.cache_size)) + // https://www.sqlite.org/pragma.html#pragma_analysis_limit + .pragma("analysis_limit", "1000") + // https://www.sqlite.org/pragma.html#pragma_threads + .pragma("threads", config.thread_count.to_string()) + // https://www.sqlite.org/pragma.html#pragma_threads + .pragma("temp_store", "memory") + // https://www.sqlite.org/wal.html + .journal_mode(sqlx::sqlite::SqliteJournalMode::Wal) + // https://www.sqlite.org/pragma.html#pragma_synchronous + .synchronous(sqlx::sqlite::SqliteSynchronous::Normal); + Ok(config) + }, + } + } + + /// Get the underlying Sqlite pool. + pub fn pool(&self) -> &SqlitePool { + &self.pool + } + + /// Create the Sqlite database if it does not already exist. + async fn create_database_if_not_exists(pool: &SqlitePool) -> Result { + sqlx::query( + "BEGIN; + CREATE TABLE IF NOT EXISTS dkg_keys ( + id INTEGER PRIMARY KEY, + session_id INTEGER NOT NULL, + local_key BLOB NOT NULL, + ); + COMMIT;", + ) + .execute(pool) + .await + } + + /// Create the Sqlite database indices if it does not already exist. + async fn create_indexes_if_not_exist(pool: &SqlitePool) -> Result { + sqlx::query( + "BEGIN; + CREATE INDEX IF NOT EXISTS session_id_index ON dkg_keys ( + session_id + ); + COMMIT;", + ) + .execute(pool) + .await + } + + async fn get_local_key(&self, session_id: SessionId) -> Result, DKGError> { + log::info!("{}", format!("SQL Storage : Fetching local keys for session {session_id:?}")); + let session_id: i64 = session_id as i64; + match sqlx::query("SELECT local_key FROM dkg_keys WHERE session_id = ?") + .bind(session_id) + .fetch_optional(self.pool()) + .await + { + Ok(result) => { + if let Some(row) = result { + let local_key_json: String = row.get(0); + let local_key: LocalKeyType = serde_json::from_str(&local_key_json).unwrap(); + return Ok(Some(local_key)) + } + return Err(DKGError::LocalKeyNotFound) + }, + Err(err) => { + log::debug!(target: "dkg-gadget", "Failed retrieving key for session_id {err:?}"); + return Err(DKGError::LocalKeyNotFound) + }, + } + } + + async fn store_local_key( + &self, + session_id: SessionId, + local_key: LocalKeyType, + ) -> Result<(), DKGError> { + log::info!( + "{}", + format!( + "SQL Storage : Store local keys for session {session_id:?}, Key : {local_key:?}" + ) + ); + let session_id: i64 = session_id as i64; + let mut tx = self.pool().begin().await.map_err(|_| DKGError::StoringLocalKeyFailed)?; + let local_key = serde_json::to_string(&local_key).unwrap(); + sqlx::query("INSERT INTO dkg_keys(session_id, local_key) VALUES (?)") + .bind(session_id) + .bind(local_key) + .execute(&mut *tx) + .await + .map_err(|_| DKGError::StoringLocalKeyFailed)?; + tx.commit().await.map_err(|_| DKGError::StoringLocalKeyFailed) + } +} + +impl super::DKGDbBackend for SqlBackend { + fn get_local_key(&self, session_id: SessionId) -> Result, DKGError> { + futures::executor::block_on(async { self.get_local_key(session_id).await }) + } + + fn store_local_key( + &self, + session_id: SessionId, + local_key: LocalKeyType, + ) -> Result<(), DKGError> { + futures::executor::block_on(async { self.store_local_key(session_id, local_key).await }) + } +} diff --git a/dkg-gadget/src/lib.rs b/dkg-gadget/src/lib.rs index 321513c44..cee351a4b 100644 --- a/dkg-gadget/src/lib.rs +++ b/dkg-gadget/src/lib.rs @@ -11,9 +11,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - -use std::{marker::PhantomData, sync::Arc}; - use debug_logger::DebugLogger; use dkg_runtime_primitives::{crypto::AuthorityId, DKGApi, MaxAuthorities, MaxProposalLength}; use parking_lot::RwLock; @@ -26,6 +23,11 @@ use sp_api::{NumberFor, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_keystore::KeystorePtr; use sp_runtime::traits::Block; +use std::{ + marker::PhantomData, + path::{Path, PathBuf}, + sync::Arc, +}; mod error; /// Stores keypairs for DKG @@ -107,6 +109,8 @@ where pub prometheus_registry: Option, /// For logging pub debug_logger: DebugLogger, + /// database path + pub db_path: PathBuf, /// Phantom block type pub _block: PhantomData, } @@ -134,6 +138,7 @@ where local_keystore, _block, debug_logger, + db_path, } = dkg_params; let dkg_keystore: DKGKeystore = DKGKeystore::new(key_store, debug_logger.clone()); @@ -180,13 +185,28 @@ where // In memory backend, not used for now // let db_backend = Arc::new(db::DKGInMemoryDb::new()); - let offchain_db_backend = db::DKGOffchainStorageDb::new( - backend.clone(), - dkg_keystore.clone(), - local_keystore.clone(), - debug_logger.clone(), - ); - let db_backend = Arc::new(offchain_db_backend); + // let offchain_db_backend = db::DKGOffchainStorageDb::new( + // backend.clone(), + // dkg_keystore.clone(), + // local_keystore.clone(), + // debug_logger.clone(), + // ); + + let path = Path::new("sqlite:///").join(db_path).join("frontier.db3"); + + let sql_backend = db::SqlBackend::new( + db::BackendConfig::Sqlite(db::SqliteBackendConfig { + path: path.to_str().unwrap(), + create_if_missing: true, + cache_size: 20480, + thread_count: 4, + }), + 1, + None, + ) + .unwrap(); + + let db_backend = Arc::new(sql_backend); let worker_params = worker::WorkerParams { latest_header, client, diff --git a/dkg-primitives/src/types.rs b/dkg-primitives/src/types.rs index 6b257838c..1a0c876c9 100644 --- a/dkg-primitives/src/types.rs +++ b/dkg-primitives/src/types.rs @@ -216,6 +216,8 @@ pub enum DKGError { InvalidSigningSet, InputOutOfBounds, CannotSign, + LocalKeyNotFound, + StoringLocalKeyFailed, } impl fmt::Display for DKGError { @@ -242,6 +244,8 @@ impl fmt::Display for DKGError { InvalidSigningSet => "Invalid Signing Set!".to_string(), InputOutOfBounds => "Input value out of bounds set by runtime".to_string(), CannotSign => "Could not sign public key".to_string(), + LocalKeyNotFound => "Local key not found!".to_string(), + StoringLocalKeyFailed => "Local key not be saved!".to_string(), }; write!(f, "DKGError of type {label}") } diff --git a/scripts/run-local-testnet.sh b/scripts/run-local-testnet.sh index 2e1462b9b..cc7d573a1 100755 --- a/scripts/run-local-testnet.sh +++ b/scripts/run-local-testnet.sh @@ -46,28 +46,28 @@ echo "*** Start Webb DKG Node ***" # Alice ./target/release/dkg-standalone-node --tmp --chain local --validator -lerror --alice --output-path=./tmp/alice/output.log \ --rpc-cors all --rpc-external --rpc-methods=unsafe \ - --port 30333 \ + --port 30333 --db-path=./tmp/alice/db \ --rpc-port 9944 --node-key 0000000000000000000000000000000000000000000000000000000000000001 & # Bob ./target/release/dkg-standalone-node --tmp --chain local --validator -lerror --bob --output-path=./tmp/bob/output.log \ --rpc-cors all --rpc-external --rpc-methods=unsafe \ - --port 30305 \ + --port 30305 --db-path=./tmp/bob/db \ --rpc-port 9945 --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp & # Charlie ./target/release/dkg-standalone-node --tmp --chain local --validator -lerror --charlie --output-path=./tmp/charlie/output.log \ --rpc-cors all --rpc-external --rpc-methods=unsafe \ - --port 30308 \ + --port 30308 --db-path=./tmp/charlie/db \ --rpc-port 9946 --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp & # Dave ./target/release/dkg-standalone-node --tmp --chain local --validator -lerror --dave --output-path=./tmp/dave/output.log \ --rpc-cors all --rpc-external --rpc-methods=unsafe \ - --port 30309 \ + --port 30309 --db-path=./tmp/dave/db \ --rpc-port 9947 --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp & # Eve ./target/release/dkg-standalone-node --tmp --chain local --validator -linfo --eve --output-path=./tmp/eve/output.log \ --rpc-cors all --rpc-external \ --rpc-port 9948 \ - --port 30310 \ + --port 30310 --db-path=./tmp/eve/db \ -ldkg=debug \ -ldkg_gadget::worker=debug \ -lruntime::dkg_metadata=debug \ diff --git a/standalone/node/src/cli.rs b/standalone/node/src/cli.rs index ea3e43497..15b5f5e70 100644 --- a/standalone/node/src/cli.rs +++ b/standalone/node/src/cli.rs @@ -21,6 +21,8 @@ pub struct Cli { pub subcommand: Option, #[clap(flatten)] pub run: RunCmd, + #[arg(long, short = 'd')] + pub db_path: std::path::PathBuf, #[arg(long, short = 'o')] pub output_path: Option, #[clap(flatten)] diff --git a/standalone/node/src/command.rs b/standalone/node/src/command.rs index 2aa5fc86d..2142273c7 100644 --- a/standalone/node/src/command.rs +++ b/standalone/node/src/command.rs @@ -208,6 +208,7 @@ pub fn run() -> sc_cli::Result<()> { runner.run_node_until_exit(|config| async move { service::new_full(service::RunFullParams { config, + db_path: cli.db_path, debug_output: cli.output_path, relayer_cmd: cli.relayer_cmd, }) diff --git a/standalone/node/src/service.rs b/standalone/node/src/service.rs index 3acc8993b..f6712eae8 100644 --- a/standalone/node/src/service.rs +++ b/standalone/node/src/service.rs @@ -165,12 +165,13 @@ pub fn new_partial( pub struct RunFullParams { pub config: Configuration, pub debug_output: Option, + pub db_path: std::path::PathBuf, pub relayer_cmd: webb_relayer_gadget_cli::WebbRelayerCmd, } /// Builds a new service for a full client. pub fn new_full( - RunFullParams { config, debug_output, relayer_cmd }: RunFullParams, + RunFullParams { config, debug_output, db_path, relayer_cmd }: RunFullParams, ) -> Result { let sc_service::PartialComponents { client, @@ -274,6 +275,7 @@ pub fn new_full( sync_service: sync_service.clone(), prometheus_registry: prometheus_registry.clone(), local_keystore: Some(keystore_container.local_keystore()), + db_path, _block: std::marker::PhantomData::, debug_logger, };