diff --git a/Cargo.lock b/Cargo.lock index e73f5eb58a6472b91fe5cca496716d1bf50813f4..5af30e7cdd0fa35334e5ab256564929618bafd6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,9 @@ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "async-attributes" @@ -110,9 +110,9 @@ dependencies = [ [[package]] name = "async-global-executor" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0659b83a146398616883aa5199cdd1b055ec088a83c9a338eab3534f33f0622e" +checksum = "124ac8c265e407641c3362b8f4d39cdb4e243885b71eef087be27199790f5a3a" dependencies = [ "async-executor", "async-io", @@ -123,9 +123,9 @@ dependencies = [ [[package]] name = "async-graphql" -version = "2.0.4" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a058ea006ad7e2f25b4594cdb5b60da29b28526e9579ef1b1adfad7d5a353d5" +checksum = "6aacd1f33609c3f37792005ddfd9dd40891c6c4553a1d22cc290b3dc664c3ade" dependencies = [ "async-graphql-derive", "async-graphql-parser", @@ -161,9 +161,9 @@ dependencies = [ [[package]] name = "async-graphql-derive" -version = "2.0.4" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed048285ebf1e6e517b62e9cd6a313b941297e9ee56233534f63ac2e8c24abfd" +checksum = "4865ce6f7993b9e06f8cab15ee16e083b7802fb681771510b6d18cc9eb70412c" dependencies = [ "Inflector", "async-graphql-parser", @@ -177,9 +177,9 @@ dependencies = [ [[package]] name = "async-graphql-parser" -version = "2.0.4" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98384ffe6801a3094428f43e799630ccf75edb23a1db6a26d5ee117f3613a9f0" +checksum = "ca660e5dea2757fefec931f34c7babb01ff7eb01756494f66929cbb8411cf98a" dependencies = [ "async-graphql-value", "pest", @@ -190,9 +190,9 @@ dependencies = [ [[package]] name = "async-graphql-value" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b445404350572b3845165a41fd5b509364074ce8daf3dc1bb7867ce139930d26" +checksum = "57d3aa3cd3696ffd8decb10f5053affc78cb33ecfc545e480072bbc600e6723d" dependencies = [ "serde", "serde_json", @@ -227,6 +227,15 @@ dependencies = [ "event-listener", ] +[[package]] +name = "async-oneshot" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f4770cbbff928c30a991de67fb3976f44d8e3e202f8c79ef91b47006e04904" +dependencies = [ + "futures-micro", +] + [[package]] name = "async-std" version = "1.6.5" @@ -238,7 +247,7 @@ dependencies = [ "async-io", "async-mutex", "blocking", - "crossbeam-utils", + "crossbeam-utils 0.7.2", "futures-channel", "futures-core", "futures-io", @@ -278,9 +287,9 @@ dependencies = [ [[package]] name = "async-task" -version = "4.0.2" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ab27c1aa62945039e44edaeee1dc23c74cc0c303dd5fe0fb462a184f1c3a518" +checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" [[package]] name = "async-trait" @@ -449,9 +458,9 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931" +checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf" dependencies = [ "lazy_static", "memchr", @@ -513,6 +522,9 @@ name = "cc" version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" +dependencies = [ + "jobserver", +] [[package]] name = "cfg-if" @@ -620,6 +632,12 @@ dependencies = [ "cache-padded", ] +[[package]] +name = "const_fn" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce90df4c658c62f12d78f7508cf92f9173e5184a539c10bfe54a3107b3ffd0f2" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -634,11 +652,11 @@ checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" [[package]] name = "crc32fast" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", ] [[package]] @@ -679,23 +697,23 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" +checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ - "crossbeam-utils", - "maybe-uninit", + "cfg-if 1.0.0", + "crossbeam-utils 0.8.0", ] [[package]] name = "crossbeam-deque" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", - "maybe-uninit", + "cfg-if 1.0.0", + "crossbeam-epoch 0.9.0", + "crossbeam-utils 0.8.0", ] [[package]] @@ -706,13 +724,27 @@ checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ "autocfg 1.0.1", "cfg-if 0.1.10", - "crossbeam-utils", + "crossbeam-utils 0.7.2", "lazy_static", "maybe-uninit", "memoffset", "scopeguard", ] +[[package]] +name = "crossbeam-epoch" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f" +dependencies = [ + "cfg-if 1.0.0", + "const_fn", + "crossbeam-utils 0.8.0", + "lazy_static", + "memoffset", + "scopeguard", +] + [[package]] name = "crossbeam-utils" version = "0.7.2" @@ -724,6 +756,18 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crossbeam-utils" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5" +dependencies = [ + "autocfg 1.0.1", + "cfg-if 1.0.0", + "const_fn", + "lazy_static", +] + [[package]] name = "crossterm" version = "0.17.7" @@ -734,7 +778,7 @@ dependencies = [ "crossterm_winapi", "lazy_static", "libc", - "mio 0.7.3", + "mio 0.7.4", "parking_lot 0.10.2", "signal-hook", "winapi 0.3.9", @@ -742,9 +786,9 @@ dependencies = [ [[package]] name = "crossterm_winapi" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057b7146d02fb50175fd7dbe5158f6097f33d02831f43b4ee8ae4ddf67b68f5c" +checksum = "c2265c3f8e080075d9b6417aa72293fc71662f34b4af2612d8d1b074d29510db" dependencies = [ "winapi 0.3.9", ] @@ -915,7 +959,7 @@ checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" [[package]] name = "dubp" version = "0.29.0" -source = "git+https://git.duniter.org/libs/dubp-rs-libs#7d397ec510fc8225ea2b563493b36eecc6b5caa9" +source = "git+https://git.duniter.org/libs/dubp-rs-libs#b3b2322240cfcc8af17dc223677dd19c8b20c746" dependencies = [ "dubp-block", "dubp-common", @@ -928,7 +972,7 @@ dependencies = [ [[package]] name = "dubp-block" version = "0.29.0" -source = "git+https://git.duniter.org/libs/dubp-rs-libs#7d397ec510fc8225ea2b563493b36eecc6b5caa9" +source = "git+https://git.duniter.org/libs/dubp-rs-libs#b3b2322240cfcc8af17dc223677dd19c8b20c746" dependencies = [ "dubp-documents", "dubp-documents-parser", @@ -942,7 +986,7 @@ dependencies = [ [[package]] name = "dubp-common" version = "0.29.0" -source = "git+https://git.duniter.org/libs/dubp-rs-libs#7d397ec510fc8225ea2b563493b36eecc6b5caa9" +source = "git+https://git.duniter.org/libs/dubp-rs-libs#b3b2322240cfcc8af17dc223677dd19c8b20c746" dependencies = [ "dup-crypto", "serde", @@ -954,7 +998,7 @@ dependencies = [ [[package]] name = "dubp-documents" version = "0.29.0" -source = "git+https://git.duniter.org/libs/dubp-rs-libs#7d397ec510fc8225ea2b563493b36eecc6b5caa9" +source = "git+https://git.duniter.org/libs/dubp-rs-libs#b3b2322240cfcc8af17dc223677dd19c8b20c746" dependencies = [ "beef", "dubp-wallet", @@ -967,7 +1011,7 @@ dependencies = [ [[package]] name = "dubp-documents-parser" version = "0.29.0" -source = "git+https://git.duniter.org/libs/dubp-rs-libs#7d397ec510fc8225ea2b563493b36eecc6b5caa9" +source = "git+https://git.duniter.org/libs/dubp-rs-libs#b3b2322240cfcc8af17dc223677dd19c8b20c746" dependencies = [ "dubp-documents", "json-pest-parser", @@ -980,7 +1024,7 @@ dependencies = [ [[package]] name = "dubp-wallet" version = "0.29.0" -source = "git+https://git.duniter.org/libs/dubp-rs-libs#7d397ec510fc8225ea2b563493b36eecc6b5caa9" +source = "git+https://git.duniter.org/libs/dubp-rs-libs#b3b2322240cfcc8af17dc223677dd19c8b20c746" dependencies = [ "byteorder", "dubp-common", @@ -1005,11 +1049,14 @@ dependencies = [ name = "duniter-dbex" version = "0.1.0" dependencies = [ + "anyhow", "arrayvec", "comfy-table", "dirs", "dubp", "duniter-dbs", + "duniter-dbs-write-ops", + "fast-threadpool", "rayon", "serde", "serde_json", @@ -1030,11 +1077,13 @@ dependencies = [ "log", "mockall", "once_cell", + "rand 0.7.3", "serde", "serde_json", "smallvec", "tempdir", "thiserror", + "uninit", "unwrap", "zerocopy", ] @@ -1054,6 +1103,7 @@ dependencies = [ "chrono", "dubp", "duniter-dbs", + "fast-threadpool", "log", "resiter", "serde_json", @@ -1121,7 +1171,6 @@ dependencies = [ "fast-threadpool", "flume", "log", - "rand 0.7.3", "resiter", "unwrap", ] @@ -1150,7 +1199,7 @@ dependencies = [ [[package]] name = "dup-crypto" version = "0.29.0" -source = "git+https://git.duniter.org/libs/dubp-rs-libs#7d397ec510fc8225ea2b563493b36eecc6b5caa9" +source = "git+https://git.duniter.org/libs/dubp-rs-libs#b3b2322240cfcc8af17dc223677dd19c8b20c746" dependencies = [ "base64", "bs58", @@ -1213,13 +1262,13 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "fast-threadpool" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3f69f217417e35f8f2c52256c8852dcd72e1933261195d437d5bfc14245793" +checksum = "cf9f76ead92b1c1e372f552dcd2e331fb321d6b16886df58ed7586208e211e14" dependencies = [ + "async-oneshot", "flume", "num_cpus", - "oneshot", ] [[package]] @@ -1339,9 +1388,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8e3078b7b2a8a671cb7a3d17b4760e4181ea243227776ba83fd043b4ca034e" +checksum = "95314d38584ffbfda215621d723e0a3906f032e03ae5551e650058dac83d4797" dependencies = [ "futures-channel", "futures-core", @@ -1354,9 +1403,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a4d35f7401e948629c9c3d6638fb9bf94e0b2121e96c3b428cc4e631f3eb74" +checksum = "0448174b01148032eed37ac4aed28963aaaa8cfa93569a08e5b479bbc6c2c151" dependencies = [ "futures-core", "futures-sink", @@ -1364,15 +1413,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d674eaa0056896d5ada519900dbf97ead2e46a7b6621e8160d79e2f2e1e2784b" +checksum = "18eaa56102984bed2c88ea39026cff3ce3b4c7f508ca970cedf2450ea10d4e46" [[package]] name = "futures-executor" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc709ca1da6f66143b8c9bec8e6260181869893714e9b5a490b169b0414144ab" +checksum = "f5f8e0c9258abaea85e78ebdda17ef9666d390e987f006be6080dfe354b708cb" dependencies = [ "futures-core", "futures-task", @@ -1381,15 +1430,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc94b64bb39543b4e432f1790b6bf18e3ee3b74653c5449f63310e9a74b123c" +checksum = "6e1798854a4727ff944a7b12aa999f58ce7aa81db80d2dfaaf2ba06f065ddd2b" [[package]] name = "futures-lite" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "381a7ad57b1bad34693f63f6f377e1abded7a9c85c9d3eb6771e11c60aaadab9" +checksum = "5e6c079abfac3ab269e2927ec048dabc89d009ebfdda6b8ee86624f30c689658" dependencies = [ "fastrand", "futures-core", @@ -1402,9 +1451,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f57ed14da4603b2554682e9f2ff3c65d7567b53188db96cb71538217fc64581b" +checksum = "e36fccf3fc58563b4a14d265027c627c3b665d7fed489427e88e7cc929559efe" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -1412,26 +1461,32 @@ dependencies = [ "syn", ] +[[package]] +name = "futures-micro" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e9325be55c5581082cd110294fa988c1f920bc573ec370ef201e33c469a95a" + [[package]] name = "futures-sink" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8764258ed64ebc5d9ed185cf86a95db5cac810269c5d20ececb32e0088abbd" +checksum = "0e3ca3f17d6e8804ae5d3df7a7d35b2b3a6fe89dac84b31872720fc3060a0b11" [[package]] name = "futures-task" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd26820a9f3637f1302da8bceba3ff33adbe53464b54ca24d4e2d4f1db30f94" +checksum = "96d502af37186c4fef99453df03e374683f8a1eec9dcc1e66b3b82dc8278ce3c" dependencies = [ "once_cell", ] [[package]] name = "futures-util" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a894a0acddba51a2d49a6f4263b1e64b8c579ece8af50fa86503d52cd1eea34" +checksum = "abcb44342f62e6f3e8ac427b8aa815f724fd705dfad060b18ac7866c15bb8e34" dependencies = [ "futures-channel", "futures-core", @@ -1440,7 +1495,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project", + "pin-project 1.0.1", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -1462,19 +1517,6 @@ version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -[[package]] -name = "generator" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cdc09201b2e8ca1b19290cf7e65de2246b8e91fb6874279722189c4de7b94dc" -dependencies = [ - "cc", - "libc", - "log", - "rustc_version", - "winapi 0.3.9", -] - [[package]] name = "generic-array" version = "0.12.3" @@ -1542,9 +1584,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993f9e0baeed60001cf565546b0d3dbe6a6ad23f2bd31644a133c641eccf6d53" +checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" dependencies = [ "bytes", "fnv", @@ -1557,6 +1599,7 @@ dependencies = [ "tokio", "tokio-util", "tracing", + "tracing-futures", ] [[package]] @@ -1679,7 +1722,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project", + "pin-project 0.4.27", "socket2", "tokio", "tower-service", @@ -1725,11 +1768,11 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66" +checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", ] [[package]] @@ -1756,6 +1799,15 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +[[package]] +name = "jobserver" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.45" @@ -1862,9 +1914,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" +checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" [[package]] name = "liblmdb-sys" @@ -1927,17 +1979,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d0925aed5b12ed59857f438d25a910cf051dbcd4107907be1e7abf6c44ec903" -[[package]] -name = "loom" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed" -dependencies = [ - "cfg-if 0.1.10", - "generator", - "scoped-tls", -] - [[package]] name = "lru" version = "0.6.0" @@ -1961,9 +2002,9 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "maybe-async" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27790c036ea5ec16a39435631eb60449ba2a83ee056b989f8dcd36a2e5c0c5fb" +checksum = "fd1afac51d14f8056cd544c83239b961c464e0a98c2ca65353195df93e636a20" dependencies = [ "proc-macro2", "quote", @@ -2038,9 +2079,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53a6ea5f38c0a48ca42159868c6d8e1bd56c0451238856cc08d58563643bdc3" +checksum = "f8f1c83949125de4a582aa2da15ae6324d91cf6a58a70ea407643941ff98f558" dependencies = [ "libc", "log", @@ -2073,9 +2114,9 @@ dependencies = [ [[package]] name = "mockall" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf52bd480d59ec342893c9c64ace644b4bbb1e184f8217312f0282107a372e4d" +checksum = "41cabea45a7fc0e37093f4f30a5e2b62602253f91791c057d5f0470c63260c3d" dependencies = [ "cfg-if 0.1.10", "downcast", @@ -2088,9 +2129,9 @@ dependencies = [ [[package]] name = "mockall_derive" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f060c7e8d81fa8cf7bfd4a2cc183402d1066c9cba56998e2807b109d8c0ec" +checksum = "7c461918bf7f59eefb1459252756bf2351a995d6bd510d0b2061bd86bcdabfa6" dependencies = [ "cfg-if 0.1.10", "proc-macro2", @@ -2250,9 +2291,9 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "ntapi" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a31937dea023539c72ddae0e3571deadc1414b300483fa7aaec176168cfa9d2" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ "winapi 0.3.9", ] @@ -2343,15 +2384,6 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" -[[package]] -name = "oneshot" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39d7085e4e51b36df4afa83db60d20ad2adf8e8587a193f93c9143bf7b375dec" -dependencies = [ - "loom", -] - [[package]] name = "oorandom" version = "11.1.2" @@ -2496,7 +2528,16 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" dependencies = [ - "pin-project-internal", + "pin-project-internal 0.4.27", +] + +[[package]] +name = "pin-project" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee41d838744f60d959d7074e3afb6b35c7456d0f61cad38a24e35e6553f73841" +dependencies = [ + "pin-project-internal 1.0.1", ] [[package]] @@ -2510,11 +2551,22 @@ dependencies = [ "syn", ] +[[package]] +name = "pin-project-internal" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a4ffa594b66bff340084d4081df649a7dc049ac8d7fc458d8e628bfbbb2f86" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e555d9e657502182ac97b539fb3dae8b79cda19e3e4f8ffb5e8de4f18df93c95" +checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" [[package]] name = "pin-utils" @@ -2536,9 +2588,9 @@ dependencies = [ [[package]] name = "polling" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab773feb154f12c49ffcfd66ab8bdcf9a1843f950db48b0d8be9d4393783b058" +checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" dependencies = [ "cfg-if 0.1.10", "libc", @@ -2813,9 +2865,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf6960dc9a5b4ee8d3e4c5787b4a112a8818e0290a42ff664ad60692fdf2032" +checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" dependencies = [ "autocfg 1.0.1", "crossbeam-deque", @@ -2825,13 +2877,13 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf" +checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" dependencies = [ "crossbeam-channel", "crossbeam-deque", - "crossbeam-utils", + "crossbeam-utils 0.8.0", "lazy_static", "num_cpus", ] @@ -2928,14 +2980,14 @@ dependencies = [ "base64", "blake2b_simd", "constant_time_eq", - "crossbeam-utils", + "crossbeam-utils 0.7.2", ] [[package]] name = "rustc-demangle" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2610b7f643d18c87dff3b489950269617e6601a51f1f05aa5daefee36f64f0b" +checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" [[package]] name = "rustc_version" @@ -3104,7 +3156,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604508c1418b99dfe1925ca9224829bb2a8a9a04dda655cc01fcad46f4ab05ed" dependencies = [ "libc", - "mio 0.7.3", + "mio 0.7.4", "signal-hook-registry", ] @@ -3131,13 +3183,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f72c064e63fbca3138ad07f3588c58093f1684f3a99f60dcfa6d46b87e60fde7" dependencies = [ "crc32fast", - "crossbeam-epoch", - "crossbeam-utils", + "crossbeam-epoch 0.8.2", + "crossbeam-utils 0.7.2", "fs2", "fxhash", "libc", "log", "parking_lot 0.11.0", + "zstd", ] [[package]] @@ -3271,9 +3324,9 @@ checksum = "171758edb47aa306a78dfa4ab9aeb5167405bd4e3dc2b64e88f6a84bbe98bd63" [[package]] name = "syn" -version = "1.0.44" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e03e57e4fcbfe7749842d53e24ccb9aa12b7252dbe5e91d2acad31834c8b8fdd" +checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" dependencies = [ "proc-macro2", "quote", @@ -3407,7 +3460,7 @@ checksum = "6d9e878ad426ca286e4dcae09cbd4e1973a7f8987d97570e2469703dd7f5720c" dependencies = [ "futures-util", "log", - "pin-project", + "pin-project 0.4.27", "tokio", "tungstenite", ] @@ -3480,7 +3533,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" dependencies = [ - "pin-project", + "pin-project 0.4.27", "tracing", ] @@ -3714,7 +3767,7 @@ dependencies = [ "mime", "mime_guess", "multipart", - "pin-project", + "pin-project 0.4.27", "scoped-tls", "serde", "serde_json", @@ -3817,9 +3870,9 @@ dependencies = [ [[package]] name = "wepoll-sys" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142bc2cba3fe88be1a8fcb55c727fa4cd5b0cf2d7438722792e22f26f04bc1e0" +checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff" dependencies = [ "cc", ] @@ -3926,3 +3979,34 @@ dependencies = [ "syn", "synstructure", ] + +[[package]] +name = "zstd" +version = "0.5.3+zstd.1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "2.0.5+zstd.1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "1.4.17+zstd.1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b" +dependencies = [ + "cc", + "glob", + "itertools", + "libc", +] diff --git a/app/lib/blockchain/DuniterBlockchain.ts b/app/lib/blockchain/DuniterBlockchain.ts index a6105de9c502e1c589359d0b7559f8678b1ee16e..17e113f94b23b81f6d57a94ad22f488d6b616e0a 100644 --- a/app/lib/blockchain/DuniterBlockchain.ts +++ b/app/lib/blockchain/DuniterBlockchain.ts @@ -327,9 +327,6 @@ export class DuniterBlockchain { // Saves the block (DAL) await dal.saveBlock(dbb, conf); - // Send block to rust server - dal.rustServer.applyBlock(block); - // Save wot file if (!dal.fs.isMemoryOnly()) { const wotbFilepath = Directory.getWotbFilePath(dal.rootPath); @@ -496,8 +493,8 @@ export class DuniterBlockchain { dal: FileDAL, block?: DBBlock ) { - if (block && block.toBlockDTO) { - dal.rustServer.revertBlock(block.toBlockDTO()); + if (block) { + dal.rustServer.revertBlock(BlockDTO.fromJSONObject(block)); } const blockstamp = [number, hash].join("-"); diff --git a/app/lib/dal/fileDAL.ts b/app/lib/dal/fileDAL.ts index 57122d88c5161fa7b7981ff3a380a53c8e84ce27..7334c653cab9bb2099ca9c5b874bba97918723de 100644 --- a/app/lib/dal/fileDAL.ts +++ b/app/lib/dal/fileDAL.ts @@ -192,9 +192,9 @@ export class FileDAL implements ServerDAO { }; } - async init(conf: ConfDTO) { + async init(conf: ConfDTO, commandName: string | null = null) { // Rust server - this.initRustServer(conf); + this.initRustServer(conf, commandName); // wotb this.wotb = this.params.wotbf(); @@ -232,9 +232,10 @@ export class FileDAL implements ServerDAO { } } - initRustServer(conf: ConfDTO) { + initRustServer(conf: ConfDTO, commandName: string | null = null) { let serverPubkey = conf.pair ? conf.pair.pub : null; let rustServerConf = { + command: commandName, gva: conf.gva, serverPubkey, txsMempoolSize: @@ -1241,8 +1242,12 @@ export class FileDAL implements ServerDAO { async saveBlock(block: DBBlock, conf: ConfDTO) { block.wrong = false; - this.rustServer.applyBlock(block.toBlockDTO()); - await this.saveBlockInFile(block); + try { + this.rustServer.applyBlock(block.toBlockDTO()); + await this.saveBlockInFile(block); + } catch (err) { + throw err; + } } async generateIndexes( diff --git a/index.ts b/index.ts index c0a4b0623db978716e9971ed4a6126297a067129..f7dd1363ab6c0235c833230f192bdde6971a087c 100644 --- a/index.ts +++ b/index.ts @@ -397,7 +397,7 @@ export class Stack { throw `Command ${command.name} does not implement onConfiguredExecute nor onDatabaseExecute.` } // Second possible class of commands: post-service - await server.initDAL(conf); + await server.initDAL(conf, command.name); /** * Service injection diff --git a/neon/native/server.d.ts b/neon/native/server.d.ts index 0f6bb45ffd55884fa25e46e8d900f7ae0ffc8b28..e17a0bfd852ce9ffa5d7e1490d3b604487c22d39 100644 --- a/neon/native/server.d.ts +++ b/neon/native/server.d.ts @@ -3,6 +3,7 @@ import { TransactionDTOV10 } from './transaction'; export class RustServerConf { + command: string | null gva: GvaConf | undefined serverPubkey: string | null txsMempoolSize: number diff --git a/neon/native/src/server.rs b/neon/native/src/server.rs index 6e4e860574b11227b1486da56836d15cbc4f37b5..017578783a965a8aa53aee2ba961c55043c0f24d 100644 --- a/neon/native/src/server.rs +++ b/neon/native/src/server.rs @@ -51,6 +51,7 @@ declare_types! { } else { None }; + let command_name = rust_server_conf_stringified.command_name; let server_pubkey = if let Some(server_pubkey_str) = rust_server_conf_stringified.server_pubkey { into_neon_res(&mut cx, PublicKey::from_base58(&server_pubkey_str))? } else { @@ -79,10 +80,10 @@ declare_types! { None }; if let Some(home_path) = home_path_opt { - let server = DuniterServer::start(conf, Some(home_path.as_path()), std::env!("CARGO_PKG_VERSION")); + let server = DuniterServer::start(command_name, conf, Some(home_path.as_path()), std::env!("CARGO_PKG_VERSION")); Ok(RustServer { server }) } else { - let server = DuniterServer::start(conf, None, std::env!("CARGO_PKG_VERSION")); + let server = DuniterServer::start(command_name, conf, None, std::env!("CARGO_PKG_VERSION")); Ok(RustServer { server }) } } @@ -144,10 +145,10 @@ declare_types! { let block_stringified: dubp::block::DubpBlockV10Stringified = neon_serde::from_value(&mut cx, block_js)?; - let this = cx.this(); + let mut this = cx.this(); let res = { let guard = cx.lock(); - let server = this.borrow(&guard); + let mut server = this.borrow_mut(&guard); server.server.revert_block(block_stringified) }.map(|()| cx.undefined().upcast()); into_neon_res(&mut cx, res) @@ -201,10 +202,10 @@ declare_types! { let block_stringified: dubp::block::DubpBlockV10Stringified = neon_serde::from_value(&mut cx, block_js)?; - let this = cx.this(); + let mut this = cx.this(); let res = { let guard = cx.lock(); - let server = this.borrow(&guard); + let mut server = this.borrow_mut(&guard); server.server.apply_block(block_stringified) }.map(|()| cx.undefined().upcast()); into_neon_res(&mut cx, res) @@ -214,10 +215,10 @@ declare_types! { let blocks_stringified: Vec<dubp::block::DubpBlockV10Stringified> = neon_serde::from_value(&mut cx, blocks_js)?; - let this = cx.this(); + let mut this = cx.this(); let res = { let guard = cx.lock(); - let server = this.borrow(&guard); + let mut server = this.borrow_mut(&guard); server.server.apply_chunk_of_blocks(blocks_stringified) }.map(|()| cx.undefined().upcast()); into_neon_res(&mut cx, res) @@ -293,6 +294,7 @@ declare_types! { #[derive(Deserialize, Serialize)] #[serde(rename_all = "camelCase")] struct RustServerConfStringified { + command_name: Option<String>, gva: Option<GvaConfStringified>, server_pubkey: Option<String>, txs_mempool_size: u32, diff --git a/rust-bins/duniter-dbex/Cargo.toml b/rust-bins/duniter-dbex/Cargo.toml index a62fcacba5049a4bb506d480a41d58c3f5cd52d5..f491939c9c4313cef8527a2d75d29712c354370e 100644 --- a/rust-bins/duniter-dbex/Cargo.toml +++ b/rust-bins/duniter-dbex/Cargo.toml @@ -18,11 +18,14 @@ name = "dex" structopt = "0.3.16" [dependencies] +anyhow = "1.0.33" arrayvec = "0.5.1" comfy-table = "1.0.0" dirs = "3.0.1" dubp = { version = "0.29.0" } duniter-dbs = { path = "../../rust-libs/duniter-dbs", default-features = false, features = ["explorer", "leveldb_backend", "sled_backend"] } +duniter-dbs-write-ops = { path = "../../rust-libs/duniter-dbs-write-ops", default-features = false, features = ["explorer", "leveldb_backend", "sled_backend"] } +fast-threadpool = "0.2.1" rayon = "1.3.1" serde_json = "1.0.53" structopt = "0.3.16" diff --git a/rust-bins/duniter-dbex/README.md b/rust-bins/duniter-dbex/README.md index f49c48fd89510f6efa24c7b495396cac545d7d21..99d1ab982d24dad51125d5304f882acda329c085 100644 --- a/rust-bins/duniter-dbex/README.md +++ b/rust-bins/duniter-dbex/README.md @@ -20,6 +20,6 @@ Bash autocompletion script is available here : `target/release/dex.bash` To generate the autocompletion script for your shell, recompile with env var `COMPLETION_SHELL`. -For exemple for fish : `COMPLETION_SHELL=fish cargo build --release -p duniter-dbex` +For example for fish : `COMPLETION_SHELL=fish cargo build --release -p duniter-dbex` The autocompletion script can be found in : `target/release/` diff --git a/rust-bins/duniter-dbex/src/cli.rs b/rust-bins/duniter-dbex/src/cli.rs index 1544fe20ded8da981e3c2ce10e7337efa28faae2..e98ee25e2c44f06f620797a52bd275be8e8d92bf 100644 --- a/rust-bins/duniter-dbex/src/cli.rs +++ b/rust-bins/duniter-dbex/src/cli.rs @@ -28,7 +28,7 @@ pub struct Opt { pub home: Option<PathBuf>, /// database - #[structopt(default_value = "bc_v1", possible_values = &["bc_v1", "gva_v1", "txs_mp_v2"])] + #[structopt(default_value = "bc_v1", possible_values = &["bc_v1", "bc_v2", "gva_v1", "txs_mp_v2"])] pub database: Database, #[structopt(subcommand)] @@ -38,6 +38,7 @@ pub struct Opt { #[derive(Debug)] pub enum Database { BcV1, + BcV2, GvaV1, TxsMpV2, } @@ -48,6 +49,7 @@ impl FromStr for Database { fn from_str(s: &str) -> Result<Self, Self::Err> { match s { "bc_v1" => Ok(Self::BcV1), + "bc_v2" => Ok(Self::BcV2), "gva_v1" => Ok(Self::GvaV1), "txs_mp_v2" => Ok(Self::TxsMpV2), _ => unreachable!(), @@ -103,6 +105,8 @@ pub enum SubCommand { }, /// Show database schema Schema, + /// Fill rust dbs from js db content + Migrate, } #[derive(Clone, Copy, Debug)] diff --git a/rust-bins/duniter-dbex/src/main.rs b/rust-bins/duniter-dbex/src/main.rs index cf655c5c94b3c6255151f20909daf38076103882..f203b5ddda95b571e1ac54d7e004c7d67771e6e4 100644 --- a/rust-bins/duniter-dbex/src/main.rs +++ b/rust-bins/duniter-dbex/src/main.rs @@ -23,12 +23,15 @@ )] mod cli; +mod migrate; mod print_found_data; mod stringify_json_value; use self::cli::{Database, Opt, OutputFormat, SubCommand}; use self::stringify_json_value::stringify_json_value; +use anyhow::anyhow; use comfy_table::Table; +use duniter_dbs::bc_v2::{BcV2Db, BcV2DbWritable}; use duniter_dbs::kv_typed::backend::sled; use duniter_dbs::kv_typed::prelude::*; use duniter_dbs::prelude::*; @@ -50,7 +53,7 @@ use structopt::StructOpt; const DATA_DIR: &str = "data"; const TOO_MANY_ENTRIES_ALERT: usize = 5_000; -fn main() -> Result<(), String> { +fn main() -> anyhow::Result<()> { let opt = Opt::from_args(); let home = if let Some(home) = opt.home { @@ -58,8 +61,7 @@ fn main() -> Result<(), String> { } else { dirs::config_dir() .ok_or_else(|| { - "Fail to auto find duniter's home directory, please specify it explicitly." - .to_owned() + anyhow!("Fail to auto find duniter's home directory, please specify it explicitly.") })? .as_path() .join("duniter") @@ -75,39 +77,47 @@ fn main() -> Result<(), String> { let data_path = profile_path.as_path().join(DATA_DIR); if !data_path.exists() { - return Err(format!( + return Err(anyhow!( "Path '{}' don't exist !", data_path.to_str().expect("non-UTF-8 strings not supported") )); } - let open_db_start_time = Instant::now(); - match opt.database { - Database::BcV1 => apply_subcommand( - BcV1Db::<LevelDb>::open(LevelDbConf { - db_path: data_path.as_path().join("leveldb"), - ..Default::default() - }) - .map_err(|e| format!("{}", e))?, - opt.cmd, - open_db_start_time, - ), - Database::GvaV1 => apply_subcommand( - GvaV1Db::<Sled>::open( - sled::Config::default().path(data_path.as_path().join("gva_v1_sled")), - ) - .map_err(|e| format!("{}", e))?, - opt.cmd, - open_db_start_time, - ), - Database::TxsMpV2 => apply_subcommand( - TxsMpV2Db::<Sled>::open( - sled::Config::default().path(data_path.as_path().join("txs_mp_v2_sled")), - ) - .map_err(|e| format!("{}", e))?, - opt.cmd, - open_db_start_time, - ), + if let SubCommand::Migrate = opt.cmd { + migrate::migrate(profile_path) + } else { + let open_db_start_time = Instant::now(); + match opt.database { + Database::BcV1 => apply_subcommand( + BcV1Db::<LevelDb>::open(LevelDbConf { + db_path: data_path.as_path().join("leveldb"), + ..Default::default() + })?, + opt.cmd, + open_db_start_time, + ), + Database::BcV2 => apply_subcommand( + BcV2Db::<Sled>::open( + sled::Config::default().path(data_path.as_path().join("bc_v2_sled")), + )?, + opt.cmd, + open_db_start_time, + ), + Database::GvaV1 => apply_subcommand( + GvaV1Db::<Sled>::open( + sled::Config::default().path(data_path.as_path().join("gva_v1_sled")), + )?, + opt.cmd, + open_db_start_time, + ), + Database::TxsMpV2 => apply_subcommand( + TxsMpV2Db::<Sled>::open( + sled::Config::default().path(data_path.as_path().join("txs_mp_v2_sled")), + )?, + opt.cmd, + open_db_start_time, + ), + } } } @@ -115,7 +125,7 @@ fn apply_subcommand<DB: DbExplorable>( db: DB, cmd: SubCommand, open_db_start_time: Instant, -) -> Result<(), String> { +) -> anyhow::Result<()> { let duration = open_db_start_time.elapsed(); println!( "Database opened in {}.{:06} seconds.", @@ -126,10 +136,8 @@ fn apply_subcommand<DB: DbExplorable>( match cmd { SubCommand::Count { collection } => { - if let ExplorerActionResponse::Count(count) = db - .explore(&collection, ExplorerAction::Count, stringify_json_value) - .map_err(|e| format!("{}", e))? - .map_err(|e| e.0)? + if let ExplorerActionResponse::Count(count) = + db.explore(&collection, ExplorerAction::Count, stringify_json_value)?? { let duration = start_time.elapsed(); println!( @@ -141,15 +149,11 @@ fn apply_subcommand<DB: DbExplorable>( } } SubCommand::Get { collection, key } => { - if let ExplorerActionResponse::Get(value_opt) = db - .explore( - &collection, - ExplorerAction::Get { key: &key }, - stringify_json_value, - ) - .map_err(|e| format!("{}", e))? - .map_err(|e| e.0)? - { + if let ExplorerActionResponse::Get(value_opt) = db.explore( + &collection, + ExplorerAction::Get { key: &key }, + stringify_json_value, + )?? { if let Some(value) = value_opt { println!("\n{}", value) } else { @@ -189,23 +193,19 @@ fn apply_subcommand<DB: DbExplorable>( } else { vec![] }; - if let ExplorerActionResponse::Find(entries) = db - .explore( - &collection, - ExplorerAction::Find { - key_min: start, - key_max: end, - key_regex: opt_string_to_res_opt_regex(key_regex)?, - value_regex: value_regex_opt, - limit, - reverse, - step, - }, - stringify_json_value, - ) - .map_err(|e| format!("{}", e))? - .map_err(|e| e.0)? - { + if let ExplorerActionResponse::Find(entries) = db.explore( + &collection, + ExplorerAction::Find { + key_min: start, + key_max: end, + key_regex: opt_string_to_res_opt_regex(key_regex)?, + value_regex: value_regex_opt, + limit, + reverse, + step, + }, + stringify_json_value, + )?? { let duration = start_time.elapsed(); println!( "Search performed in {}.{:06} seconds.\n\n{} entries found.", @@ -214,16 +214,13 @@ fn apply_subcommand<DB: DbExplorable>( entries.len() ); - if !too_many_entries(entries.len(), output_file.is_none()) - .map_err(|e| format!("{}", e))? - { + if !too_many_entries(entries.len(), output_file.is_none())? { return Ok(()); } let start_print = Instant::now(); if let Some(output_file) = output_file { - let mut file = - File::create(output_file.as_path()).map_err(|e| format!("{}", e))?; + let mut file = File::create(output_file.as_path())?; //let mut file_buffer = BufWriter::new(file); print_found_data::print_found_data( @@ -237,8 +234,7 @@ fn apply_subcommand<DB: DbExplorable>( only_properties: properties, }, captures_headers, - ) - .map_err(|e| format!("{}", e))?; + )?; //file_buffer.flush().map_err(|e| format!("{}", e))?; let export_duration = start_print.elapsed(); @@ -262,8 +258,7 @@ fn apply_subcommand<DB: DbExplorable>( only_properties: properties, }, captures_headers, - ) - .map_err(|e| format!("{}", e))?; + )?; let print_duration = start_print.elapsed(); println!( "Search results were displayed in {}.{:06} seconds.", @@ -276,6 +271,7 @@ fn apply_subcommand<DB: DbExplorable>( SubCommand::Schema => { show_db_schema(db.list_collections()); } + SubCommand::Migrate => unreachable!(), }; Ok(()) @@ -313,9 +309,9 @@ fn show_db_schema(collections_names: Vec<(&'static str, &'static str, &'static s } #[inline] -fn opt_string_to_res_opt_regex(str_regex_opt: Option<String>) -> Result<Option<Regex>, String> { +fn opt_string_to_res_opt_regex(str_regex_opt: Option<String>) -> anyhow::Result<Option<Regex>> { if let Some(str_regex) = str_regex_opt { - Ok(Some(Regex::new(&str_regex).map_err(|e| format!("{}", e))?)) + Ok(Some(Regex::new(&str_regex)?)) } else { Ok(None) } diff --git a/rust-bins/duniter-dbex/src/migrate.rs b/rust-bins/duniter-dbex/src/migrate.rs new file mode 100644 index 0000000000000000000000000000000000000000..3146ed0c7e772a622dfdec12868b201c03048c24 --- /dev/null +++ b/rust-bins/duniter-dbex/src/migrate.rs @@ -0,0 +1,157 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// 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 <https://www.gnu.org/licenses/>. + +use crate::*; +use dubp::{ + block::parser::parse_json_block_from_serde_value, block::parser::ParseJsonBlockError, + block::prelude::DubpBlockTrait, block::DubpBlock, common::prelude::BlockNumber, +}; +use duniter_dbs::BcV1DbReadable; +use fast_threadpool::{ThreadPool, ThreadPoolConfig}; +use std::path::PathBuf; + +const CHUNK_SIZE: usize = 250; + +pub(crate) fn migrate(profile_path: PathBuf) -> anyhow::Result<()> { + let start_time = Instant::now(); + let dbs = duniter_dbs::open_dbs(Some(profile_path.as_path())); + + let data_path = profile_path.join(crate::DATA_DIR); + let duniter_js_db = BcV1Db::<LevelDb>::open(LevelDbConf { + db_path: data_path.as_path().join("leveldb"), + ..Default::default() + })?; + + let dbs_pool = ThreadPool::start(ThreadPoolConfig::default(), dbs).into_sync_handler(); + + if let Some(target) = get_target_block_number(&duniter_js_db)? { + println!("target block: #{}", target.0); + /*let chunk_count = if (target.0 as usize + 1) % CHUNK_SIZE == 0 { + (target.0 as usize + 1) / CHUNK_SIZE + } else { + (target.0 as usize / CHUNK_SIZE) + 1 + };*/ + + let (s, r) = std::sync::mpsc::channel(); + let reader_handle = std::thread::spawn(move || { + duniter_js_db.main_blocks().iter(.., |it| { + it.values() + .map(|block_res| s.send(block_res).map_err(|_| anyhow!("fail to send"))) + .collect::<anyhow::Result<()>>() + }) + }); + let (s2, r2) = std::sync::mpsc::channel(); + let parser_handle = std::thread::spawn(move || { + let target_u64 = target.0 as u64; + let mut db_blocks = Vec::with_capacity(CHUNK_SIZE); + while let Ok(db_block_res) = r.recv() { + let db_block = db_block_res?; + let db_block_number = db_block.number; + db_blocks.push(db_block); + if db_blocks.len() == CHUNK_SIZE || db_block_number == target_u64 { + let blocks = std::mem::take(&mut db_blocks) + .into_par_iter() + .map(|db_block| match serde_json::to_value(&db_block) { + Ok(json_block) => { + match parse_json_block_from_serde_value(&json_block) { + Ok(block) => match block { + DubpBlock::V10(block_v10) => Ok(block_v10), + }, + Err(e) => Err(anyhow::Error::new::<ParseJsonBlockError>(e)), + } + } + Err(e) => Err(anyhow::Error::new::<serde_json::Error>(e)), + }) + .collect::<anyhow::Result<Vec<_>>>()?; + s2.send(blocks).map_err(|_| anyhow!("fail to send"))?; + db_blocks.reserve_exact(CHUNK_SIZE); + } + } + Ok::<(), anyhow::Error>(()) + }); + + let mut current = None; + while let Ok(chunk) = r2.recv() { + if !chunk.is_empty() { + println!( + "Apply chunk #{}-#{} ..", + chunk[0].number(), + chunk[chunk.len() - 1].number() + ); + current = Some(duniter_dbs_write_ops::apply_block::apply_chunk( + current, &dbs_pool, chunk, true, + )?); + } + } + + reader_handle.join().expect("reader thread panic")?; + parser_handle.join().expect("parser thread panic")?; + + dbs_pool.execute(|dbs| { + dbs.bc_db.save()?; + dbs.gva_db.save()?; + Ok::<(), KvError>(()) + })??; + + if let Some(current) = current { + if current.number != target.0 { + Err(anyhow::anyhow!("Migration fail: current != target")) + } else { + let duration = start_time.elapsed(); + println!( + "Migration successfully completed on {} seconds.", + duration.as_secs() + ); + Ok(()) + } + } else { + Err(anyhow::anyhow!("Migration fail: rust dbs are empty")) + } + } else { + Err(anyhow::anyhow!("Empty blockchain")) + } +} + +fn get_target_block_number(duniter_js_db: &BcV1Db<LevelDb>) -> KvResult<Option<BlockNumber>> { + duniter_js_db.main_blocks().iter(.., |it| { + it.reverse() + .keys() + .map(|k_res| k_res.map(|bn| bn.0)) + .next_res() + }) +} + +/*fn get_chunk(duniter_js_db: &BcV1Db<LevelDb>, i: u32) -> anyhow::Result<Vec<DubpBlockV10>> { + let start = BlockNumberKeyV1(BlockNumber(i * CHUNK_SIZE)); + let end = BlockNumberKeyV1(BlockNumber(((i + 1) * CHUNK_SIZE) - 1)); + println!("get_chunk({}): range {}..{}", i, start.0, end.0); + let db_blocks = duniter_js_db + .main_blocks() + .iter(start..=end, |it| it.values().collect::<KvResult<Vec<_>>>())?; + + db_blocks + .into_par_iter() + .map(|db_block| match serde_json::to_value(&db_block) { + Ok(json_block) => match parse_json_block_from_serde_value(&json_block) { + Ok(block) => match block { + DubpBlock::V10(block_v10) => Ok(block_v10), + }, + Err(e) => Err(anyhow::Error::new::<ParseJsonBlockError>(e)), + }, + Err(e) => Err(anyhow::Error::new::<serde_json::Error>(e)), + }) + .collect() +} +*/ diff --git a/rust-libs/duniter-dbs-read-ops/src/lib.rs b/rust-libs/duniter-dbs-read-ops/src/lib.rs index c5bce22f260fc26aea9e8e989edda907a9ebbbf9..1fd64539477fcfe75f5acf4c3d7071f9f9484fc4 100644 --- a/rust-libs/duniter-dbs-read-ops/src/lib.rs +++ b/rust-libs/duniter-dbs-read-ops/src/lib.rs @@ -28,8 +28,11 @@ pub mod utxos; use dubp::common::crypto::hashs::Hash; use dubp::common::crypto::keys::ed25519::PublicKey; use dubp::documents::transaction::TransactionDocumentV10; +use duniter_dbs::bc_v2::BcV2DbReadable; use duniter_dbs::{ kv_typed::prelude::*, + BlockMetaV2, //TxsMpV2DbWritable, + //WalletConditionsV2 //BlockNumberArrayV2, BlockNumberKeyV2, SourceAmountValV2, UtxosOfScriptV1 //GvaV1Db, GvaV1DbReadable, @@ -40,6 +43,10 @@ use duniter_dbs::{ TxDbV2, //TxsMpV2Db, TxsMpV2DbReadable, - //TxsMpV2DbWritable, - //WalletConditionsV2, }; + +pub fn get_current_block_meta<BcDb: BcV2DbReadable>(bc_db: &BcDb) -> KvResult<Option<BlockMetaV2>> { + bc_db + .blocks_meta() + .iter(.., |it| it.reverse().values().next_res()) +} diff --git a/rust-libs/duniter-dbs-write-ops/Cargo.toml b/rust-libs/duniter-dbs-write-ops/Cargo.toml index c6013efb36f0bf1fae8967c391b8537e3740b80c..f78eb6dc660428588c9cca9e3cda6383b1758c05 100644 --- a/rust-libs/duniter-dbs-write-ops/Cargo.toml +++ b/rust-libs/duniter-dbs-write-ops/Cargo.toml @@ -15,8 +15,16 @@ path = "src/lib.rs" chrono = "0.4.19" dubp = { version = "0.29.0" } duniter-dbs = { path = "../duniter-dbs" } +fast-threadpool = "0.2.1" log = "0.4.11" resiter = "0.4.0" [dev-dependencies] serde_json = "1.0.53" + +[features] +default = ["sled_backend"] + +explorer = ["duniter-dbs/explorer"] +leveldb_backend = ["duniter-dbs/leveldb_backend"] +sled_backend = ["duniter-dbs/sled_backend"] diff --git a/rust-libs/duniter-dbs-write-ops/src/apply_block.rs b/rust-libs/duniter-dbs-write-ops/src/apply_block.rs new file mode 100644 index 0000000000000000000000000000000000000000..9e78303c896d53fb6d9f901fe31320164df4d001 --- /dev/null +++ b/rust-libs/duniter-dbs-write-ops/src/apply_block.rs @@ -0,0 +1,183 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// 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 <https://www.gnu.org/licenses/>. + +use crate::*; + +pub fn apply_block( + block: DubpBlockV10, + current_opt: Option<BlockMetaV2>, + dbs_pool: &fast_threadpool::ThreadPoolSyncHandler<DuniterDbs>, + gva: bool, + throw_chainability: bool, +) -> KvResult<BlockMetaV2> { + if let Some(current) = current_opt { + if block.number().0 == current.number + 1 { + apply_block_inner(dbs_pool, Arc::new(block), gva) + } else if throw_chainability { + Err(KvError::Custom( + format!( + "block #{} not chainable on current #{}", + block.number().0, + current.number + ) + .into(), + )) + } else { + Ok(current) + } + } else if block.number() == BlockNumber(0) { + apply_block_inner(dbs_pool, Arc::new(block), gva) + } else { + Err(KvError::Custom( + "Try to apply non genesis block on empty blockchain".into(), + )) + } +} + +#[inline(always)] +pub fn apply_chunk( + current_opt: Option<BlockMetaV2>, + dbs_pool: &fast_threadpool::ThreadPoolSyncHandler<DuniterDbs>, + blocks: Vec<DubpBlockV10>, + gva: bool, +) -> KvResult<BlockMetaV2> { + verify_chunk_chainability(current_opt, &blocks)?; + apply_chunk_inner(dbs_pool, Arc::new(blocks), gva) +} + +fn verify_chunk_chainability( + current_opt: Option<BlockMetaV2>, + blocks: &[DubpBlockV10], +) -> KvResult<()> { + if let Some(mut current) = current_opt { + for block in blocks { + if block.number().0 == current.number + 1 { + current.number += 1; + } else { + return Err(KvError::Custom( + format!( + "block #{} not chainable on current #{}", + blocks[0].number().0, + current.number + ) + .into(), + )); + } + } + Ok(()) + } else if blocks[0].number() == BlockNumber(0) { + let mut current_number = 0; + for block in &blocks[1..] { + if block.number().0 == current_number + 1 { + current_number += 1; + } else { + return Err(KvError::Custom( + format!( + "block #{} not chainable on current #{}", + block.number().0, + current_number + ) + .into(), + )); + } + } + Ok(()) + } else { + Err(KvError::Custom( + "Try to apply non genesis block on empty blockchain".into(), + )) + } +} + +fn apply_block_inner( + dbs_pool: &fast_threadpool::ThreadPoolSyncHandler<DuniterDbs>, + block: Arc<DubpBlockV10>, + gva: bool, +) -> KvResult<BlockMetaV2> { + // Bc + let block_arc = Arc::clone(&block); + let bc_recv = dbs_pool + .launch(move |dbs| crate::bc::apply_block(&dbs.bc_db, &block_arc)) + .expect("dbs pool disconnected"); + //TxsMp + let block_arc = Arc::clone(&block); + let txs_mp_recv = dbs_pool + .launch(move |dbs| { + crate::txs_mp::apply_block(block_arc.transactions(), &dbs.txs_mp_db)?; + Ok::<_, KvError>(()) + }) + .expect("dbs pool disconnected"); + // Gva + if gva { + let block_arc = Arc::clone(&block); + dbs_pool + .execute(move |dbs| { + crate::gva::apply_block(&block_arc, &dbs.gva_db)?; + Ok::<_, KvError>(()) + }) + .expect("dbs pool disconnected")?; + } + txs_mp_recv.join().expect("dbs pool disconnected")?; + bc_recv.join().expect("dbs pool disconnected") +} + +fn apply_chunk_inner( + dbs_pool: &fast_threadpool::ThreadPoolSyncHandler<DuniterDbs>, + blocks: Arc<Vec<DubpBlockV10>>, + gva: bool, +) -> KvResult<BlockMetaV2> { + // Bc + let blocks_len = blocks.len(); + let blocks_arc = Arc::clone(&blocks); + //log::info!("apply_chunk: launch bc job..."); + let bc_handle = dbs_pool + .launch(move |dbs| { + for block in &blocks_arc[..(blocks_len - 1)] { + crate::bc::apply_block(&dbs.bc_db, block)?; + } + crate::bc::apply_block(&dbs.bc_db, &blocks_arc[blocks_len - 1]) + }) + .expect("apply_chunk_inner:bc: dbs pool disconnected"); + //TxsMp + let blocks_arc = Arc::clone(&blocks); + //log::info!("apply_chunk: launch txs_mp job..."); + let txs_mp_handle = dbs_pool + .launch(move |dbs| { + for block in blocks_arc.deref() { + crate::txs_mp::apply_block(block.transactions(), &dbs.txs_mp_db)?; + } + Ok::<_, KvError>(()) + }) + .expect("apply_chunk_inner:txs_mp: dbs pool disconnected"); + // Gva + if gva { + let blocks_arc = Arc::clone(&blocks); + //log::info!("apply_chunk: launch gva job..."); + dbs_pool + .execute(move |dbs| { + for block in blocks_arc.deref() { + crate::gva::apply_block(&block, &dbs.gva_db)?; + } + Ok::<_, KvError>(()) + }) + .expect("apply_chunk_inner:gva: dbs pool disconnected")?; + //log::info!("apply_chunk: gva job finish."); + } + txs_mp_handle + .join() + .expect("txs_mp_recv: dbs pool disconnected")?; + //log::info!("apply_chunk: txs_mp job finish."); + bc_handle.join().expect("bc_recv: dbs pool disconnected") +} diff --git a/rust-libs/duniter-dbs-write-ops/src/bc.rs b/rust-libs/duniter-dbs-write-ops/src/bc.rs new file mode 100644 index 0000000000000000000000000000000000000000..3898eaff1ddcb93db11d0cb424faba70cfd8f864 --- /dev/null +++ b/rust-libs/duniter-dbs-write-ops/src/bc.rs @@ -0,0 +1,104 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// 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 <https://www.gnu.org/licenses/>. + +mod identities; +mod txs; +mod uds; + +use crate::*; +use duniter_dbs::bc_v2::BcV2DbWritable; + +// ["blocks_meta", blocks_meta, BlockNumberKeyV2, BlockMetaV2,], +// ["identities", identities, PubKeyKeyV2, IdtyDbV2,], + +pub fn revert_block<B: Backend>( + bc_db: &duniter_dbs::bc_v2::BcV2Db<B>, + block: DubpBlockV10, +) -> KvResult<Option<BlockMetaV2>> { + ( + bc_db.blocks_meta_write(), + bc_db.identities_write(), + bc_db.uds_write(), + bc_db.uds_reval_write(), + ) + .write( + |(mut blocks_meta, mut identities, mut uds, mut uds_reval)| { + txs::revert_txs::<B>(block.transactions(), &mut uds)?; + if block.dividend().is_some() { + uds::revert_uds::<B>( + block.number(), + &mut identities, + &mut uds, + &mut uds_reval, + )?; + } + identities::revert_identities::<B>(&block, &mut identities)?; + blocks_meta.remove(BlockNumberKeyV2(block.number())); + Ok(if block.number() == BlockNumber(0) { + None + } else { + blocks_meta.get(&BlockNumberKeyV2(BlockNumber(block.number().0 - 1)))? + }) + }, + ) +} + +pub fn apply_block<B: Backend>( + bc_db: &duniter_dbs::bc_v2::BcV2Db<B>, + block: &DubpBlockV10, +) -> KvResult<BlockMetaV2> { + //log::info!("apply_block #{}", block.number().0); + let block_meta = BlockMetaV2 { + version: 10, + number: block.number().0, + hash: block.hash().0, + issuer: block.issuer(), + signature: block.signature(), + inner_hash: block.inner_hash(), + previous_hash: block.previous_hash(), + pow_min: block.pow_min() as u32, + members_count: block.members_count() as u64, + issuers_count: block.issuers_count() as u32, + median_time: block.common_time(), + dividend: block.dividend(), + ..Default::default() + }; + + ( + bc_db.blocks_meta_write(), + bc_db.identities_write(), + bc_db.uds_write(), + bc_db.uds_reval_write(), + ) + .write( + |(mut blocks_meta, mut identities, mut uds, mut uds_reval)| { + blocks_meta.upsert(BlockNumberKeyV2(block.number()), block_meta); + identities::update_identities::<B>(&block, &mut identities)?; + if let Some(dividend) = block.dividend() { + uds::create_uds::<B>( + block.number(), + dividend, + &mut identities, + &mut uds, + &mut uds_reval, + )?; + } + txs::apply_txs::<B>(block.transactions(), &mut uds)?; + Ok(()) + }, + )?; + + Ok(block_meta) +} diff --git a/rust-libs/duniter-dbs-write-ops/src/bc/identities.rs b/rust-libs/duniter-dbs-write-ops/src/bc/identities.rs new file mode 100644 index 0000000000000000000000000000000000000000..ed42c5014413bae6f5b1d2d291c2e835216e1f49 --- /dev/null +++ b/rust-libs/duniter-dbs-write-ops/src/bc/identities.rs @@ -0,0 +1,95 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// 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 <https://www.gnu.org/licenses/>. + +use crate::*; +use duniter_dbs::bc_v2::IdentityEvent; +use duniter_dbs::IdtyDbV2; + +pub(crate) fn update_identities<B: Backend>( + block: &DubpBlockV10, + identities: &mut TxColRw<B::Col, IdentityEvent>, +) -> KvResult<()> { + for idty in block.identities() { + let pubkey = idty.issuers()[0]; + let username = idty.username().to_owned(); + identities.upsert( + PubKeyKeyV2(pubkey), + IdtyDbV2 { + member: true, + username, + }, + ) + } + for mb in block.joiners() { + let pubkey = mb.issuers()[0]; + let username = mb.identity_username().to_owned(); + identities.upsert( + PubKeyKeyV2(pubkey), + IdtyDbV2 { + member: true, + username, + }, + ) + } + for revo in block.revoked() { + let pubkey = revo.issuer; + if let Some(mut idty) = identities.get(&PubKeyKeyV2(pubkey))? { + idty.member = false; + identities.upsert(PubKeyKeyV2(pubkey), idty) + } + } + for pubkey in block.excluded().iter().copied() { + if let Some(mut idty) = identities.get(&PubKeyKeyV2(pubkey))? { + idty.member = false; + identities.upsert(PubKeyKeyV2(pubkey), idty) + } + } + Ok(()) +} + +pub(crate) fn revert_identities<B: Backend>( + block: &DubpBlockV10, + identities: &mut TxColRw<B::Col, IdentityEvent>, +) -> KvResult<()> { + for mb in block.joiners() { + let pubkey = mb.issuers()[0]; + let username = mb.identity_username().to_owned(); + identities.upsert( + PubKeyKeyV2(pubkey), + IdtyDbV2 { + member: false, + username, + }, + ) + } + for idty in block.identities() { + let pubkey = idty.issuers()[0]; + identities.remove(PubKeyKeyV2(pubkey)); + } + for revo in block.revoked() { + let pubkey = revo.issuer; + if let Some(mut idty) = identities.get(&PubKeyKeyV2(pubkey))? { + idty.member = true; + identities.upsert(PubKeyKeyV2(pubkey), idty) + } + } + for pubkey in block.excluded().iter().copied() { + if let Some(mut idty) = identities.get(&PubKeyKeyV2(pubkey))? { + idty.member = true; + identities.upsert(PubKeyKeyV2(pubkey), idty) + } + } + Ok(()) +} diff --git a/rust-libs/duniter-dbs-write-ops/src/bc/txs.rs b/rust-libs/duniter-dbs-write-ops/src/bc/txs.rs new file mode 100644 index 0000000000000000000000000000000000000000..5e4b35a9533f1b08bfe989fc22b8090b14515809 --- /dev/null +++ b/rust-libs/duniter-dbs-write-ops/src/bc/txs.rs @@ -0,0 +1,53 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// 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 <https://www.gnu.org/licenses/>. + +use crate::*; +use duniter_dbs::{bc_v2::UdEvent, UdIdV2}; + +pub(crate) fn apply_txs<B: Backend>( + block_txs: &[TransactionDocumentV10], + uds: &mut TxColRw<B::Col, UdEvent>, +) -> KvResult<()> { + for tx in block_txs { + for input in tx.get_inputs() { + if let SourceIdV10::Ud(UdSourceIdV10 { + issuer, + block_number, + }) = input.id + { + uds.remove(UdIdV2(issuer, block_number)); + } + } + } + Ok(()) +} + +pub(crate) fn revert_txs<B: Backend>( + block_txs: &[TransactionDocumentV10], + uds: &mut TxColRw<B::Col, UdEvent>, +) -> KvResult<()> { + for tx in block_txs { + for input in tx.get_inputs() { + if let SourceIdV10::Ud(UdSourceIdV10 { + issuer, + block_number, + }) = input.id + { + uds.upsert(UdIdV2(issuer, block_number), EmptyValue); + } + } + } + Ok(()) +} diff --git a/rust-libs/duniter-dbs-write-ops/src/bc/uds.rs b/rust-libs/duniter-dbs-write-ops/src/bc/uds.rs new file mode 100644 index 0000000000000000000000000000000000000000..73952aa2b3c7c9e1c068028fb248fca8995ef202 --- /dev/null +++ b/rust-libs/duniter-dbs-write-ops/src/bc/uds.rs @@ -0,0 +1,72 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// 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 <https://www.gnu.org/licenses/>. + +use crate::*; +use duniter_dbs::{ + bc_v2::{IdentityEvent, UdEvent, UdsRevalEvent}, + UdIdV2, +}; + +// ["uds_reval", uds_reval, BlockNumberKeyV2, SourceAmountValV2,], +// ["uds", uds, UdIdV2, EmptyValue,], + +pub(crate) fn create_uds<B: Backend>( + block_number: BlockNumber, + dividend: SourceAmount, + identities: &mut TxColRw<B::Col, IdentityEvent>, + uds: &mut TxColRw<B::Col, UdEvent>, + uds_reval: &mut TxColRw<B::Col, UdsRevalEvent>, +) -> KvResult<()> { + let previous_ud_amount = uds_reval + .iter(.., |it| it.reverse().values().next_res())? + .unwrap_or_else(|| SourceAmountValV2(SourceAmount::new(0, 0))); + if dividend > previous_ud_amount.0 { + uds_reval.upsert(BlockNumberKeyV2(block_number), SourceAmountValV2(dividend)); + } + + let members = identities.iter(.., |it| { + it.filter_map_ok(|(pk, idty)| if idty.member { Some(pk.0) } else { None }) + .collect::<KvResult<Vec<_>>>() + })?; + for member in members { + uds.upsert(UdIdV2(member, block_number), EmptyValue); + } + Ok(()) +} + +pub(crate) fn revert_uds<B: Backend>( + block_number: BlockNumber, + identities: &mut TxColRw<B::Col, IdentityEvent>, + uds: &mut TxColRw<B::Col, UdEvent>, + uds_reval: &mut TxColRw<B::Col, UdsRevalEvent>, +) -> KvResult<()> { + let previous_reval_block_number = uds_reval + .iter(.., |it| it.reverse().keys().next_res())? + .expect("corrupted db") + .0; + if block_number == previous_reval_block_number { + uds_reval.remove(BlockNumberKeyV2(block_number)); + } + + let members = identities.iter(.., |it| { + it.filter_map_ok(|(pk, idty)| if idty.member { Some(pk.0) } else { None }) + .collect::<KvResult<Vec<_>>>() + })?; + for member in members { + uds.remove(UdIdV2(member, block_number)); + } + + Ok(()) +} diff --git a/rust-libs/duniter-dbs-write-ops/src/gva.rs b/rust-libs/duniter-dbs-write-ops/src/gva.rs new file mode 100644 index 0000000000000000000000000000000000000000..bacd738c9035613e076e3736f49c9320e26c14e2 --- /dev/null +++ b/rust-libs/duniter-dbs-write-ops/src/gva.rs @@ -0,0 +1,70 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// 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 <https://www.gnu.org/licenses/>. + +mod tx; +mod utxos; + +use crate::*; + +pub fn revert_block<B: Backend>(block: &DubpBlockV10, gva_db: &GvaV1Db<B>) -> KvResult<()> { + for idty in block.identities() { + let username = idty.username().to_owned(); + gva_db.uids_index_write().remove(username)?; + } + for tx in block.transactions() { + let tx_hash = tx.get_hash(); + tx::revert_tx(gva_db, &tx_hash)?.ok_or_else(|| { + KvError::DbCorrupted(format!("GVA: tx '{}' dont exist on txs history.", tx_hash,)) + })?; + } + + Ok(()) +} + +pub fn apply_block<B: Backend>(block: &DubpBlockV10, gva_db: &GvaV1Db<B>) -> KvResult<()> { + let blockstamp = Blockstamp { + number: block.number(), + hash: block.hash(), + }; + for idty in block.identities() { + let pubkey = idty.issuers()[0]; + let username = idty.username().to_owned(); + gva_db + .uids_index_write() + .upsert(username, PubKeyValV2(pubkey))?; + } + write_block_txs( + &gva_db, + blockstamp, + block.common_time() as i64, + block.transactions(), + )?; + + Ok(()) +} + +fn write_block_txs<B: Backend>( + gva_db: &GvaV1Db<B>, + current_blockstamp: Blockstamp, + current_time: i64, + txs: &[TransactionDocumentV10], +) -> KvResult<()> { + for tx in txs { + let tx_hash = tx.get_hash(); + // Write tx and update sources + tx::write_gva_tx(current_blockstamp, current_time, &gva_db, tx_hash, tx)?; + } + Ok(()) +} diff --git a/rust-libs/duniter-dbs-write-ops/src/tx.rs b/rust-libs/duniter-dbs-write-ops/src/gva/tx.rs similarity index 96% rename from rust-libs/duniter-dbs-write-ops/src/tx.rs rename to rust-libs/duniter-dbs-write-ops/src/gva/tx.rs index 6dc3d21caa073c69ee15868654a0db2a0898bcb1..dbdad922ffe65a1b7fa574d1cb1fbf8a6214569f 100644 --- a/rust-libs/duniter-dbs-write-ops/src/tx.rs +++ b/rust-libs/duniter-dbs-write-ops/src/gva/tx.rs @@ -20,7 +20,7 @@ pub(crate) fn write_gva_tx<B: Backend>( current_time: i64, gva_db: &GvaV1Db<B>, tx_hash: Hash, - tx: TransactionDocumentV10, + tx: &TransactionDocumentV10, ) -> KvResult<()> { ( gva_db.scripts_by_pubkey_write(), @@ -69,7 +69,7 @@ pub(crate) fn write_gva_tx<B: Backend>( .conditions .script .clone(); - utxos::remove_utxo_v10::<B>( + super::utxos::remove_utxo_v10::<B>( &mut scripts_by_pubkey, &mut utxos_by_script, &utxo_script, @@ -80,7 +80,7 @@ pub(crate) fn write_gva_tx<B: Backend>( // Insert created UTXOs for (output_index, output) in tx.get_outputs().iter().enumerate() { - utxos::write_utxo_v10::<B>( + super::utxos::write_utxo_v10::<B>( &mut scripts_by_pubkey, &mut utxos_by_script, UtxoV10 { @@ -99,7 +99,7 @@ pub(crate) fn write_gva_tx<B: Backend>( txs.upsert( HashKeyV2(tx_hash), TxDbV2 { - tx, + tx: tx.clone(), written_block: current_blockstamp, written_time: current_time, }, @@ -138,7 +138,7 @@ pub(crate) fn revert_tx<B: Backend>( use dubp::documents::transaction::TransactionDocumentTrait as _; for output in tx_db.tx.get_outputs() { let script = &output.conditions.script; - utxos::remove_utxo_v10::<B>( + super::utxos::remove_utxo_v10::<B>( &mut scripts_by_pubkey, &mut utxos_by_script, script, @@ -162,7 +162,7 @@ pub(crate) fn revert_tx<B: Backend>( .conditions .script .clone(); - utxos::write_utxo_v10::<B>( + super::utxos::write_utxo_v10::<B>( &mut scripts_by_pubkey, &mut utxos_by_script, UtxoV10 { diff --git a/rust-libs/duniter-dbs-write-ops/src/utxos.rs b/rust-libs/duniter-dbs-write-ops/src/gva/utxos.rs similarity index 95% rename from rust-libs/duniter-dbs-write-ops/src/utxos.rs rename to rust-libs/duniter-dbs-write-ops/src/gva/utxos.rs index 869d6d9cf16dd6591150d0ac4c502f1ee8936f2a..c38e43a3f9c8aa7a407cf63ca09f7298ba1055d7 100644 --- a/rust-libs/duniter-dbs-write-ops/src/utxos.rs +++ b/rust-libs/duniter-dbs-write-ops/src/gva/utxos.rs @@ -15,13 +15,6 @@ use crate::*; -pub struct UtxoV10 { - pub id: UtxoIdV10, - pub amount: SourceAmount, - pub script: WalletScriptV10, - pub written_time: i64, -} - pub(crate) fn write_utxo_v10<B: Backend>( scripts_by_pubkey: &mut TxColRw<B::Col, duniter_dbs::gva_v1::ScriptsByPubkeyEvent>, utxos_by_script: &mut TxColRw<B::Col, duniter_dbs::gva_v1::UtxosByScriptEvent>, diff --git a/rust-libs/duniter-dbs-write-ops/src/lib.rs b/rust-libs/duniter-dbs-write-ops/src/lib.rs index 043295c09236a51adcd101e3295961f93d102194..42026eab3ae931ff56796bfe61ff1cb09253bf54 100644 --- a/rust-libs/duniter-dbs-write-ops/src/lib.rs +++ b/rust-libs/duniter-dbs-write-ops/src/lib.rs @@ -22,266 +22,46 @@ unused_import_braces )] -mod identities; -mod tx; -mod utxos; +pub mod apply_block; +pub mod bc; +pub mod gva; +pub mod txs_mp; use std::borrow::Cow; -use crate::utxos::UtxoV10; -use dubp::block::DubpBlockV10Stringified; +use dubp::block::prelude::*; use dubp::common::crypto::hashs::Hash; use dubp::common::prelude::*; use dubp::documents::{ prelude::*, smallvec::SmallVec, transaction::TransactionDocumentTrait, transaction::TransactionDocumentV10, }; -use dubp::documents_parser::prelude::*; use dubp::wallet::prelude::*; use duniter_dbs::gva_v1::{TxEvent, TxsByIssuerEvent, TxsByRecipientEvent}; use duniter_dbs::{ - kv_typed::prelude::*, GvaV1Db, GvaV1DbReadable, GvaV1DbWritable, HashKeyV2, PendingTxDbV2, - PubKeyKeyV2, TxDbV2, TxsMpV2Db, TxsMpV2DbReadable, TxsMpV2DbWritable, WalletConditionsV2, + kv_typed::prelude::*, BlockMetaV2, BlockNumberKeyV2, DuniterDbs, GvaV1Db, GvaV1DbReadable, + GvaV1DbWritable, HashKeyV2, PendingTxDbV2, PubKeyKeyV2, PubKeyValV2, SourceAmountValV2, TxDbV2, + TxsMpV2Db, TxsMpV2DbReadable, TxsMpV2DbWritable, WalletConditionsV2, }; +use resiter::filter_map::FilterMap; use resiter::flatten::Flatten; use resiter::map::Map; +use std::ops::Deref; -pub fn add_pending_tx< - B: Backend, - F: FnOnce( - &TransactionDocumentV10, - &TxColRw<B::Col, duniter_dbs::txs_mp_v2::TxEvent>, - ) -> KvResult<()>, ->( - control: F, - txs_mp_db: &TxsMpV2Db<B>, - tx: Cow<TransactionDocumentV10>, -) -> KvResult<()> { - let tx_hash = tx.get_hash(); - let received_time = chrono::offset::Utc::now().timestamp(); - ( - txs_mp_db.txs_by_recv_time_write(), - txs_mp_db.txs_by_issuer_write(), - txs_mp_db.txs_by_recipient_write(), - txs_mp_db.txs_write(), - ) - .write( - |(mut txs_by_recv_time, mut txs_by_issuer, mut txs_by_recipient, mut txs)| { - control(&tx, &txs)?; - // Insert on col `txs_by_recv_time` - let mut hashs = txs_by_recv_time.get(&received_time)?.unwrap_or_default(); - hashs.0.insert(tx_hash); - txs_by_recv_time.upsert(received_time, hashs); - // Insert on col `txs_by_issuer` - for pubkey in tx.issuers() { - let mut hashs = txs_by_issuer.get(&PubKeyKeyV2(pubkey))?.unwrap_or_default(); - hashs.0.insert(tx.get_hash()); - txs_by_issuer.upsert(PubKeyKeyV2(pubkey), hashs); - } - // Insert on col `txs_by_recipient` - for pubkey in tx.recipients_keys() { - let mut hashs = txs_by_recipient - .get(&PubKeyKeyV2(pubkey))? - .unwrap_or_default(); - hashs.0.insert(tx.get_hash()); - txs_by_recipient.upsert(PubKeyKeyV2(pubkey), hashs); - } - // Insert tx itself - txs.upsert(HashKeyV2(tx_hash), PendingTxDbV2(tx.into_owned())); - Ok(()) - }, - ) -} - -pub fn remove_all_pending_txs<B: Backend>(txs_mp_db: &TxsMpV2Db<B>) -> KvResult<()> { - txs_mp_db.txs_by_recv_time_write().clear()?; - txs_mp_db.txs_by_issuer_write().clear()?; - txs_mp_db.txs_by_recipient_write().clear()?; - txs_mp_db.txs_write().clear()?; - - Ok(()) -} - -pub fn remove_pending_tx_by_hash<B: Backend>(txs_mp_db: &TxsMpV2Db<B>, hash: Hash) -> KvResult<()> { - remove_one_pending_tx(&txs_mp_db, hash)?; - Ok(()) -} - -pub fn revert_block<B: Backend>( - gva_db: &GvaV1Db<B>, - txs_mp_db: &TxsMpV2Db<B>, - block: DubpBlockV10Stringified, - gva: bool, -) -> KvResult<()> { - for tx in &block.transactions { - let tx_hash = if let Some(ref tx_hash) = tx.hash { - Hash::from_hex(&tx_hash) - .map_err(|e| KvError::DeserError(format!("Transaction with invalid hash: {}", e)))? - } else { - return Err(KvError::DeserError( - "Try to revert a block that contains a transaction without hash !".to_owned(), - )); - }; - if gva { - let tx = tx::revert_tx(gva_db, &tx_hash)?.ok_or_else(|| { - KvError::DbCorrupted(format!("GVA: tx '{}' dont exist on txs history.", tx_hash,)) - })?; - add_pending_tx(|_, _| Ok(()), txs_mp_db, Cow::Owned(tx))?; - } else { - add_pending_tx( - |_, _| Ok(()), - txs_mp_db, - Cow::Owned( - TransactionDocumentV10::from_string_object(&tx).map_err(|e| { - KvError::DeserError(format!("Block with invalid tx: {}", e)) - })?, - ), - )?; - } - } - - identities::revert_identities(gva_db, &block)?; - - Ok(()) -} - -pub fn apply_block<B: Backend>( - gva_db: &GvaV1Db<B>, - txs_mp_db: &TxsMpV2Db<B>, - block: DubpBlockV10Stringified, - gva: bool, -) -> KvResult<()> { - let block_hash = if let Some(ref block_hash_str) = block.hash { - Hash::from_hex(&block_hash_str) - .map_err(|_| KvError::DeserError(format!("Hash '{}' is invalid", block_hash_str)))? - } else { - return Err(KvError::DeserError(format!( - "Block #{} is without hash", - block.number - ))); - }; - let blockstamp = Blockstamp { - number: BlockNumber(block.number as u32), - hash: BlockHash(block_hash), - }; - let txs = block - .transactions - .iter() - .map(|tx_str| TransactionDocumentV10::from_string_object(tx_str)) - .collect::<Result<Vec<TransactionDocumentV10>, TextParseError>>() - .map_err(|e| KvError::DeserError(format!("Invalid transaction in block: {}", e)))?; - write_block_txs( - &txs_mp_db, - &gva_db, - blockstamp, - block.median_time as i64, - gva, - txs, - )?; - - if gva { - identities::update_identities(&gva_db, &block)?; - } - - Ok(()) -} - -#[inline(always)] -pub fn apply_chunk_of_blocks<B: Backend>( - gva_db: &GvaV1Db<B>, - txs_mp_db: &TxsMpV2Db<B>, - blocks: Vec<DubpBlockV10Stringified>, - gva: bool, -) -> KvResult<()> { - for block in blocks { - if block.number > 300_000 { - log::info!("apply_block(#{})", block.number); - } - apply_block(gva_db, txs_mp_db, block, gva)?; - } - Ok(()) -} - -fn write_block_txs<B: Backend>( - txs_mp_db: &TxsMpV2Db<B>, - gva_db: &GvaV1Db<B>, - current_blockstamp: Blockstamp, - current_time: i64, - gva: bool, - txs: Vec<TransactionDocumentV10>, -) -> KvResult<()> { - for tx in txs { - let tx_hash = tx.get_hash(); - // Remove tx from mempool - remove_one_pending_tx(&txs_mp_db, tx_hash)?; - // Write tx and update sources - if gva { - tx::write_gva_tx(current_blockstamp, current_time, &gva_db, tx_hash, tx)?; - } - } - Ok(()) -} - -pub fn trim_expired_non_written_txs<B: Backend>( - txs_mp_db: &TxsMpV2Db<B>, - limit_time: i64, -) -> KvResult<()> { - // Get hashs of tx to remove and "times" to remove - let mut times = Vec::new(); - let hashs = txs_mp_db.txs_by_recv_time().iter(..limit_time, |it| { - it.map_ok(|(k, v)| { - times.push(k); - v.0 - }) - .flatten_ok() - .collect::<KvResult<SmallVec<[Hash; 4]>>>() - })?; - // For each tx to remove - for (hash, time) in hashs.into_iter().zip(times.into_iter()) { - remove_one_pending_tx(&txs_mp_db, hash)?; - // Remove txs hashs in col `txs_by_recv_time` - txs_mp_db.txs_by_recv_time_write().remove(time)?; - } - - Ok(()) -} - -fn remove_one_pending_tx<B: Backend>(txs_mp_db: &TxsMpV2Db<B>, tx_hash: Hash) -> KvResult<bool> { - if let Some(tx) = txs_mp_db.txs().get(&HashKeyV2(tx_hash))? { - // Remove tx hash in col `txs_by_issuer` - for pubkey in tx.0.issuers() { - let mut hashs_ = txs_mp_db - .txs_by_issuer() - .get(&PubKeyKeyV2(pubkey))? - .unwrap_or_default(); - hashs_.0.remove(&tx_hash); - txs_mp_db - .txs_by_issuer_write() - .upsert(PubKeyKeyV2(pubkey), hashs_)? - } - // Remove tx hash in col `txs_by_recipient` - for pubkey in tx.0.recipients_keys() { - let mut hashs_ = txs_mp_db - .txs_by_recipient() - .get(&PubKeyKeyV2(pubkey))? - .unwrap_or_default(); - hashs_.0.remove(&tx_hash); - txs_mp_db - .txs_by_recipient_write() - .upsert(PubKeyKeyV2(pubkey), hashs_)? - } - // Remove tx itself - txs_mp_db.txs_write().remove(HashKeyV2(tx_hash))?; - Ok(true) - } else { - Ok(false) - } +pub struct UtxoV10 { + pub id: UtxoIdV10, + pub amount: SourceAmount, + pub script: WalletScriptV10, + pub written_time: i64, } #[cfg(test)] mod tests { use super::*; - use dubp::documents::transaction::TransactionDocumentV10Stringified; + use dubp::{ + documents::transaction::TransactionDocumentV10Stringified, + documents_parser::prelude::FromStringObject, + }; #[test] #[ignore] @@ -291,11 +71,11 @@ mod tests { .path("/home/elois/.config/duniter/s2/data/gva_v1_sled") .flush_every_ms(None), )?; - let txs_mp_db = TxsMpV2Db::<Sled>::open( + /*let txs_mp_db = TxsMpV2Db::<Sled>::open( SledConf::default() .path("/home/elois/.config/duniter/s2/data/txs_mp_v2_sled") .flush_every_ms(None), - )?; + )?;*/ let txs: Vec<TransactionDocumentV10Stringified> = serde_json::from_str(r#"[ { @@ -403,8 +183,9 @@ mod tests { transactions: txs, ..Default::default() }; + let block = DubpBlockV10::from_string_object(&block).expect("fail to parse block"); - apply_block(&gva_db, &txs_mp_db, block, true)?; + gva::apply_block(&block, &gva_db)?; Ok(()) } diff --git a/rust-libs/duniter-dbs-write-ops/src/txs_mp.rs b/rust-libs/duniter-dbs-write-ops/src/txs_mp.rs new file mode 100644 index 0000000000000000000000000000000000000000..3765a2d4614d41fe6303a68954b797782b0a280f --- /dev/null +++ b/rust-libs/duniter-dbs-write-ops/src/txs_mp.rs @@ -0,0 +1,154 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// 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 <https://www.gnu.org/licenses/>. + +use crate::*; + +pub fn apply_block<B: Backend>( + block_txs: &[TransactionDocumentV10], + txs_mp_db: &TxsMpV2Db<B>, +) -> KvResult<()> { + for tx in block_txs { + // Remove tx from mempool + remove_one_pending_tx(&txs_mp_db, tx.get_hash())?; + } + Ok(()) +} + +pub fn revert_block<B: Backend>( + block_txs: &[TransactionDocumentV10], + txs_mp_db: &TxsMpV2Db<B>, +) -> KvResult<()> { + for tx in block_txs { + // Rewrite tx on mempool + add_pending_tx(|_, _| Ok(()), txs_mp_db, Cow::Borrowed(tx))?; + } + Ok(()) +} + +pub fn add_pending_tx< + B: Backend, + F: FnOnce( + &TransactionDocumentV10, + &TxColRw<B::Col, duniter_dbs::txs_mp_v2::TxEvent>, + ) -> KvResult<()>, +>( + control: F, + txs_mp_db: &TxsMpV2Db<B>, + tx: Cow<TransactionDocumentV10>, +) -> KvResult<()> { + let tx_hash = tx.get_hash(); + let received_time = chrono::offset::Utc::now().timestamp(); + ( + txs_mp_db.txs_by_recv_time_write(), + txs_mp_db.txs_by_issuer_write(), + txs_mp_db.txs_by_recipient_write(), + txs_mp_db.txs_write(), + ) + .write( + |(mut txs_by_recv_time, mut txs_by_issuer, mut txs_by_recipient, mut txs)| { + control(&tx, &txs)?; + // Insert on col `txs_by_recv_time` + let mut hashs = txs_by_recv_time.get(&received_time)?.unwrap_or_default(); + hashs.0.insert(tx_hash); + txs_by_recv_time.upsert(received_time, hashs); + // Insert on col `txs_by_issuer` + for pubkey in tx.issuers() { + let mut hashs = txs_by_issuer.get(&PubKeyKeyV2(pubkey))?.unwrap_or_default(); + hashs.0.insert(tx.get_hash()); + txs_by_issuer.upsert(PubKeyKeyV2(pubkey), hashs); + } + // Insert on col `txs_by_recipient` + for pubkey in tx.recipients_keys() { + let mut hashs = txs_by_recipient + .get(&PubKeyKeyV2(pubkey))? + .unwrap_or_default(); + hashs.0.insert(tx.get_hash()); + txs_by_recipient.upsert(PubKeyKeyV2(pubkey), hashs); + } + // Insert tx itself + txs.upsert(HashKeyV2(tx_hash), PendingTxDbV2(tx.into_owned())); + Ok(()) + }, + ) +} + +pub fn remove_all_pending_txs<B: Backend>(txs_mp_db: &TxsMpV2Db<B>) -> KvResult<()> { + txs_mp_db.txs_by_recv_time_write().clear()?; + txs_mp_db.txs_by_issuer_write().clear()?; + txs_mp_db.txs_by_recipient_write().clear()?; + txs_mp_db.txs_write().clear()?; + + Ok(()) +} + +pub fn remove_pending_tx_by_hash<B: Backend>(txs_mp_db: &TxsMpV2Db<B>, hash: Hash) -> KvResult<()> { + remove_one_pending_tx(&txs_mp_db, hash)?; + Ok(()) +} + +pub fn trim_expired_non_written_txs<B: Backend>( + txs_mp_db: &TxsMpV2Db<B>, + limit_time: i64, +) -> KvResult<()> { + // Get hashs of tx to remove and "times" to remove + let mut times = Vec::new(); + let hashs = txs_mp_db.txs_by_recv_time().iter(..limit_time, |it| { + it.map_ok(|(k, v)| { + times.push(k); + v.0 + }) + .flatten_ok() + .collect::<KvResult<SmallVec<[Hash; 4]>>>() + })?; + // For each tx to remove + for (hash, time) in hashs.into_iter().zip(times.into_iter()) { + remove_one_pending_tx(&txs_mp_db, hash)?; + // Remove txs hashs in col `txs_by_recv_time` + txs_mp_db.txs_by_recv_time_write().remove(time)?; + } + + Ok(()) +} + +fn remove_one_pending_tx<B: Backend>(txs_mp_db: &TxsMpV2Db<B>, tx_hash: Hash) -> KvResult<bool> { + if let Some(tx) = txs_mp_db.txs().get(&HashKeyV2(tx_hash))? { + ( + txs_mp_db.txs_by_issuer_write(), + txs_mp_db.txs_by_recipient_write(), + txs_mp_db.txs_write(), + ) + .write(|(mut txs_by_issuer, mut txs_by_recipient, mut txs)| { + // Remove tx hash in col `txs_by_issuer` + for pubkey in tx.0.issuers() { + let mut hashs_ = txs_by_issuer.get(&PubKeyKeyV2(pubkey))?.unwrap_or_default(); + hashs_.0.remove(&tx_hash); + txs_by_issuer.upsert(PubKeyKeyV2(pubkey), hashs_) + } + // Remove tx hash in col `txs_by_recipient` + for pubkey in tx.0.recipients_keys() { + let mut hashs_ = txs_by_recipient + .get(&PubKeyKeyV2(pubkey))? + .unwrap_or_default(); + hashs_.0.remove(&tx_hash); + txs_by_recipient.upsert(PubKeyKeyV2(pubkey), hashs_) + } + // Remove tx itself + txs.remove(HashKeyV2(tx_hash)); + Ok(true) + }) + } else { + Ok(false) + } +} diff --git a/rust-libs/duniter-dbs/Cargo.toml b/rust-libs/duniter-dbs/Cargo.toml index 1dfc931750d6b7a8d2acf52442f99247dfacc56b..f7c5bf46e3fb93c2dfe44ceda057fc7180669606 100644 --- a/rust-libs/duniter-dbs/Cargo.toml +++ b/rust-libs/duniter-dbs/Cargo.toml @@ -20,10 +20,12 @@ dubp = { version = "0.29.0" } kv_typed = { path = "../tools/kv_typed", default-features = false } log = "0.4.8" mockall = { version = "0.8.0", optional = true } +rand = "0.7.3" serde = { version = "1.0.105", features = ["derive"] } serde_json = "1.0.53" smallvec = { version = "1.4.0", features = ["serde", "write"] } thiserror = "1.0.20" +uninit = "0.4.0" zerocopy = "0.3.0" [dev-dependencies] diff --git a/rust-libs/duniter-dbs-write-ops/src/identities.rs b/rust-libs/duniter-dbs/src/bc_v2.rs similarity index 58% rename from rust-libs/duniter-dbs-write-ops/src/identities.rs rename to rust-libs/duniter-dbs/src/bc_v2.rs index c572294a4e2bc4d50e93272f407cf77ef43b8b05..79db9a3913429ddc6a866a32f24eecde76a26de8 100644 --- a/rust-libs/duniter-dbs-write-ops/src/identities.rs +++ b/rust-libs/duniter-dbs/src/bc_v2.rs @@ -15,23 +15,12 @@ use crate::*; -pub(crate) fn update_identities<B: Backend>( - _gva_db: &GvaV1Db<B>, - block: &DubpBlockV10Stringified, -) -> KvResult<()> { - for joiner in &block.joiners { - let joiner_fields: SmallVec<[&str; 5]> = joiner.split(':').collect(); - let _pubkey = joiner_fields[0]; - let _username = joiner_fields[4]; - } - // TODO - Ok(()) -} - -pub(crate) fn revert_identities<B: Backend>( - _gva_db: &GvaV1Db<B>, - _block: &DubpBlockV10Stringified, -) -> KvResult<()> { - // TODO - Ok(()) -} +db_schema!( + BcV2, + [ + ["blocks_meta", blocks_meta, BlockNumberKeyV2, BlockMetaV2,], + ["uds_reval", uds_reval, BlockNumberKeyV2, SourceAmountValV2,], + ["identities", identities, PubKeyKeyV2, IdtyDbV2,], + ["uds", uds, UdIdV2, EmptyValue,], + ] +); diff --git a/rust-libs/duniter-dbs/src/gva_v1.rs b/rust-libs/duniter-dbs/src/gva_v1.rs index 88aab2d60cd86a169d0d40c6cb7ccaf6e6def42e..a3623490b836dcb3d61d1b3a4dd7ea9a5ff53637 100644 --- a/rust-libs/duniter-dbs/src/gva_v1.rs +++ b/rust-libs/duniter-dbs/src/gva_v1.rs @@ -18,6 +18,7 @@ use crate::*; db_schema!( GvaV1, [ + ["uids_index", uids_index, String, PubKeyValV2,], ["txs", txs, HashKeyV2, TxDbV2,], ["txs_by_issuer", txs_by_issuer, PubKeyKeyV2, HashBTSetV2,], [ @@ -38,8 +39,5 @@ db_schema!( WalletConditionsV2, UtxosOfScriptV1, ], - ["identities", identities, PubKeyKeyV2, IdtyDbV2,], - ["uds", uds_by_block, BlockNumberKeyV2, SourceAmountValV2,], - ["uds", uds_by_issuer, PubKeyKeyV2, BlockNumberArrayV2,], ] ); diff --git a/rust-libs/duniter-dbs/src/keys.rs b/rust-libs/duniter-dbs/src/keys.rs index d05a345d404619552de75b41844f14667445875c..35cb4e6dc5aa8456eb1296ae661c9f164e920f2c 100644 --- a/rust-libs/duniter-dbs/src/keys.rs +++ b/rust-libs/duniter-dbs/src/keys.rs @@ -21,5 +21,6 @@ pub mod pubkey; pub mod pubkey_and_sig; pub mod source_key; pub mod timestamp; +pub mod ud_id; pub mod uid; pub mod wallet_conditions; diff --git a/rust-libs/duniter-dbs/src/keys/ud_id.rs b/rust-libs/duniter-dbs/src/keys/ud_id.rs new file mode 100644 index 0000000000000000000000000000000000000000..71617b5fdf0f3df857110a2b7e790913ee5c5998 --- /dev/null +++ b/rust-libs/duniter-dbs/src/keys/ud_id.rs @@ -0,0 +1,123 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// 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 <https://www.gnu.org/licenses/>. + +use crate::*; +use uninit::prelude::*; + +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] +pub struct UdIdV2(pub PublicKey, pub BlockNumber); + +impl PartialOrd for UdIdV2 { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + match self.0.partial_cmp(&other.0) { + Some(std::cmp::Ordering::Equal) => self.1.partial_cmp(&other.1), + o => o, + } + } +} +impl Ord for UdIdV2 { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + match self.0.cmp(&other.0) { + std::cmp::Ordering::Equal => self.1.cmp(&other.1), + o => o, + } + } +} + +impl KeyAsBytes for UdIdV2 { + fn as_bytes<T, F: FnMut(&[u8]) -> T>(&self, mut f: F) -> T { + let mut buffer = uninit_array![u8; 37]; + let (pubkey_buffer, block_number_buffer) = buffer.as_out().split_at_out(33); + let pubkey_buffer = pubkey_buffer.copy_from_slice(self.0.as_ref()); + block_number_buffer.copy_from_slice(&(self.1).0.to_be_bytes()); + f(unsafe { std::slice::from_raw_parts_mut(pubkey_buffer.as_mut_ptr(), 37) }) + } +} + +impl FromBytes for UdIdV2 { + type Err = StringErr; + + fn from_bytes(bytes: &[u8]) -> std::result::Result<Self, Self::Err> { + let pubkey = PublicKey::try_from(&bytes[..33]) + .map_err(|e| StringErr(format!("{}: {:?}", e, bytes)))?; + let block_number = BlockNumber( + zerocopy::LayoutVerified::<_, zerocopy::U32<byteorder::BigEndian>>::new(&bytes[33..]) + .ok_or_else(|| { + StringErr( + "Corrupted DB: BlockNumber bytes are invalid length or unaligned" + .to_owned(), + ) + })? + .get(), + ); + Ok(UdIdV2(pubkey, block_number)) + } +} + +impl ToDumpString for UdIdV2 { + fn to_dump_string(&self) -> String { + todo!() + } +} + +#[cfg(feature = "explorer")] +impl ExplorableKey for UdIdV2 { + fn from_explorer_str(source: &str) -> std::result::Result<Self, StringErr> { + let mut source = source.split(':'); + if let Some(pubkey_str) = source.next() { + let pubkey = PublicKey::from_base58(&pubkey_str) + .map_err(|e| StringErr(format!("{}: {}", e, pubkey_str)))?; + if let Some(block_number_str) = source.next() { + Ok(UdIdV2( + pubkey, + BlockNumber::from_str(block_number_str) + .map_err(|e| StringErr(format!("{}", e)))?, + )) + } else { + Err(StringErr("UdIdV2: Invalid format".to_owned())) + } + } else { + Err(StringErr("UdIdV2: Invalid format".to_owned())) + } + } + fn to_explorer_string(&self) -> KvResult<String> { + Ok(format!("{}:{}", self.0.to_base58(), (self.1).0)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ud_id_v2_as_bytes() -> std::result::Result<(), StringErr> { + let ud_id = UdIdV2(PublicKey::default(), BlockNumber(3)); + + let ud_id_2_res = ud_id.as_bytes(|bytes| { + assert_eq!( + bytes, + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 3 + ] + ); + UdIdV2::from_bytes(bytes) + }); + + assert_eq!(ud_id_2_res?, ud_id); + + Ok(()) + } +} diff --git a/rust-libs/duniter-dbs/src/lib.rs b/rust-libs/duniter-dbs/src/lib.rs index 01dd5e49e3da1c0c5dccfd87e88e05ac3783e662..e4fc04be2df8289d8a049ddb42fdaa87bf383dc4 100644 --- a/rust-libs/duniter-dbs/src/lib.rs +++ b/rust-libs/duniter-dbs/src/lib.rs @@ -23,9 +23,11 @@ )] mod bc_v1; +pub mod bc_v2; mod errors; pub mod gva_v1; mod keys; +mod open_dbs; pub mod txs_mp_v2; mod values; @@ -50,8 +52,9 @@ pub mod prelude { }; } -// Export technical types +// Export technical types and functions pub use crate::errors::Result; +pub use crate::open_dbs::open_dbs; // Export profession types pub use bc_v1::{BcV1Db, BcV1DbReadable, BcV1DbRo, BcV1DbWritable, MainBlockEvent, UidEvent}; @@ -64,11 +67,13 @@ pub use keys::pubkey::{PubKeyKeyV1, PubKeyKeyV2}; pub use keys::pubkey_and_sig::PubKeyAndSigV1; pub use keys::source_key::SourceKeyV1; pub use keys::timestamp::TimestampKeyV1; +pub use keys::ud_id::UdIdV2; pub use keys::uid::UidKeyV1; pub use keys::wallet_conditions::{WalletConditionsV1, WalletConditionsV2}; pub use txs_mp_v2::{TxsMpV2Db, TxsMpV2DbReadable, TxsMpV2DbRo, TxsMpV2DbWritable}; pub use values::block_db::{BlockDbEnum, BlockDbV1, TransactionInBlockDbV1}; pub use values::block_head_db::BlockHeadDbV1; +pub use values::block_meta::BlockMetaV2; pub use values::block_number_array_db::{BlockNumberArrayV1, BlockNumberArrayV2}; pub use values::cindex_db::CIndexDbV1; pub use values::hash_array_db::HashBTSetV2; @@ -76,7 +81,7 @@ pub use values::idty_db::IdtyDbV2; pub use values::iindex_db::IIndexDbV1; pub use values::kick_db::KickDbV1; pub use values::mindex_db::MIndexDbV1; -pub use values::pubkey_db::{PublicKeyArrayDbV1, PublicKeySingletonDbV1}; +pub use values::pubkey_db::{PubKeyValV2, PublicKeyArrayDbV1, PublicKeySingletonDbV1}; pub use values::sindex_db::{SIndexDBV1, SourceKeyArrayDbV1}; pub use values::source_amount::SourceAmountValV2; pub use values::tx_db::{PendingTxDbV2, TxDbV2}; @@ -104,6 +109,7 @@ pub(crate) use std::{ convert::TryFrom, fmt::Debug, iter::Iterator, + path::{Path, PathBuf}, str::FromStr, }; @@ -114,12 +120,13 @@ pub trait ToDumpString { #[cfg(feature = "mem")] pub type DbsBackend = kv_typed::backend::memory::Mem; #[cfg(all(not(feature = "mem"), target_arch = "x86_64"))] -pub type DbsBackend = Lmdb; +pub type DbsBackend = Sled; // TODO ESZ #[cfg(all(not(feature = "mem"), not(target_arch = "x86_64")))] pub type DbsBackend = Sled; #[derive(Clone, Debug)] pub struct DuniterDbs { + pub bc_db: bc_v2::BcV2Db<DbsBackend>, pub gva_db: GvaV1Db<DbsBackend>, pub txs_mp_db: TxsMpV2Db<DbsBackend>, } diff --git a/rust-libs/duniter-server/src/conf.rs b/rust-libs/duniter-dbs/src/open_dbs.rs similarity index 62% rename from rust-libs/duniter-server/src/conf.rs rename to rust-libs/duniter-dbs/src/open_dbs.rs index 63ab05afd4131da648a2bd16d9bac1832930dd92..5dab56843a829b69597d274e5cccb0f01fea2f16 100644 --- a/rust-libs/duniter-server/src/conf.rs +++ b/rust-libs/duniter-dbs/src/open_dbs.rs @@ -13,19 +13,18 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. +use crate::bc_v2::BcV2DbWritable as _; use crate::*; -#[derive(Clone, Debug)] -pub struct DuniterServerConf { - pub gva: Option<GvaConf>, - pub server_pubkey: PublicKey, - pub txs_mempool_size: usize, -} - pub fn open_dbs(home_path_opt: Option<&Path>) -> DuniterDbs { DuniterDbs { + bc_db: crate::bc_v2::BcV2Db::<DbsBackend>::open(DbsBackend::gen_backend_conf( + "bc_v2", + home_path_opt, + )) + .expect("fail to open BcV2 DB"), gva_db: GvaV1Db::<DbsBackend>::open(DbsBackend::gen_backend_conf("gva_v1", home_path_opt)) - .expect("fail to open GVA DB"), + .expect("fail to open Gva DB"), txs_mp_db: TxsMpV2Db::<DbsBackend>::open(DbsBackend::gen_backend_conf( "txs_mp_v2", home_path_opt, @@ -68,7 +67,30 @@ impl BackendConf for Lmdb { impl BackendConf for Sled { #[inline(always)] fn gen_backend_conf(db_name: &'static str, home_path_opt: Option<&Path>) -> SledConf { - let conf = SledConf::default().flush_every_ms(Some(10_000)); + let mut conf = SledConf::default().flush_every_ms(Some(10_000)); + conf = match db_name { + "bc_v2" => { + if let Ok(compression_level) = std::env::var("DUNITER_BC_DB_COMPRESSION") { + conf.use_compression(true) + .compression_factor(i32::from_str(&compression_level).expect( + "Env var DUNITER_BC_DB_COMPRESSION must be a number beetween 1 and 22 !", + )) + } else { + conf.use_compression(false) + } + } + "gva_v1" => { + if let Ok(compression_level) = std::env::var("DUNITER_GVA_DB_COMPRESSION") { + conf.use_compression(true) + .compression_factor(i32::from_str(&compression_level).expect( + "Env var DUNITER_GVA_DB_COMPRESSION must be a number beetween 1 and 22 !", + )) + } else { + conf.use_compression(false) + } + } + _ => conf.use_compression(false), + }; if let Some(data_path) = home_path_opt { conf.path(data_path.join(format!("data/{}_sled", db_name))) } else { diff --git a/rust-libs/duniter-dbs/src/values.rs b/rust-libs/duniter-dbs/src/values.rs index 62427e53eb8cae5ffc8b497340a110251a61cd78..7c6823de95323b4f9856a8857e3d7a687bbb7101 100644 --- a/rust-libs/duniter-dbs/src/values.rs +++ b/rust-libs/duniter-dbs/src/values.rs @@ -15,6 +15,7 @@ pub mod block_db; pub mod block_head_db; +pub mod block_meta; pub mod block_number_array_db; pub mod cindex_db; pub mod hash_array_db; diff --git a/rust-libs/duniter-dbs/src/values/block_meta.rs b/rust-libs/duniter-dbs/src/values/block_meta.rs new file mode 100644 index 0000000000000000000000000000000000000000..8cd6ca2e39abfaf79131e83fdd0ed29683aa43d6 --- /dev/null +++ b/rust-libs/duniter-dbs/src/values/block_meta.rs @@ -0,0 +1,97 @@ +// Copyright (C) 2020 Éloïs SANCHEZ. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// 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 <https://www.gnu.org/licenses/>. + +use crate::*; + +const BLOCK_META_SERIALIZED_SIZE: usize = 319; + +#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize)] +pub struct BlockMetaV2 { + pub version: u64, // 8 + pub number: u32, // 4 + pub hash: Hash, // 32 + pub signature: Signature, // 64 + pub inner_hash: Hash, // 32 + pub previous_hash: Hash, // 32 + pub issuer: PublicKey, // 33 + pub previous_issuer: PublicKey, // 33 + pub time: u64, // 8 + pub pow_min: u32, // 4 + pub members_count: u64, // 8 + pub issuers_count: u32, // 4 + pub issuers_frame: u64, // 8 + pub issuers_frame_var: i64, // 8 + pub median_time: u64, // 8 + pub nonce: u64, // 8 + pub monetary_mass: u64, // 8 + pub dividend: Option<SourceAmount>, // 17 -> TOTAL SIZE == 331 bytes +} + +impl ValueAsBytes for BlockMetaV2 { + fn as_bytes<T, F: FnMut(&[u8]) -> KvResult<T>>(&self, mut f: F) -> KvResult<T> { + let mut buffer = [0u8; BLOCK_META_SERIALIZED_SIZE]; + bincode::serialize_into(&mut buffer[..], self).unwrap_or_else(|_| unreachable!()); + f(buffer.as_ref()) + } +} + +impl kv_typed::prelude::FromBytes for BlockMetaV2 { + type Err = StringErr; + + fn from_bytes(bytes: &[u8]) -> std::result::Result<Self, Self::Err> { + Ok(bincode::deserialize(bytes).map_err(|e| StringErr(format!("{}", e)))?) + } +} + +impl ToDumpString for BlockMetaV2 { + fn to_dump_string(&self) -> String { + todo!() + } +} + +#[cfg(feature = "explorer")] +impl ExplorableValue for BlockMetaV2 { + fn from_explorer_str(json_str: &str) -> std::result::Result<Self, StringErr> { + Ok(serde_json::from_str(&json_str) + .map_err(|e| StringErr(format!("{}: '{}'", e, json_str)))?) + } + fn to_explorer_json(&self) -> KvResult<serde_json::Value> { + serde_json::to_value(self).map_err(|e| KvError::DeserError(format!("{}", e))) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use unwrap::unwrap; + + #[test] + fn block_meta_v2_as_bytes() -> KvResult<()> { + assert_eq!( + unwrap!(bincode::serialized_size(&BlockMetaV2 { + dividend: Some(SourceAmount::new(42, 0)), + ..Default::default() + })), + BLOCK_META_SERIALIZED_SIZE as u64 + ); + let bloc_meta = BlockMetaV2::default(); + + let bm2_res = bloc_meta.as_bytes(|bytes| Ok(unwrap!(BlockMetaV2::from_bytes(bytes)))); + + assert_eq!(bm2_res?, bloc_meta); + + Ok(()) + } +} diff --git a/rust-libs/duniter-dbs/src/values/idty_db.rs b/rust-libs/duniter-dbs/src/values/idty_db.rs index 3e60717844c3333a9ef8e55633f08d54b0f2ddd2..f12a27fbe2a395c94472a233b04655746f596c06 100644 --- a/rust-libs/duniter-dbs/src/values/idty_db.rs +++ b/rust-libs/duniter-dbs/src/values/idty_db.rs @@ -17,8 +17,8 @@ use crate::*; #[derive(Debug, Default, PartialEq, Serialize, Deserialize)] pub struct IdtyDbV2 { - member: bool, - username: String, + pub member: bool, + pub username: String, } impl ValueAsBytes for IdtyDbV2 { diff --git a/rust-libs/duniter-dbs/src/values/pubkey_db.rs b/rust-libs/duniter-dbs/src/values/pubkey_db.rs index 78e750ef65a72939f504e007b9920e4e948d301c..17be3a7528442c809f7937d4c3266d98368f6e7c 100644 --- a/rust-libs/duniter-dbs/src/values/pubkey_db.rs +++ b/rust-libs/duniter-dbs/src/values/pubkey_db.rs @@ -15,6 +15,8 @@ use crate::*; +// V1 + #[derive(Copy, Clone, Debug, PartialEq)] pub struct PublicKeySingletonDbV1(pub PublicKey); @@ -107,3 +109,42 @@ impl ExplorableValue for PublicKeyArrayDbV1 { )) } } + +// V2 + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct PubKeyValV2(pub PublicKey); + +impl ValueAsBytes for PubKeyValV2 { + fn as_bytes<T, F: FnMut(&[u8]) -> KvResult<T>>(&self, mut f: F) -> KvResult<T> { + f(self.0.as_ref()) + } +} + +impl kv_typed::prelude::FromBytes for PubKeyValV2 { + type Err = StringErr; + + fn from_bytes(bytes: &[u8]) -> std::result::Result<Self, Self::Err> { + Ok(PubKeyValV2( + PublicKey::try_from(bytes).map_err(|e| StringErr(format!("{}: {:?}", e, bytes)))?, + )) + } +} + +impl ToDumpString for PubKeyValV2 { + fn to_dump_string(&self) -> String { + todo!() + } +} + +#[cfg(feature = "explorer")] +impl ExplorableValue for PubKeyValV2 { + fn from_explorer_str(pubkey_str: &str) -> std::result::Result<Self, StringErr> { + Ok(PubKeyValV2(PublicKey::from_base58(&pubkey_str).map_err( + |e| StringErr(format!("{}: {}", e, pubkey_str)), + )?)) + } + fn to_explorer_json(&self) -> KvResult<serde_json::Value> { + Ok(serde_json::Value::String(self.0.to_base58())) + } +} diff --git a/rust-libs/duniter-gva/Cargo.toml b/rust-libs/duniter-gva/Cargo.toml index 973c4db8d14f1f0bdb3c3cdda8946e51bf4e470b..3e53ba15076044c5d230557502cb2d7780876144 100644 --- a/rust-libs/duniter-gva/Cargo.toml +++ b/rust-libs/duniter-gva/Cargo.toml @@ -12,7 +12,7 @@ dubp = { version = "0.29.0" } duniter-dbs = { path = "../duniter-dbs" } duniter-dbs-read-ops = { path = "../duniter-dbs-read-ops" } duniter-mempools = { path = "../duniter-mempools" } -fast-threadpool = "0.1.1" +fast-threadpool = "0.2.1" flume = "0.9.1" futures = "0.3.6" http = "0.2.1" diff --git a/rust-libs/duniter-gva/src/lib.rs b/rust-libs/duniter-gva/src/lib.rs index 07d6247c46e252b46c739d1bb577e59e5e94aafb..3f8e6cf31cce261fbb6ab09eac3599ade104f99d 100644 --- a/rust-libs/duniter-gva/src/lib.rs +++ b/rust-libs/duniter-gva/src/lib.rs @@ -170,6 +170,7 @@ impl GvaServer { #[cfg(test)] mod tests { use super::*; + use duniter_dbs::bc_v2::{BcV2Db, BcV2DbWritable}; use duniter_dbs::kv_typed::backend::memory::{Mem, MemConf}; use duniter_dbs::{GvaV1Db, GvaV1DbWritable, TxsMpV2Db, TxsMpV2DbWritable}; use fast_threadpool::ThreadPoolConfig; @@ -179,6 +180,7 @@ mod tests { #[ignore] fn launch_mem_gva() { let dbs = DuniterDbs { + bc_db: unwrap!(BcV2Db::<Mem>::open(MemConf::default())), gva_db: unwrap!(GvaV1Db::<Mem>::open(MemConf::default())), txs_mp_db: unwrap!(TxsMpV2Db::<Mem>::open(MemConf::default())), }; diff --git a/rust-libs/duniter-mempools/src/lib.rs b/rust-libs/duniter-mempools/src/lib.rs index f6e4b426cbbc0131a9dcad9c05b93f23907051b3..a4528f80fe5e8afa5838f94457ceec916b631cdd 100644 --- a/rust-libs/duniter-mempools/src/lib.rs +++ b/rust-libs/duniter-mempools/src/lib.rs @@ -84,10 +84,14 @@ impl TxsMempool { if duniter_dbs_read_ops::txs_history::tx_exist(gva_db_ro, tx.get_hash())? { Err(TxMpError::TxAlreadyWritten) } else if tx.issuers().contains(&server_pubkey) { - duniter_dbs_write_ops::add_pending_tx(|_, _| Ok(()), txs_mp_db, Cow::Borrowed(tx))?; + duniter_dbs_write_ops::txs_mp::add_pending_tx( + |_, _| Ok(()), + txs_mp_db, + Cow::Borrowed(tx), + )?; Ok(()) } else { - duniter_dbs_write_ops::add_pending_tx( + duniter_dbs_write_ops::txs_mp::add_pending_tx( |_tx, txs| { if txs.count()? < self.max_size { Err(KvError::Custom(TxMpError::Full.into())) @@ -108,7 +112,7 @@ impl TxsMempool { txs_mp_db: &TxsMpV2Db<B>, tx: &TransactionDocumentV10, ) -> KvResult<()> { - duniter_dbs_write_ops::add_pending_tx(|_, _| Ok(()), txs_mp_db, Cow::Borrowed(tx))?; + duniter_dbs_write_ops::txs_mp::add_pending_tx(|_, _| Ok(()), txs_mp_db, Cow::Borrowed(tx))?; Ok(()) } diff --git a/rust-libs/duniter-server/Cargo.toml b/rust-libs/duniter-server/Cargo.toml index 358937e224382b3c1163f19ab257d83248e929f5..77adee8f61ee2ccf4900bbf34143b971fd0dc731 100644 --- a/rust-libs/duniter-server/Cargo.toml +++ b/rust-libs/duniter-server/Cargo.toml @@ -12,11 +12,10 @@ duniter-dbs-read-ops = { path = "../duniter-dbs-read-ops" } duniter-dbs-write-ops = { path = "../duniter-dbs-write-ops" } duniter-gva = { path = "../duniter-gva" } duniter-mempools = { path = "../duniter-mempools" } -fast-threadpool = "0.1.1" +fast-threadpool = "0.2.1" flume = "0.9.1" log = "0.4.11" resiter = "0.4.0" -rand = "0.7.3" [dev-dependencies] unwrap = "1.2.1" diff --git a/rust-libs/duniter-server/src/lib.rs b/rust-libs/duniter-server/src/lib.rs index 16b5b844701bb62d47e29d46e66f7756ea8e8242..19240c051c2f3caba79af46f945bac82ffefa1b3 100644 --- a/rust-libs/duniter-server/src/lib.rs +++ b/rust-libs/duniter-server/src/lib.rs @@ -22,37 +22,42 @@ unused_import_braces )] -mod conf; - pub use duniter_dbs::smallvec; use duniter_mempools::{TxMpError, TxsMempool}; use fast_threadpool::ThreadPoolConfig; -pub use crate::conf::{BackendConf, DuniterServerConf}; pub use duniter_gva::GvaConf; -use dubp::block::DubpBlockV10Stringified; -use dubp::common::crypto::hashs::Hash; use dubp::common::crypto::keys::ed25519::PublicKey; use dubp::common::prelude::*; use dubp::documents::{prelude::*, transaction::TransactionDocumentV10}; -use duniter_dbs::prelude::*; +use dubp::{ + block::prelude::*, common::crypto::hashs::Hash, documents_parser::prelude::FromStringObject, +}; use duniter_dbs::{ - kv_typed::backend::memory::{Mem, MemConf}, - kv_typed::backend::sled::Sled, - kv_typed::prelude::*, - GvaV1Db, GvaV1DbReadable, GvaV1DbWritable, HashKeyV2, PendingTxDbV2, TxsMpV2Db, - TxsMpV2DbReadable, TxsMpV2DbWritable, + kv_typed::prelude::*, GvaV1DbReadable, HashKeyV2, PendingTxDbV2, TxsMpV2DbReadable, }; +use duniter_dbs::{prelude::*, BlockMetaV2}; use duniter_dbs_read_ops::txs_history::TxsHistory; use resiter::filter::Filter; -use std::{ - collections::BTreeMap, - path::{Path, PathBuf}, -}; +use std::{collections::BTreeMap, path::Path}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum DuniterCommand { + Sync, + Start, +} + +#[derive(Clone, Debug)] +pub struct DuniterServerConf { + pub gva: Option<GvaConf>, + pub server_pubkey: PublicKey, + pub txs_mempool_size: usize, +} pub struct DuniterServer { conf: DuniterServerConf, + current: Option<BlockMetaV2>, dbs_pool: fast_threadpool::ThreadPoolSyncHandler<DuniterDbs>, pending_txs_subscriber: flume::Receiver<Arc<Events<duniter_dbs::txs_mp_v2::TxEvent>>>, txs_mempool: TxsMempool, @@ -60,13 +65,23 @@ pub struct DuniterServer { impl DuniterServer { pub fn start( + command_name: Option<String>, conf: DuniterServerConf, home_path_opt: Option<&Path>, software_version: &'static str, ) -> Self { + let command = match command_name.unwrap_or_default().as_str() { + "sync" => DuniterCommand::Sync, + _ => DuniterCommand::Start, + }; + let txs_mempool = TxsMempool::new(conf.txs_mempool_size); - let dbs = conf::open_dbs(home_path_opt); + log::info!("open duniter databases..."); + let dbs = duniter_dbs::open_dbs(home_path_opt); + log::info!("Databases successfully opened."); + let current = + duniter_dbs_read_ops::get_current_block_meta(&dbs.bc_db).expect("Fail to get current"); let (s, pending_txs_subscriber) = flume::unbounded(); dbs.txs_mp_db @@ -75,26 +90,29 @@ impl DuniterServer { .expect("Fail to subscribe to txs col"); let threadpool = if home_path_opt.is_some() { + log::info!("start dbs threadpool..."); let threadpool = fast_threadpool::ThreadPool::start(ThreadPoolConfig::default(), dbs.clone()); - if let Some(mut gva_conf) = conf.gva.clone() { - if let Some(remote_path) = std::env::var_os("DUNITER_GVA_REMOTE_PATH") { - gva_conf.remote_path( - remote_path - .into_string() - .expect("Invalid utf8 for Env var DUNITER_GVA_REMOTE_PATH"), - ); + if command != DuniterCommand::Sync { + if let Some(mut gva_conf) = conf.gva.clone() { + if let Some(remote_path) = std::env::var_os("DUNITER_GVA_REMOTE_PATH") { + gva_conf.remote_path( + remote_path + .into_string() + .expect("Invalid utf8 for Env var DUNITER_GVA_REMOTE_PATH"), + ); + } + duniter_gva::GvaServer::start( + gva_conf, + dbs, + threadpool.async_handler(), + conf.server_pubkey, + software_version, + txs_mempool, + ) + .expect("Fail to start GVA server"); } - duniter_gva::GvaServer::start( - gva_conf, - dbs, - threadpool.async_handler(), - conf.server_pubkey, - software_version, - txs_mempool, - ) - .expect("Fail to start GVA server"); } threadpool } else { @@ -103,6 +121,7 @@ impl DuniterServer { DuniterServer { conf, + current, dbs_pool: threadpool.into_sync_handler(), pending_txs_subscriber, txs_mempool, @@ -211,49 +230,70 @@ impl DuniterServer { pub fn remove_all_pending_txs(&self) -> KvResult<()> { self.dbs_pool - .execute(move |dbs| duniter_dbs_write_ops::remove_all_pending_txs(&dbs.txs_mp_db)) + .execute(move |dbs| { + duniter_dbs_write_ops::txs_mp::remove_all_pending_txs(&dbs.txs_mp_db) + }) .expect("dbs pool disconnected") } pub fn remove_pending_tx_by_hash(&self, hash: Hash) -> KvResult<()> { self.dbs_pool .execute(move |dbs| { - duniter_dbs_write_ops::remove_pending_tx_by_hash(&dbs.txs_mp_db, hash) + duniter_dbs_write_ops::txs_mp::remove_pending_tx_by_hash(&dbs.txs_mp_db, hash) }) .expect("dbs pool disconnected") } - pub fn revert_block(&self, block: DubpBlockV10Stringified) -> KvResult<()> { + pub fn revert_block(&mut self, block: DubpBlockV10Stringified) -> KvResult<()> { let gva = self.conf.gva.is_some(); - self.dbs_pool + let block = DubpBlockV10::from_string_object(&block) + .map_err(|e| KvError::DeserError(format!("{}", e)))?; + self.current = self + .dbs_pool .execute(move |dbs| { - duniter_dbs_write_ops::revert_block(&dbs.gva_db, &dbs.txs_mp_db, block, gva) + duniter_dbs_write_ops::txs_mp::revert_block(block.transactions(), &dbs.txs_mp_db)?; + if gva { + duniter_dbs_write_ops::gva::revert_block(&block, &dbs.gva_db)?; + } + duniter_dbs_write_ops::bc::revert_block(&dbs.bc_db, block) }) - .expect("dbs pool disconnected") + .expect("dbs pool disconnected")?; + Ok(()) } - pub fn apply_block(&self, block: DubpBlockV10Stringified) -> KvResult<()> { + pub fn apply_block(&mut self, block: DubpBlockV10Stringified) -> KvResult<()> { let gva = self.conf.gva.is_some(); - self.dbs_pool - .execute(move |dbs| { - duniter_dbs_write_ops::apply_block(&dbs.gva_db, &dbs.txs_mp_db, block, gva) - }) - .expect("dbs pool disconnected") + let block = DubpBlockV10::from_string_object(&block) + .map_err(|e| KvError::DeserError(format!("{}", e)))?; + self.current = Some(duniter_dbs_write_ops::apply_block::apply_block( + block, + self.current, + &self.dbs_pool, + gva, + false, + )?); + Ok(()) } - pub fn apply_chunk_of_blocks(&self, blocks: Vec<DubpBlockV10Stringified>) -> KvResult<()> { + pub fn apply_chunk_of_blocks(&mut self, blocks: Vec<DubpBlockV10Stringified>) -> KvResult<()> { + log::debug!("apply_chunk(#{})", blocks[0].number); let gva = self.conf.gva.is_some(); - self.dbs_pool - .execute(move |dbs| { - duniter_dbs_write_ops::apply_chunk_of_blocks( - &dbs.gva_db, - &dbs.txs_mp_db, - blocks, - gva, - ) - }) - .expect("dbs pool disconnected") + let blocks = blocks + .into_iter() + .map(|block| DubpBlockV10::from_string_object(&block)) + .collect::<Result<Vec<_>, _>>() + .map_err(|e| KvError::DeserError(format!("{}", e)))?; + self.current = Some(duniter_dbs_write_ops::apply_block::apply_chunk( + self.current, + &self.dbs_pool, + blocks, + gva, + )?); + Ok(()) } pub fn trim_expired_non_written_txs(&self, limit_time: i64) -> KvResult<()> { self.dbs_pool .execute(move |dbs| { - duniter_dbs_write_ops::trim_expired_non_written_txs(&dbs.txs_mp_db, limit_time) + duniter_dbs_write_ops::txs_mp::trim_expired_non_written_txs( + &dbs.txs_mp_db, + limit_time, + ) }) .expect("dbs pool disconnected") } @@ -268,6 +308,7 @@ mod tests { #[test] fn test_txs_history() -> KvResult<()> { let server = DuniterServer::start( + None, DuniterServerConf { gva: None, server_pubkey: PublicKey::default(), diff --git a/rust-libs/tools/kv_typed/Cargo.toml b/rust-libs/tools/kv_typed/Cargo.toml index 68cb443dde41454b4efa46598198a5e1eaf69da6..66d4966da6587e16bbd2155679ecd74488a6909f 100644 --- a/rust-libs/tools/kv_typed/Cargo.toml +++ b/rust-libs/tools/kv_typed/Cargo.toml @@ -22,7 +22,7 @@ paste = "1.0.2" rayon = { version = "1.3.1", optional = true } regex = { version = "1.3.9", optional = true } serde_json = { version = "1.0.53", optional = true } -sled = { version = "0.34.4", optional = true } +sled = { version = "0.34.4", optional = true, features = ["compression"] } smallvec = { version = "1.4.0", features = ["serde", "write"] } thiserror = "1.0.20" uninit = "0.4.0" diff --git a/rust-libs/tools/kv_typed/benches/compare_backends.rs b/rust-libs/tools/kv_typed/benches/compare_backends.rs index ac8e2d92b1ab46012df03e8b2b2a178d78424136..8eef7214aadb83e453c1539abe00cc3d5f20e369 100644 --- a/rust-libs/tools/kv_typed/benches/compare_backends.rs +++ b/rust-libs/tools/kv_typed/benches/compare_backends.rs @@ -1,4 +1,4 @@ -use criterion::{criterion_group, criterion_main, AxisScale, Criterion, PlotConfiguration}; +use criterion::{criterion_group, criterion_main, Criterion, /*, AxisScale, PlotConfiguration*/}; use kv_typed::prelude::*; use std::{fmt::Debug, path::PathBuf}; diff --git a/rust-libs/tools/kv_typed/src/as_bytes.rs b/rust-libs/tools/kv_typed/src/as_bytes.rs index 0ba24d8e07edab661687ce0010693134924f3394..b7734bb7c50d53388cf569a7679f3f42288712c7 100644 --- a/rust-libs/tools/kv_typed/src/as_bytes.rs +++ b/rust-libs/tools/kv_typed/src/as_bytes.rs @@ -28,7 +28,7 @@ impl KeyAsBytes for () { } fn fill_bytes(&self, _: &mut [u8]) {} } -impl ValueAsBytes for () { +impl ValueAsBytes for EmptyValue { fn as_bytes<T, F: FnMut(&[u8]) -> Result<T, KvError>>(&self, mut f: F) -> Result<T, KvError> { f(&[]) } diff --git a/rust-libs/tools/kv_typed/src/batch.rs b/rust-libs/tools/kv_typed/src/batch.rs index 90b9738dfe577271cb043a536b180400c12db61b..1583d515ac4c162c7abaf15d5a0fe47fcc4cdd59 100644 --- a/rust-libs/tools/kv_typed/src/batch.rs +++ b/rust-libs/tools/kv_typed/src/batch.rs @@ -71,6 +71,7 @@ impl<BC: BackendCol, C: DbCollectionRw> Batch<BC, C> { let _ = k.as_bytes(|k_bytes| { self.tree.insert(IVec::from(k_bytes), None); }); + self.upsert_ops.remove(&k); self.delete_ops.insert(k); } #[doc(hidden)] diff --git a/rust-libs/tools/kv_typed/src/event.rs b/rust-libs/tools/kv_typed/src/event.rs index e259e267c5e545b7f3488192c653c0b1bf8fa319..0a2c79abe82bc8ab9cea316804bd8095eacb2e47 100644 --- a/rust-libs/tools/kv_typed/src/event.rs +++ b/rust-libs/tools/kv_typed/src/event.rs @@ -29,18 +29,3 @@ pub trait EventTrait: 'static + Debug + PartialEq + Send + Sync { fn upsert(k: Self::K, v: Self::V) -> Self; fn remove(k: Self::K) -> Self; } - -impl EventTrait for () { - type K = (); - type V = (); - - fn clear() -> Self { - unimplemented!() - } - fn upsert(_: Self::K, _: Self::V) -> Self { - unimplemented!() - } - fn remove(_: Self::K) -> Self { - unimplemented!() - } -} diff --git a/rust-libs/tools/kv_typed/src/explorer.rs b/rust-libs/tools/kv_typed/src/explorer.rs index 9522f03b3bc6ef15e7836aa2babb056dd52452c5..49bfd9ef34a9dee09077ebac231d4e6a6eebd495 100644 --- a/rust-libs/tools/kv_typed/src/explorer.rs +++ b/rust-libs/tools/kv_typed/src/explorer.rs @@ -68,6 +68,16 @@ impl ExplorableValue for () { } } +impl ExplorableValue for EmptyValue { + fn from_explorer_str(_: &str) -> Result<Self, StringErr> { + Ok(EmptyValue) + } + + fn to_explorer_json(&self) -> KvResult<serde_json::Value> { + Ok(serde_json::Value::String(String::with_capacity(0))) + } +} + impl ExplorableValue for String { fn from_explorer_str(source: &str) -> Result<Self, StringErr> { Ok(source.to_owned()) diff --git a/rust-libs/tools/kv_typed/src/from_bytes.rs b/rust-libs/tools/kv_typed/src/from_bytes.rs index a8837d27d53aa461f6516a8f3fbd3e0d2dbaa572..1ec49096a8f7cf1c8f99739cbcbda352203d76b8 100644 --- a/rust-libs/tools/kv_typed/src/from_bytes.rs +++ b/rust-libs/tools/kv_typed/src/from_bytes.rs @@ -15,6 +15,14 @@ impl FromBytes for () { } } +impl FromBytes for EmptyValue { + type Err = std::convert::Infallible; + + fn from_bytes(_: &[u8]) -> Result<Self, Self::Err> { + Ok(EmptyValue) + } +} + macro_rules! impl_from_bytes_for_numbers { ($($T:ty),*) => {$( impl FromBytes for $T { diff --git a/rust-libs/tools/kv_typed/src/lib.rs b/rust-libs/tools/kv_typed/src/lib.rs index 0a4ac7072fb38511a62d44bd211d2b0293c27dbe..2e80ad614235ab39a13e9254f458bec2058397fe 100644 --- a/rust-libs/tools/kv_typed/src/lib.rs +++ b/rust-libs/tools/kv_typed/src/lib.rs @@ -85,7 +85,7 @@ pub mod prelude { pub use crate::transactional_read::TransactionalRead; pub use crate::transactional_write::{DbTxCollectionRw, TransactionalWrite, TxColRw}; pub use crate::utils::arc::Arc; - pub use crate::value::{Value, ValueSliceZc, ValueZc}; + pub use crate::value::{EmptyValue, Value, ValueSliceZc, ValueZc}; pub use kv_typed_code_gen::db_schema; } diff --git a/rust-libs/tools/kv_typed/src/value.rs b/rust-libs/tools/kv_typed/src/value.rs index 2391b7bd73ea2276c8948cb783bdad433acab799..c2d383e67b400c1565a6562a6c3ebc2b04c760f5 100644 --- a/rust-libs/tools/kv_typed/src/value.rs +++ b/rust-libs/tools/kv_typed/src/value.rs @@ -81,3 +81,6 @@ impl ValueSliceZc for String { 0 } } + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct EmptyValue; diff --git a/rust-libs/tools/kv_typed/tests/db_schema.rs b/rust-libs/tools/kv_typed/tests/db_schema.rs index d0d49b745d7a354bd047cadc0a3556342b861ca1..6026dead8d43f3594ad64b442aaf37c2834b8cba 100644 --- a/rust-libs/tools/kv_typed/tests/db_schema.rs +++ b/rust-libs/tools/kv_typed/tests/db_schema.rs @@ -26,7 +26,7 @@ mod tests { TestV1, [ ["c1", col_1, i32, String,], - ["c2", col_2, usize, i128,], + ["c2", col_2, usize, EmptyValue,], ["c3", col_3, u64, VecU128], ["c4", col_4, u64, BTSetU128], ] @@ -88,6 +88,8 @@ mod tests { assert_eq!(d, Some("toto".to_owned())); assert_eq!(db.col_2().get(&3)?, None,); + db.col_2_write().upsert(3, EmptyValue)?; + assert_eq!(db.col_2().get(&3)?, Some(EmptyValue),); db.col_1_write().upsert(5, "tutu".to_owned())?; diff --git a/server.ts b/server.ts index 46fcc19d01dde9e8256770bbb4bcd7d30f777daa..6cdd3e3dc5a2847aa3e442b8d4f673bb932c5f18 100644 --- a/server.ts +++ b/server.ts @@ -351,8 +351,8 @@ export class Server extends stream.Duplex implements HookableServer { this.streamPush(res.clone()) } - async initDAL(conf:ConfDTO|null = null) { - await this.dal.init(this.conf) + async initDAL(conf:ConfDTO|null = null, commandName: string|null = null) { + await this.dal.init(this.conf, commandName) // Maintenance let head_1 = await this.dal.bindexDAL.head(1); if (head_1) { diff --git a/test/dal/basic-dal-tests.ts b/test/dal/basic-dal-tests.ts index 8fc3836d2d9c1668d5a4b47a3c6b46ddfdbc0b97..7891325bc433d04a5fcc0434a52d02a5ca1454f2 100644 --- a/test/dal/basic-dal-tests.ts +++ b/test/dal/basic-dal-tests.ts @@ -44,7 +44,7 @@ var mocks = { "currency" : "meta_brouzouf", "issuer" : "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk", "parameters" : "0.1:86400:100:604800:2629800:3:3:2629800:3:11:600:20:144:0.67", - "previousHash" : "", + "previousHash" : "00063EB6E83F8717CEF1D25B3E2EE30800063EB6E83F8717CEF1D25B3E2EE308", "previousIssuer" : "", "transactions" : [ ], @@ -71,28 +71,28 @@ var mocks = { "37qBxM4hLV2jfyYo2bNzAjkeLngLr2r7G2HpdpKieVxw" ], "leavers" : [ - "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:3cJm3F44eLMhQtnQY/7+14SWCDqVTL3Miw65hBVpV+YiUSUknIGhBNN0C0Cf+Pf0/pa1tjucW8Us3z5IklFSDg==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:1421787800:inso", - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:3lFIiaR0QX0jibr5zQpXVGzBvMGqcsTRlmHiwGz5HOAZT8PTdVUb5q6YGZ6qAUZjdMjPmhLaiMIpYc47wUnzBA==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:1421786393:cgeek", - "BMAVuMDcGhYAV4wA27DL1VXX2ZARZGJYaMwpf7DJFMYH:3tyAhpTRrAAOhFJukWI8RBr//nqYYdQibVzjOfaCdcWLb3TNFKrNBBothNsq/YrYHr7gKrpoftucf/oxLF8zAg==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:1421790376:moul", - "37qBxM4hLV2jfyYo2bNzAjkeLngLr2r7G2HpdpKieVxw:3oiGaC5b7kWqtqdPxwatPk9QajZHCNT9rf8/8ud9Rli24z/igcOf0Zr4A6RTAIKWUq9foW39VqJe+Y9R3rhACw==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:1421787461:galuel" + "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:3cJm3F44eLMhQtnQY/7+14SWCDqVTL3Miw65hBVpV+YiUSUknIGhBNN0C0Cf+Pf0/pa1tjucW8Us3z5IklFSDg==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:inso", + "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:3lFIiaR0QX0jibr5zQpXVGzBvMGqcsTRlmHiwGz5HOAZT8PTdVUb5q6YGZ6qAUZjdMjPmhLaiMIpYc47wUnzBA==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:cgeek", + "BMAVuMDcGhYAV4wA27DL1VXX2ZARZGJYaMwpf7DJFMYH:3tyAhpTRrAAOhFJukWI8RBr//nqYYdQibVzjOfaCdcWLb3TNFKrNBBothNsq/YrYHr7gKrpoftucf/oxLF8zAg==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:moul", + "37qBxM4hLV2jfyYo2bNzAjkeLngLr2r7G2HpdpKieVxw:3oiGaC5b7kWqtqdPxwatPk9QajZHCNT9rf8/8ud9Rli24z/igcOf0Zr4A6RTAIKWUq9foW39VqJe+Y9R3rhACw==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:galuel" ], "actives" : [ - "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:2cJm3F44eLMhQtnQY/7+14SWCDqVTL3Miw65hBVpV+YiUSUknIGhBNN0C0Cf+Pf0/pa1tjucW8Us3z5IklFSDg==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:1421787800:inso", - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:2lFIiaR0QX0jibr5zQpXVGzBvMGqcsTRlmHiwGz5HOAZT8PTdVUb5q6YGZ6qAUZjdMjPmhLaiMIpYc47wUnzBA==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:1421786393:cgeek", - "BMAVuMDcGhYAV4wA27DL1VXX2ZARZGJYaMwpf7DJFMYH:2tyAhpTRrAAOhFJukWI8RBr//nqYYdQibVzjOfaCdcWLb3TNFKrNBBothNsq/YrYHr7gKrpoftucf/oxLF8zAg==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:1421790376:moul", - "37qBxM4hLV2jfyYo2bNzAjkeLngLr2r7G2HpdpKieVxw:2oiGaC5b7kWqtqdPxwatPk9QajZHCNT9rf8/8ud9Rli24z/igcOf0Zr4A6RTAIKWUq9foW39VqJe+Y9R3rhACw==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:1421787461:galuel" + "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:2cJm3F44eLMhQtnQY/7+14SWCDqVTL3Miw65hBVpV+YiUSUknIGhBNN0C0Cf+Pf0/pa1tjucW8Us3z5IklFSDg==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:inso", + "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:2lFIiaR0QX0jibr5zQpXVGzBvMGqcsTRlmHiwGz5HOAZT8PTdVUb5q6YGZ6qAUZjdMjPmhLaiMIpYc47wUnzBA==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:cgeek", + "BMAVuMDcGhYAV4wA27DL1VXX2ZARZGJYaMwpf7DJFMYH:2tyAhpTRrAAOhFJukWI8RBr//nqYYdQibVzjOfaCdcWLb3TNFKrNBBothNsq/YrYHr7gKrpoftucf/oxLF8zAg==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:moul", + "37qBxM4hLV2jfyYo2bNzAjkeLngLr2r7G2HpdpKieVxw:2oiGaC5b7kWqtqdPxwatPk9QajZHCNT9rf8/8ud9Rli24z/igcOf0Zr4A6RTAIKWUq9foW39VqJe+Y9R3rhACw==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:galuel" ], "joiners" : [ - "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:1cJm3F44eLMhQtnQY/7+14SWCDqVTL3Miw65hBVpV+YiUSUknIGhBNN0C0Cf+Pf0/pa1tjucW8Us3z5IklFSDg==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:1421787800:inso", - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:1lFIiaR0QX0jibr5zQpXVGzBvMGqcsTRlmHiwGz5HOAZT8PTdVUb5q6YGZ6qAUZjdMjPmhLaiMIpYc47wUnzBA==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:1421786393:cgeek", - "BMAVuMDcGhYAV4wA27DL1VXX2ZARZGJYaMwpf7DJFMYH:1tyAhpTRrAAOhFJukWI8RBr//nqYYdQibVzjOfaCdcWLb3TNFKrNBBothNsq/YrYHr7gKrpoftucf/oxLF8zAg==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:1421790376:moul", - "37qBxM4hLV2jfyYo2bNzAjkeLngLr2r7G2HpdpKieVxw:1oiGaC5b7kWqtqdPxwatPk9QajZHCNT9rf8/8ud9Rli24z/igcOf0Zr4A6RTAIKWUq9foW39VqJe+Y9R3rhACw==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:1421787461:galuel" + "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:1cJm3F44eLMhQtnQY/7+14SWCDqVTL3Miw65hBVpV+YiUSUknIGhBNN0C0Cf+Pf0/pa1tjucW8Us3z5IklFSDg==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:inso", + "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:1lFIiaR0QX0jibr5zQpXVGzBvMGqcsTRlmHiwGz5HOAZT8PTdVUb5q6YGZ6qAUZjdMjPmhLaiMIpYc47wUnzBA==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:cgeek", + "BMAVuMDcGhYAV4wA27DL1VXX2ZARZGJYaMwpf7DJFMYH:1tyAhpTRrAAOhFJukWI8RBr//nqYYdQibVzjOfaCdcWLb3TNFKrNBBothNsq/YrYHr7gKrpoftucf/oxLF8zAg==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:moul", + "37qBxM4hLV2jfyYo2bNzAjkeLngLr2r7G2HpdpKieVxw:1oiGaC5b7kWqtqdPxwatPk9QajZHCNT9rf8/8ud9Rli24z/igcOf0Zr4A6RTAIKWUq9foW39VqJe+Y9R3rhACw==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:galuel" ], "identities" : [ - "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:Ot3zIp/nsHT3zgJy+2YcXPL6vaM5WFsD+F8w3qnJoBRuBG6lv761zoaExp2iyUnm8fDAyKPpMxRK2kf437QSCw==:1421787800:inso", - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:GZKLgaxJKL+GqxVLePMt8OVLJ6qTLrib5Mr/j2gjiNRY2k485YLB2OlzhBzZVnD3xLs0xi69JUfmLnM54j3aCA==:1421786393:cgeek", - "BMAVuMDcGhYAV4wA27DL1VXX2ZARZGJYaMwpf7DJFMYH:th576H89dfymkG7/sH+DAIzjlmIqNEW6zY3ONrGeAml+k3f1ver399kYnEgG5YCaKXnnVM7P0oJHah80BV3mDw==:1421790376:moul", - "37qBxM4hLV2jfyYo2bNzAjkeLngLr2r7G2HpdpKieVxw:XRmbTYFkPeGVEU2mJzzN4h1oVNDsZ4yyNZlDAfBm9CWhBsZ82QqX9GPHye2hBxxiu4Nz1BHgQiME6B4JcAC8BA==:1421787461:galuel" + "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:Ot3zIp/nsHT3zgJy+2YcXPL6vaM5WFsD+F8w3qnJoBRuBG6lv761zoaExp2iyUnm8fDAyKPpMxRK2kf437QSCw==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:inso", + "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:GZKLgaxJKL+GqxVLePMt8OVLJ6qTLrib5Mr/j2gjiNRY2k485YLB2OlzhBzZVnD3xLs0xi69JUfmLnM54j3aCA==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:cgeek", + "BMAVuMDcGhYAV4wA27DL1VXX2ZARZGJYaMwpf7DJFMYH:th576H89dfymkG7/sH+DAIzjlmIqNEW6zY3ONrGeAml+k3f1ver399kYnEgG5YCaKXnnVM7P0oJHah80BV3mDw==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:moul", + "37qBxM4hLV2jfyYo2bNzAjkeLngLr2r7G2HpdpKieVxw:XRmbTYFkPeGVEU2mJzzN4h1oVNDsZ4yyNZlDAfBm9CWhBsZ82QqX9GPHye2hBxxiu4Nz1BHgQiME6B4JcAC8BA==:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:galuel" ], "membersCount" : 4, "monetaryMass" : 0, @@ -104,7 +104,7 @@ var mocks = { "powMin" : 3, "number" : 0, "nonce" : 10144, - "inner_hash": "r51009E813AEAB91F6541170D589E42BD2BBBC19BAB18F32EC1D3E83159BB1CD6" + "inner_hash": "51009E813AEAB91F6541170D589E42BD2BBBC19BAB18F32EC1D3E83159BB1CD6" } }; diff --git a/test/integration/tools/toolbox.ts b/test/integration/tools/toolbox.ts index 5f6394f17264b790ed510fe2c4001b0545923320..571c3c6ed6852f02a0bc6437440119eae2dc59ea 100644 --- a/test/integration/tools/toolbox.ts +++ b/test/integration/tools/toolbox.ts @@ -520,6 +520,10 @@ export class TestingServer { return blocksResolved } + async revertCurrentBlock() { + await this.server.BlockchainService.revertCurrentBlock() + } + async resolveExistingBlock(filterFunc: (b: DBBlock) => boolean) { const blocksResolved = await this.server.BlockchainService.blockResolution(filterFunc) if (!blocksResolved) { diff --git a/test/integration/ws2p/ws2p_sync.ts b/test/integration/ws2p/ws2p_sync.ts deleted file mode 100644 index faa75739b062a4be76dcbbfc748902d38da5e8e2..0000000000000000000000000000000000000000 --- a/test/integration/ws2p/ws2p_sync.ts +++ /dev/null @@ -1,60 +0,0 @@ -// Source file from duniter: Crypto-currency software to manage libre currency such as Ğ1 -// Copyright (C) 2018 Cedric Moreau <cem.moreau@gmail.com> -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// 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. - -import {WS2PConstants} from "../../../app/modules/ws2p/lib/constants" -import {assertEqual, assertNotNull, createCurrencyWith2Blocks, writeBasicTestWith2Users} from "../tools/test-framework" -import {NewTestingServer, TestWS2PAPI} from "../tools/toolbox" -import {CrawlerDependency} from "../../../app/modules/crawler/index" - -describe('WS2P sync', () => writeBasicTestWith2Users((test) => { - - - // We want the test to fail quickly - WS2PConstants.CONNEXION_TIMEOUT = 1000 - WS2PConstants.REQUEST_TIMEOUT = 1000 - - let ws2p: TestWS2PAPI - - test('should be able to init with 2 blocks', async (s1, cat, tac) => { - await createCurrencyWith2Blocks(s1, cat, tac) - await s1.disableBMA() - }) - - test('we should be able to connect for SYNC', async (s1, cat, tac) => { - ws2p = await s1.enableWS2P() - const ws = ws2p.connectForSync(tac.keypair, '12345678') - const current = await ws.getCurrent() - assertNotNull(current) - assertEqual(2, current.number) - }) - - test('we should be able to reconnect for SYNC', async (s1, cat, tac) => { - const ws = ws2p.connectForSync(tac.keypair, '22222222') - await assertNotNull(ws.getCurrent()) - }) - - test('we should be able to connect for SYNC with toc', async (s1, cat, tac, toc) => { - const ws = ws2p.connectForSync(toc.keypair, '33333333') - const current = await ws.getCurrent() - assertNotNull(current) - assertEqual(2, current.number) - }) - - test('we should be able to make a full sync with cat', async (s1, cat, tac, toc) => { - const s2 = NewTestingServer({ pair: cat.keypair }) - await s2.initWithDAL() - // We sync on s1 - await CrawlerDependency.duniter.methods.synchronize(s2._server, ws2p.host, ws2p.port, 2, 2, true).syncPromise - assertNotNull(await s2.dal.getCurrentBlockOrNull()) - }) -}))