From f24d6e224db9d3e077fc60c50f085d39535adc55 Mon Sep 17 00:00:00 2001 From: Drazen Urch Date: Thu, 17 Mar 2022 12:03:05 +0100 Subject: [PATCH] Change accumulated reward to Option, migrate delegations (#1147) * Change accumulated reward to Option, migrate delegations * Remove interval from the validator cache * Add info to db errors * Remove interval fetch from the contract * Rework epochs * Fix undelegation errors * Emit error event instead of error * make no-clippy * Fix clippy lints --- Cargo.lock | 162 ++++++++++-------- Makefile | 1 + .../validator-client/src/client.rs | 32 ++-- .../validator-client/src/nymd/mod.rs | 59 +++---- .../mixnet-contract/src/events.rs | 28 ++- .../mixnet-contract/src/interval.rs | 32 +++- .../mixnet-contract/src/mixnode.rs | 20 ++- .../mixnet-contract/src/msg.rs | 7 +- common/socks5/proxy-helpers/Cargo.toml | 3 +- contracts/Cargo.lock | 19 +- contracts/mixnet/src/constants.rs | 4 - contracts/mixnet/src/contract.rs | 73 ++++++-- contracts/mixnet/src/delegations/storage.rs | 6 +- .../mixnet/src/delegations/transactions.rs | 37 ++-- contracts/mixnet/src/error.rs | 17 ++ contracts/mixnet/src/interval/queries.rs | 68 +------- contracts/mixnet/src/interval/storage.rs | 28 +-- contracts/mixnet/src/interval/transactions.rs | 136 +++++---------- contracts/mixnet/src/mixnodes/storage.rs | 10 +- contracts/mixnet/src/mixnodes/transactions.rs | 2 +- contracts/mixnet/src/rewards/queries.rs | 6 +- contracts/mixnet/src/rewards/transactions.rs | 48 ++++-- .../mixnet/src/support/tests/fixtures.rs | 7 +- contracts/mixnet/src/support/tests/mod.rs | 5 +- nym-wallet/src/types/rust/account.ts | 8 +- nym-wallet/src/types/rust/balance.ts | 7 +- nym-wallet/src/types/rust/coin.ts | 7 +- .../src/types/rust/corenodestatusresponse.ts | 6 +- nym-wallet/src/types/rust/createdaccount.ts | 7 +- nym-wallet/src/types/rust/delegationresult.ts | 8 +- nym-wallet/src/types/rust/denom.ts | 3 +- nym-wallet/src/types/rust/gateway.ts | 11 +- .../rust/inclusionprobabilityresponse.ts | 6 +- nym-wallet/src/types/rust/mixnode.ts | 12 +- nym-wallet/src/types/rust/mixnodestatus.ts | 3 +- .../src/types/rust/mixnodestatusresponse.ts | 6 +- nym-wallet/src/types/rust/network.ts | 3 +- nym-wallet/src/types/rust/operation.ts | 36 +--- .../src/types/rust/originalvestingresponse.ts | 8 +- nym-wallet/src/types/rust/period.ts | 3 +- nym-wallet/src/types/rust/pledgedata.ts | 7 +- .../src/types/rust/rewardedsetnodestatus.ts | 3 +- .../types/rust/rewardestimationresponse.ts | 11 +- .../src/types/rust/stakesaturationresponse.ts | 6 +- nym-wallet/src/types/rust/stateparams.ts | 8 +- nym-wallet/src/types/rust/tauritxresult.ts | 11 +- .../src/types/rust/transactiondetails.ts | 8 +- .../src/types/rust/vestingaccountinfo.ts | 12 +- nym-wallet/src/types/rust/vestingperiod.ts | 6 +- validator-api/src/contract_cache/mod.rs | 16 +- validator-api/src/main.rs | 3 +- validator-api/src/node_status_api/models.rs | 6 +- validator-api/src/node_status_api/routes.rs | 40 +++-- validator-api/src/nymd_client.rs | 26 +-- .../src/rewarded_set_updater/error.rs | 3 + validator-api/src/rewarded_set_updater/mod.rs | 48 +++--- validator-api/src/storage/manager.rs | 8 +- validator-api/src/storage/mod.rs | 94 +++++----- 58 files changed, 589 insertions(+), 671 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4bfc4c430..7ad3ea4834 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.55" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" [[package]] name = "arrayref" @@ -93,9 +93,9 @@ checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "async-stream" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" +checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" dependencies = [ "async-stream-impl", "futures-core", @@ -103,9 +103,9 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" +checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" dependencies = [ "proc-macro2", "quote", @@ -218,9 +218,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "base64ct" -version = "1.3.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874f8444adcb4952a8bc51305c8be95c8ec8237bb0d2e78d2e039f771f8828a0" +checksum = "71acf5509fc522cce1b100ac0121c635129bfd4d91cdf036bcc9b9935f97ccf5" [[package]] name = "binascii" @@ -245,7 +245,7 @@ checksum = "873faa4363bfc54c36a48321da034c92a0645a363eed34d948683ffc1706e37f" dependencies = [ "bs58", "hmac 0.11.0", - "k256 0.10.2", + "k256 0.10.4", "once_cell", "pbkdf2", "rand_core 0.6.3", @@ -519,9 +519,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.1.5" +version = "3.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced1892c55c910c1219e98d6fc8d71f6bddba7905866ce740066d8bfea859312" +checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123" dependencies = [ "atty", "bitflags", @@ -736,7 +736,7 @@ dependencies = [ "ecdsa 0.13.4", "eyre", "getrandom 0.2.5", - "k256 0.10.2", + "k256 0.10.4", "prost", "prost-types", "rand_core 0.6.3", @@ -750,9 +750,9 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.0.0-beta5" +version = "1.0.0-beta6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8904127a5b9e325ef5d6b2b3f997dcd74943cd35097139b1a4d15b1b6bccae66" +checksum = "2dddc1443004c6340e55ca66d98e9d2f1a44aadf4ce2bed2c4f29baa8a15e7b7" dependencies = [ "digest 0.9.0", "ed25519-zebra", @@ -763,22 +763,23 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.0.0-beta5" +version = "1.0.0-beta6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a14364ac4d9d085867929d0cf3e94b1d2100121ce02c33c72961406830002613" +checksum = "fe4f0f10f165b8bcc558a13cddb498140960544519aa0581532c766dd80b5598" dependencies = [ "syn", ] [[package]] name = "cosmwasm-std" -version = "1.0.0-beta5" +version = "1.0.0-beta6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2ece12e5bbde434b93937d7b2107e6291f11d69ffa72398c50e8bab41d451d3" +checksum = "2f0f3145097b692b2d95fa5d2c7c6fdd60f193ccc709857e7e1987a608725300" dependencies = [ "base64", "cosmwasm-crypto", "cosmwasm-derive", + "forward_ref", "schemars", "serde", "serde-json-wasm", @@ -870,9 +871,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" +checksum = "fdbfe11fe19ff083c48923cf179540e8cd0535903dc35e178a1fdeeb59aef51f" dependencies = [ "cfg-if", "crossbeam-utils", @@ -891,10 +892,11 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" dependencies = [ + "autocfg 1.1.0", "cfg-if", "crossbeam-utils", "lazy_static", @@ -904,9 +906,9 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd435b205a4842da59efd07628f921c096bc1cc0a156835b4fa0bcb9a19bcce" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" dependencies = [ "cfg-if", "crossbeam-utils", @@ -914,9 +916,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ "cfg-if", "lazy_static", @@ -1267,9 +1269,9 @@ checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" [[package]] name = "dyn-clone" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" +checksum = "21e50f3adc76d6a43f5ed73b698a87d0760ca74617f60f7c3b879003536fdd28" [[package]] name = "ecdsa" @@ -1551,9 +1553,9 @@ dependencies = [ [[package]] name = "fixed" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d38004fb072c44da88a322343c7c784bd1ff6f2e3f5b332050de60c5eea3e0e" +checksum = "d3342b127378d13cfdbd56de8d7e7feec33a9772d5657b9605e59a6e4a337e36" dependencies = [ "az", "bytemuck", @@ -1604,9 +1606,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.10.11" +version = "0.10.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b279436a715a9de95dcd26b151db590a71961cc06e54918b24fe0dd5b7d3fc4" +checksum = "843c03199d0c0ca54bc1ea90ac0d507274c28abcc4f691ae8b4eaa375087c76a" dependencies = [ "futures-core", "futures-sink", @@ -1660,6 +1662,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + [[package]] name = "fs2" version = "0.4.3" @@ -1922,9 +1930,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e7d3b96ec1fcaa8431cf04a4f1ef5caafe58d5cf7bcc31f09c1626adddb0ffe" +checksum = "3826a6e0e2215d7a41c2bfc7c9244123969273f3476b939a226aac0ab56e9e3c" dependencies = [ "bitflags", "libc", @@ -1976,9 +1984,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" +checksum = "62eeb471aa3e3c9197aa4bfeabfe02982f6dc96f750486c0bb0009ac58b26d2b" dependencies = [ "bytes", "fnv", @@ -2194,9 +2202,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "humantime-serde" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac34a56cfd4acddb469cc7fff187ed5ac36f498ba085caf8bbc725e3ff474058" +checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" dependencies = [ "humantime 2.1.0", "serde", @@ -2397,9 +2405,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" +checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c" [[package]] name = "ipnetwork" @@ -2494,9 +2502,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cc5937366afd3b38071f400d1ce5bd8b1d40b5083cc14e6f8dbcc4032a7f5bb" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" dependencies = [ "cfg-if", "ecdsa 0.13.4", @@ -2526,15 +2534,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.119" +version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" +checksum = "ad5c14e80759d0939d013e6ca49930e59fc53dd8e5009132f76240c179380c09" [[package]] name = "libgit2-sys" -version = "0.13.1+1.4.2" +version = "0.13.2+1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43e598aa7a4faedf1ea1b4608f582b06f0f40211eec551b7ef36019ae3f62def" +checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b" dependencies = [ "cc", "libc", @@ -2561,9 +2569,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" +checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859" dependencies = [ "cc", "libc", @@ -2682,14 +2690,15 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +checksum = "7ba42135c6a5917b9db9cd7b293e5409e1c6b041e6f9825e92e55a894c63b6f8" dependencies = [ "libc", "log", "miow", "ntapi", + "wasi 0.11.0+wasi-snapshot-preview1", "winapi", ] @@ -2815,13 +2824,12 @@ dependencies = [ [[package]] name = "nom" -version = "7.1.0" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" dependencies = [ "memchr", "minimal-lexical", - "version_check", ] [[package]] @@ -2885,9 +2893,9 @@ dependencies = [ [[package]] name = "num_threads" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15" +checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" dependencies = [ "libc", ] @@ -2935,7 +2943,7 @@ dependencies = [ "bandwidth-claim-contract", "bip39", "bs58", - "clap 3.1.5", + "clap 3.1.6", "coconut-interface", "colored", "config", @@ -2978,7 +2986,7 @@ version = "0.12.1" dependencies = [ "anyhow", "bs58", - "clap 3.1.5", + "clap 3.1.6", "colored", "config", "crypto", @@ -3263,9 +3271,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "oorandom" @@ -4118,9 +4126,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -4153,9 +4161,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.9" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525" +checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb" dependencies = [ "base64", "bytes", @@ -5208,9 +5216,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" dependencies = [ "proc-macro2", "quote", @@ -5261,7 +5269,7 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", - "k256 0.10.2", + "k256 0.10.4", "num-traits", "once_cell", "prost", @@ -5715,9 +5723,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f" +checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" dependencies = [ "cfg-if", "log", @@ -5728,9 +5736,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" +checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" dependencies = [ "proc-macro2", "quote", @@ -5739,9 +5747,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" +checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c" dependencies = [ "lazy_static", "valuable", @@ -6112,6 +6120,12 @@ version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" version = "0.2.78" @@ -6374,9 +6388,9 @@ checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" [[package]] name = "winreg" -version = "0.7.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] diff --git a/Makefile b/Makefile index 77279cdaea..3d87c659b5 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ test: build clippy-all cargo-test wasm fmt +no-clippy: build cargo-test wasm fmt happy: fmt clippy-happy test clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet diff --git a/common/client-libs/validator-client/src/client.rs b/common/client-libs/validator-client/src/client.rs index 69fb9f132b..6e1b599ea8 100644 --- a/common/client-libs/validator-client/src/client.rs +++ b/common/client-libs/validator-client/src/client.rs @@ -3,7 +3,7 @@ use crate::{validator_api, ValidatorClientError}; use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse}; -use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond}; +use mixnet_contract_common::{GatewayBond, IdentityKeyRef, Interval, MixNodeBond}; use network_defaults::DEFAULT_NETWORK; use url::Url; use validator_api_requests::models::{ @@ -20,7 +20,7 @@ use mixnet_contract_common::ContractStateParams; #[cfg(feature = "nymd-client")] use mixnet_contract_common::{ - Delegation, IdentityKey, Interval, MixnetContractVersion, MixnodeRewardingStatusResponse, + Delegation, IdentityKey, MixnetContractVersion, MixnodeRewardingStatusResponse, RewardedSetNodeStatus, RewardedSetUpdateDetails, }; #[cfg(feature = "nymd-client")] @@ -248,6 +248,13 @@ impl Client { Ok(self.nymd.get_contract_settings().await?) } + pub async fn get_current_epoch(&self) -> Result, ValidatorClientError> + where + C: CosmWasmClient + Sync, + { + Ok(self.nymd.get_current_epoch().await?) + } + pub async fn get_mixnet_contract_version(&self) -> Result where C: CosmWasmClient + Sync, @@ -276,20 +283,6 @@ impl Client { Ok(self.nymd.get_reward_pool().await?.u128()) } - pub async fn get_current_interval(&self) -> Result - where - C: CosmWasmClient + Sync, - { - Ok(self.nymd.get_current_interval().await?) - } - - pub async fn get_epochs_in_interval(&self) -> Result - where - C: CosmWasmClient + Sync, - { - Ok(self.nymd.get_epochs_in_interval().await?) - } - pub async fn get_circulating_supply(&self) -> Result where C: CosmWasmClient + Sync, @@ -311,6 +304,13 @@ impl Client { Ok(self.nymd.get_active_set_work_factor().await?) } + pub async fn get_epochs_in_interval(&self) -> Result + where + C: CosmWasmClient + Sync, + { + Ok(self.nymd.get_epochs_in_interval().await?) + } + pub async fn get_interval_reward_percent(&self) -> Result where C: CosmWasmClient + Sync, diff --git a/common/client-libs/validator-client/src/nymd/mod.rs b/common/client-libs/validator-client/src/nymd/mod.rs index df5079d2c4..96e75928e5 100644 --- a/common/client-libs/validator-client/src/nymd/mod.rs +++ b/common/client-libs/validator-client/src/nymd/mod.rs @@ -290,6 +290,16 @@ impl NymdClient { .await } + pub async fn get_current_epoch(&self) -> Result, NymdError> + where + C: CosmWasmClient + Sync, + { + let request = QueryMsg::GetCurrentEpoch {}; + self.client + .query_contract_smart(self.mixnet_contract_address()?, &request) + .await + } + pub async fn get_mixnet_contract_version(&self) -> Result where C: CosmWasmClient + Sync, @@ -369,16 +379,6 @@ impl NymdClient { .await } - pub async fn get_current_interval(&self) -> Result - where - C: CosmWasmClient + Sync, - { - let request = QueryMsg::GetCurrentInterval {}; - self.client - .query_contract_smart(self.mixnet_contract_address()?, &request) - .await - } - pub async fn get_reward_pool(&self) -> Result where C: CosmWasmClient + Sync, @@ -389,16 +389,6 @@ impl NymdClient { .await } - pub async fn get_epochs_in_interval(&self) -> Result - where - C: CosmWasmClient + Sync, - { - let request = QueryMsg::GetEpochsInInterval {}; - self.client - .query_contract_smart(self.mixnet_contract_address()?, &request) - .await - } - pub async fn get_circulating_supply(&self) -> Result where C: CosmWasmClient + Sync, @@ -439,6 +429,16 @@ impl NymdClient { .await } + pub async fn get_epochs_in_interval(&self) -> Result + where + C: CosmWasmClient + Sync, + { + let request = QueryMsg::GetEpochsInInterval {}; + self.client + .query_contract_smart(self.mixnet_contract_address()?, &request) + .await + } + /// Checks whether there is a bonded mixnode associated with the provided client's address pub async fn owns_mixnode(&self, address: &AccountId) -> Result, NymdError> where @@ -1205,25 +1205,6 @@ impl NymdClient { .await } - pub async fn advance_current_interval(&self) -> Result - where - C: SigningCosmWasmClient + Sync, - { - let fee = self.operation_fee(Operation::AdvanceCurrentInterval); - - let req = ExecuteMsg::AdvanceCurrentInterval {}; - self.client - .execute( - self.address(), - self.mixnet_contract_address()?, - &req, - fee, - "Advancing current interval", - Vec::new(), - ) - .await - } - pub async fn reconcile_delegations(&self) -> Result where C: SigningCosmWasmClient + Sync, diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/events.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/events.rs index 752952d450..8464fc6d4c 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/events.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/events.rs @@ -1,6 +1,5 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 - use crate::mixnode::NodeRewardResult; use crate::{ContractStateParams, IdentityKeyRef, Interval, Layer}; use cosmwasm_std::{Addr, Coin, Event, Uint128}; @@ -10,6 +9,7 @@ pub use contracts_common::events::*; // event types pub const DELEGATION_EVENT_TYPE: &str = "delegation"; pub const PENDING_DELEGATION_EVENT_TYPE: &str = "pending_delegation"; +pub const RECONCILE_DELEGATION_EVENT_TYPE: &str = "reconcile_delegation"; pub const UNDELEGATION_EVENT_TYPE: &str = "undelegation"; pub const PENDING_UNDELEGATION_EVENT_TYPE: &str = "pending_undelegation"; pub const GATEWAY_BONDING_EVENT_TYPE: &str = "gateway_bonding"; @@ -79,12 +79,17 @@ pub const NEW_CURRENT_INTERVAL_KEY: &str = "new_current_interval"; pub const NEW_CURRENT_EPOCH_KEY: &str = "new_current_epoch"; pub const BLOCK_HEIGHT_KEY: &str = "block_height"; pub const CHECKPOINT_MIXNODES_EVENT: &str = "checkpoint_mixnodes"; +pub const RECONCILIATION_ERROR_EVENT: &str = "reconciliation_error"; pub fn new_checkpoint_mixnodes_event(block_height: u64) -> Event { Event::new(CHECKPOINT_MIXNODES_EVENT) .add_attribute(BLOCK_HEIGHT_KEY, format!("{}", block_height)) } +pub fn new_error_event(err: String) -> Event { + Event::new(RECONCILIATION_ERROR_EVENT).add_attribute("error", err) +} + pub fn new_delegation_event( delegator: &Addr, proxy: &Option, @@ -122,6 +127,25 @@ pub fn new_pending_delegation_event( .add_attribute(DELEGATION_TARGET_KEY, mix_identity) } +pub fn new_reconcile_delegation_event( + delegator: &Addr, + proxy: &Option, + amount: &Coin, + mix_identity: IdentityKeyRef<'_>, +) -> Event { + let mut event = + Event::new(RECONCILE_DELEGATION_EVENT_TYPE).add_attribute(DELEGATOR_KEY, delegator); + + if let Some(proxy) = proxy { + event = event.add_attribute(PROXY_KEY, proxy) + } + + // coin implements Display trait and we use that implementation here + event + .add_attribute(AMOUNT_KEY, amount.to_string()) + .add_attribute(DELEGATION_TARGET_KEY, mix_identity) +} + pub fn new_compound_operator_reward_event(owner: &Addr, amount: Uint128) -> Event { let event = Event::new(COMPOUND_OPERATOR_REWARD_EVENT_TYPE).add_attribute(OWNER_KEY, owner); event.add_attribute(AMOUNT_KEY, amount.to_string()) @@ -388,13 +412,11 @@ pub fn new_change_rewarded_set_event( active_set_size: u32, rewarded_set_size: u32, nodes_in_rewarded_set: u32, - current_interval_id: u32, ) -> Event { Event::new(CHANGE_REWARDED_SET_EVENT_TYPE) .add_attribute(ACTIVE_SET_SIZE_KEY, active_set_size.to_string()) .add_attribute(REWARDED_SET_SIZE_KEY, rewarded_set_size.to_string()) .add_attribute(NODES_IN_REWARDED_SET_KEY, nodes_in_rewarded_set.to_string()) - .add_attribute(CURRENT_INTERVAL_ID_KEY, current_interval_id.to_string()) } pub fn new_advance_interval_event(interval: Interval) -> Event { diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/interval.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/interval.rs index 319d7f109b..019b7a7062 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/interval.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/interval.rs @@ -1,6 +1,7 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use cosmwasm_std::Env; use serde::{Deserialize, Serialize}; use std::convert::TryInto; use std::fmt::{Display, Formatter}; @@ -65,9 +66,23 @@ pub struct Interval { } impl Interval { - /// Creates new interval instance. - pub const fn new(id: u32, start: OffsetDateTime, length: Duration) -> Self { - Interval { id, start, length } + /// Initialize epoch in the contract with default values. + /// FIXME: THIS unwrap! + pub fn init_epoch(env: Env) -> Self { + Interval { + id: 0, + start: OffsetDateTime::from_unix_timestamp(env.block.time.seconds() as i64).unwrap(), + length: Duration::from_secs(3600), + } + } + + pub fn is_over(&self, env: Env) -> bool { + self.end_unix_timestamp() <= env.block.time.seconds() as i64 + } + + pub fn in_progress(&self, env: Env) -> bool { + let block_time = env.block.time.seconds() as i64; + self.start_unix_timestamp() <= block_time && block_time < self.end_unix_timestamp() } /// Returns the next interval. @@ -80,6 +95,17 @@ impl Interval { } } + pub fn next_on_chain(&self, env: Env) -> Self { + let start = self + .end() + .max(OffsetDateTime::from_unix_timestamp(env.block.time.seconds() as i64).unwrap()); + Interval { + id: self.id + 1, + start, + length: self.length, + } + } + /// Returns the last interval. pub fn previous(&self) -> Option { if self.id > 0 { diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/mixnode.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/mixnode.rs index 49ecd63228..41702fcc8e 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/mixnode.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/mixnode.rs @@ -296,7 +296,7 @@ pub struct MixNodeBond { pub block_height: u64, pub mix_node: MixNode, pub proxy: Option, - pub accumulated_rewards: Uint128, + pub accumulated_rewards: Option, } impl MixNodeBond { @@ -316,10 +316,14 @@ impl MixNodeBond { block_height, mix_node, proxy, - accumulated_rewards: Uint128::zero(), + accumulated_rewards: None, } } + pub fn accumulated_rewards(&self) -> Uint128 { + self.accumulated_rewards.unwrap_or_else(Uint128::zero) + } + pub fn profit_margin(&self) -> U128 { U128::from_num(self.mix_node.profit_margin_percent) / U128::from_num(100) } @@ -348,7 +352,7 @@ impl MixNodeBond { Some( self.pledge_amount.amount.u128() + self.total_delegation.amount.u128() - + self.accumulated_rewards.u128(), + + self.accumulated_rewards().u128(), ) } } @@ -614,7 +618,7 @@ mod tests { block_height: 100, mix_node: mixnode_fixture(), proxy: None, - accumulated_rewards: Uint128::zero(), + accumulated_rewards: Some(Uint128::zero()), }; let mix2 = MixNodeBond { @@ -625,7 +629,7 @@ mod tests { block_height: 120, mix_node: mixnode_fixture(), proxy: None, - accumulated_rewards: Uint128::zero(), + accumulated_rewards: Some(Uint128::zero()), }; let mix3 = MixNodeBond { @@ -636,7 +640,7 @@ mod tests { block_height: 120, mix_node: mixnode_fixture(), proxy: None, - accumulated_rewards: Uint128::zero(), + accumulated_rewards: Some(Uint128::zero()), }; let mix4 = MixNodeBond { @@ -647,7 +651,7 @@ mod tests { block_height: 120, mix_node: mixnode_fixture(), proxy: None, - accumulated_rewards: Uint128::zero(), + accumulated_rewards: Some(Uint128::zero()), }; let mix5 = MixNodeBond { @@ -658,7 +662,7 @@ mod tests { block_height: 120, mix_node: mixnode_fixture(), proxy: None, - accumulated_rewards: Uint128::zero(), + accumulated_rewards: Some(Uint128::zero()), }; // summary: diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs index 90cb5bac6b..dbb1b0c4fb 100644 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/msg.rs @@ -99,7 +99,7 @@ pub enum ExecuteMsg { rewarded_set: Vec, expected_active_set_size: u32, }, - AdvanceCurrentInterval {}, + // AdvanceCurrentInterval {}, AdvanceCurrentEpoch {}, } @@ -164,13 +164,10 @@ pub enum QueryMsg { start_after: Option, limit: Option, }, - GetRewardedSetHeightsForInterval { - interval_id: u32, - }, GetRewardedSetUpdateDetails {}, GetCurrentRewardedSetHeight {}, - GetCurrentInterval {}, GetRewardedSetRefreshBlocks {}, + GetCurrentEpoch {}, GetEpochsInInterval {}, } diff --git a/common/socks5/proxy-helpers/Cargo.toml b/common/socks5/proxy-helpers/Cargo.toml index e3e6470a03..77c9e4cf7e 100644 --- a/common/socks5/proxy-helpers/Cargo.toml +++ b/common/socks5/proxy-helpers/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] bytes = "1.0" -tokio = { version = "1.4", features = [ "net", "io-util", "sync", "macros", "time" ] } +tokio = { version = "1.4", features = [ "net", "io-util", "sync", "macros", "time", "rt-multi-thread" ] } tokio-util = { version = "0.6", features = [ "io" ] } # reason for getting this guy is to to able to port to tokio 1.X more quickly by being able to use # their `read_buf` [from the util crate] replacement rather than having to rethink/reimplement `AvailableReader` with the new AsyncRead trait definition. # In the long run, the dependency should probably get removed in favour of pure-tokio implementation, but for time being it's fine. @@ -18,5 +18,4 @@ socks5-requests = { path = "../requests" } ordered-buffer = { path = "../ordered-buffer" } [dev-dependencies] -tokio = { version = "1.4", features = ["rt-multi-thread"] } tokio-test = "0.4" \ No newline at end of file diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index cdf52b9419..9758571507 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -218,9 +218,9 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.0.0-beta5" +version = "1.0.0-beta6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8904127a5b9e325ef5d6b2b3f997dcd74943cd35097139b1a4d15b1b6bccae66" +checksum = "2dddc1443004c6340e55ca66d98e9d2f1a44aadf4ce2bed2c4f29baa8a15e7b7" dependencies = [ "digest 0.9.0", "ed25519-zebra", @@ -231,9 +231,9 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.0.0-beta5" +version = "1.0.0-beta6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a14364ac4d9d085867929d0cf3e94b1d2100121ce02c33c72961406830002613" +checksum = "fe4f0f10f165b8bcc558a13cddb498140960544519aa0581532c766dd80b5598" dependencies = [ "syn", ] @@ -250,13 +250,14 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.0.0-beta5" +version = "1.0.0-beta6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2ece12e5bbde434b93937d7b2107e6291f11d69ffa72398c50e8bab41d451d3" +checksum = "2f0f3145097b692b2d95fa5d2c7c6fdd60f193ccc709857e7e1987a608725300" dependencies = [ "base64", "cosmwasm-crypto", "cosmwasm-derive", + "forward_ref", "schemars", "serde", "serde-json-wasm", @@ -536,6 +537,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + [[package]] name = "generic-array" version = "0.12.4" diff --git a/contracts/mixnet/src/constants.rs b/contracts/mixnet/src/constants.rs index 7d80b80c22..37ca8a2b90 100644 --- a/contracts/mixnet/src/constants.rs +++ b/contracts/mixnet/src/constants.rs @@ -1,8 +1,6 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use std::time::Duration; - // approximately 1 week (assuming 5s per block) // i.e. approximately quarter of the interval (there are 3600 * 60 * 7 = 604800 seconds in a week, i.e. ~604800 / 5 = 120960 blocks) pub const MINIMUM_BLOCK_AGE_FOR_REWARDING: u64 = 120960; @@ -17,5 +15,3 @@ pub const ACTIVE_SET_WORK_FACTOR: u8 = 10; // would be messed up... (as we look up stuff "by blocks") pub const REWARDED_SET_REFRESH_BLOCKS: u64 = 720; // with blocktime being approximately 5s, it should be roughly 1h pub const EPOCHS_IN_INTERVAL: u64 = 720; // Hours in a month - -pub const REWARDING_INTERVAL_LENGTH: Duration = Duration::from_secs(60 * 60 * 720); // 720h, i.e. 30 days diff --git a/contracts/mixnet/src/contract.rs b/contracts/mixnet/src/contract.rs index 9aa088b39e..c39e49b80b 100644 --- a/contracts/mixnet/src/contract.rs +++ b/contracts/mixnet/src/contract.rs @@ -1,10 +1,7 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::constants::{ - ACTIVE_SET_WORK_FACTOR, INTERVAL_REWARD_PERCENT, REWARDING_INTERVAL_LENGTH, - SYBIL_RESISTANCE_PERCENT, -}; +use crate::constants::{ACTIVE_SET_WORK_FACTOR, INTERVAL_REWARD_PERCENT, SYBIL_RESISTANCE_PERCENT}; use crate::delegations::queries::query_all_network_delegations_paged; use crate::delegations::queries::query_delegator_delegations_paged; use crate::delegations::queries::query_mixnode_delegation; @@ -12,10 +9,10 @@ use crate::delegations::queries::query_mixnode_delegations_paged; use crate::error::ContractError; use crate::gateways::queries::query_gateways_paged; use crate::gateways::queries::query_owns_gateway; +use crate::interval::queries::query_current_epoch; use crate::interval::queries::{ - query_current_interval, query_current_rewarded_set_height, query_rewarded_set, - query_rewarded_set_heights_for_interval, query_rewarded_set_refresh_minimum_blocks, - query_rewarded_set_update_details, + query_current_rewarded_set_height, query_rewarded_set, + query_rewarded_set_refresh_minimum_blocks, query_rewarded_set_update_details, }; use crate::interval::storage as interval_storage; use crate::mixnet_contract_settings::models::ContractState; @@ -34,7 +31,7 @@ use cosmwasm_std::{ entry_point, to_binary, Addr, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response, Uint128, }; use mixnet_contract_common::{ - ContractStateParams, ExecuteMsg, InstantiateMsg, Interval, MigrateMsg, QueryMsg, + ContractStateParams, Delegation, ExecuteMsg, InstantiateMsg, Interval, MigrateMsg, QueryMsg, }; use time::OffsetDateTime; @@ -80,13 +77,12 @@ pub fn instantiate( ) -> Result { let rewarding_validator_address = deps.api.addr_validate(&msg.rewarding_validator_address)?; let state = default_initial_state(info.sender, rewarding_validator_address); - let rewarding_interval = - Interval::new(0, DEFAULT_FIRST_INTERVAL_START, REWARDING_INTERVAL_LENGTH); + let rewarding_interval = Interval::init_epoch(env.clone()); mixnet_params_storage::CONTRACT_STATE.save(deps.storage, &state)?; mixnet_params_storage::LAYERS.save(deps.storage, &Default::default())?; rewards_storage::REWARD_POOL.save(deps.storage, &Uint128::new(INITIAL_REWARD_POOL))?; - interval_storage::save_interval(deps.storage, &rewarding_interval)?; + interval_storage::save_epoch(deps.storage, &rewarding_interval)?; interval_storage::CURRENT_REWARDED_SET_HEIGHT.save(deps.storage, &env.block.height)?; Ok(Response::default()) @@ -242,9 +238,6 @@ pub fn execute( rewarded_set, expected_active_set_size, ), - ExecuteMsg::AdvanceCurrentInterval {} => { - crate::interval::transactions::try_advance_interval(env, deps.storage) - } ExecuteMsg::AdvanceCurrentEpoch {} => { crate::interval::transactions::try_advance_epoch(env, deps.storage) } @@ -354,27 +347,69 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result to_binary( - &query_rewarded_set_heights_for_interval(deps.storage, interval_id)?, - ), QueryMsg::GetRewardedSetUpdateDetails {} => { to_binary(&query_rewarded_set_update_details(env, deps.storage)?) } QueryMsg::GetCurrentRewardedSetHeight {} => { to_binary(&query_current_rewarded_set_height(deps.storage)?) } - QueryMsg::GetCurrentInterval {} => to_binary(&query_current_interval(deps.storage)?), + // QueryMsg::GetCurrentInterval {} => to_binary(&query_current_interval(deps.storage)?), QueryMsg::GetRewardedSetRefreshBlocks {} => { to_binary(&query_rewarded_set_refresh_minimum_blocks()) } QueryMsg::GetEpochsInInterval {} => to_binary(&crate::constants::EPOCHS_IN_INTERVAL), + QueryMsg::GetCurrentEpoch {} => to_binary(&query_current_epoch(deps.storage)?), }; Ok(query_res?) } #[entry_point] -pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result { +pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result { + use crate::delegations::storage::{ + DelegationIndex, DELEGATION_MIXNODE_IDX_NAMESPACE, DELEGATION_OWNER_IDX_NAMESPACE, + DELEGATION_PK_NAMESPACE, + }; + use cosmwasm_std::Order; + use cw_storage_plus::{IndexedMap, MultiIndex}; + + type PrimaryKey = Vec; + + fn old_delegations<'a>() -> IndexedMap<'a, PrimaryKey, Delegation, DelegationIndex<'a>> { + let indexes = DelegationIndex { + owner: MultiIndex::new( + |d| d.owner.clone(), + DELEGATION_PK_NAMESPACE, + DELEGATION_OWNER_IDX_NAMESPACE, + ), + mixnode: MultiIndex::new( + |d| d.node_identity.clone(), + DELEGATION_PK_NAMESPACE, + DELEGATION_MIXNODE_IDX_NAMESPACE, + ), + }; + + IndexedMap::new(DELEGATION_PK_NAMESPACE, indexes) + } + + let old_delegations = old_delegations() + .range(deps.storage, None, None, Order::Ascending) + .filter_map(|r| r.ok()) + .map(|(_key, delegation)| delegation) + .collect::>(); + + for delegation in old_delegations { + crate::delegations::storage::delegations().save( + deps.storage, + ( + delegation.node_identity(), + delegation.owner().as_bytes().to_vec(), + delegation.block_height(), + ), + &delegation, + )?; + } + Ok(Default::default()) } diff --git a/contracts/mixnet/src/delegations/storage.rs b/contracts/mixnet/src/delegations/storage.rs index c9e4dc2c64..976b6bd8ac 100644 --- a/contracts/mixnet/src/delegations/storage.rs +++ b/contracts/mixnet/src/delegations/storage.rs @@ -5,9 +5,9 @@ use cw_storage_plus::{Index, IndexList, IndexedMap, Map, MultiIndex}; use mixnet_contract_common::{mixnode::DelegationEvent, Addr, Delegation, IdentityKey}; // storage prefixes -const DELEGATION_PK_NAMESPACE: &str = "dl"; -const DELEGATION_OWNER_IDX_NAMESPACE: &str = "dlo"; -const DELEGATION_MIXNODE_IDX_NAMESPACE: &str = "dlm"; +pub const DELEGATION_PK_NAMESPACE: &str = "dl"; +pub const DELEGATION_OWNER_IDX_NAMESPACE: &str = "dlo"; +pub const DELEGATION_MIXNODE_IDX_NAMESPACE: &str = "dlm"; pub const PENDING_DELEGATION_EVENTS: Map< (BlockHeight, IdentityKey, OwnerAddress), diff --git a/contracts/mixnet/src/delegations/transactions.rs b/contracts/mixnet/src/delegations/transactions.rs index 693916ecbb..b0a7f181cf 100644 --- a/contracts/mixnet/src/delegations/transactions.rs +++ b/contracts/mixnet/src/delegations/transactions.rs @@ -11,7 +11,8 @@ use cosmwasm_std::{ Response, Storage, Uint128, WasmMsg, }; use mixnet_contract_common::events::{ - new_pending_delegation_event, new_pending_undelegation_event, new_undelegation_event, + new_error_event, new_pending_delegation_event, new_pending_undelegation_event, + new_undelegation_event, }; use mixnet_contract_common::mixnode::{DelegationEvent, PendingUndelegate}; use mixnet_contract_common::{Delegation, IdentityKey}; @@ -53,7 +54,9 @@ pub(crate) fn _try_reconcile_all_delegation_events( let undelegate_response = try_reconcile_undelegation(storage, api, &pending_undelegate)?; response = response.add_event(undelegate_response.event); - response = response.add_message(undelegate_response.bank_msg); + if let Some(msg) = undelegate_response.bank_msg { + response = response.add_message(msg); + } if let Some(msg) = undelegate_response.wasm_msg { response = response.add_message(msg); } @@ -232,7 +235,7 @@ pub(crate) fn try_remove_delegation_from_mixnode_on_behalf( } pub struct ReconcileUndelegateResponse { - bank_msg: BankMsg, + bank_msg: Option, wasm_msg: Option, event: Event, } @@ -260,9 +263,16 @@ pub(crate) fn try_reconcile_undelegation( .is_some(); if !any_delegations { - return Err(ContractError::NoMixnodeDelegationFound { - identity: pending_undelegate.mix_identity(), - address: pending_undelegate.delegate().to_string(), + return Ok(ReconcileUndelegateResponse { + bank_msg: None, + wasm_msg: None, + event: new_error_event( + ContractError::NoMixnodeDelegationFound { + identity: pending_undelegate.mix_identity(), + address: pending_undelegate.delegate().to_string(), + } + .to_string(), + ), }); } @@ -283,9 +293,16 @@ pub(crate) fn try_reconcile_undelegation( .collect::>(); if delegation_heights.is_empty() { - return Err(ContractError::NoMixnodeDelegationFound { - identity: pending_undelegate.mix_identity(), - address: pending_undelegate.delegate().to_string(), + return Ok(ReconcileUndelegateResponse { + bank_msg: None, + wasm_msg: None, + event: new_error_event( + ContractError::NoMixnodeDelegationFound { + identity: pending_undelegate.mix_identity(), + address: pending_undelegate.delegate().to_string(), + } + .to_string(), + ), }); } @@ -354,7 +371,7 @@ pub(crate) fn try_reconcile_undelegation( ); Ok(ReconcileUndelegateResponse { - bank_msg, + bank_msg: Some(bank_msg), wasm_msg, event, }) diff --git a/contracts/mixnet/src/error.rs b/contracts/mixnet/src/error.rs index dce9955fe5..3fcbb8df10 100644 --- a/contracts/mixnet/src/error.rs +++ b/contracts/mixnet/src/error.rs @@ -132,6 +132,20 @@ pub enum ContractError { epoch_end: i64, }, + #[error("MIXNET ({}): Can't change to the desired interval as it hasn't started yet. It starts at {epoch_start} and finishes at {epoch_end}, while the current block time is {current_block_time}", line!())] + EpochNotStarted { + current_block_time: u64, + epoch_start: i64, + epoch_end: i64, + }, + + #[error("MIXNET ({}): Can't change to the desired interval as it's in progress. It starts at {epoch_start} and finishes at {epoch_end}, while the current block time is {current_block_time}", line!())] + EpochInProgress { + current_block_time: u64, + epoch_start: i64, + epoch_end: i64, + }, + #[error("Could not cast reward to a u128, this should be impossible, at {}", line!())] CastError, #[error("{source}")] @@ -141,4 +155,7 @@ pub enum ContractError { }, #[error("No rewards to claim for mixnode {identity} for delegate {delegate}")] NoRewardsToClaim { identity: String, delegate: String }, + + #[error("Epoch not initialized yet!")] + EpochNotInitialized, } diff --git a/contracts/mixnet/src/interval/queries.rs b/contracts/mixnet/src/interval/queries.rs index 2fdc48ba27..41cfb4e8cf 100644 --- a/contracts/mixnet/src/interval/queries.rs +++ b/contracts/mixnet/src/interval/queries.rs @@ -6,37 +6,18 @@ use crate::error::ContractError; use cosmwasm_std::{Env, Order, StdResult, Storage}; use cw_storage_plus::Bound; use mixnet_contract_common::{ - IdentityKey, Interval, IntervalRewardedSetHeightsResponse, PagedRewardedSetResponse, - RewardedSetNodeStatus, RewardedSetUpdateDetails, + IdentityKey, Interval, PagedRewardedSetResponse, RewardedSetNodeStatus, + RewardedSetUpdateDetails, }; -pub fn query_current_interval(storage: &dyn Storage) -> Result { - storage::current_interval(storage) +pub fn query_current_epoch(storage: &dyn Storage) -> Result, ContractError> { + storage::current_epoch(storage) } pub(crate) fn query_rewarded_set_refresh_minimum_blocks() -> u64 { crate::constants::REWARDED_SET_REFRESH_BLOCKS } -pub fn query_rewarded_set_heights_for_interval( - storage: &dyn Storage, - interval_id: u32, -) -> Result { - // I don't think we have to deal with paging here as at most we're going to have 720 values here - // and I think the validators are capable of performing 720 storage reads at once if they're only - // reading u64 (+ u8) values... - let heights = storage::REWARDED_SET_HEIGHTS_FOR_INTERVAL - .prefix(interval_id) - .range(storage, None, None, Order::Ascending) - .map(|val| val.map(|(height, _)| height)) - .collect::>>()?; - - Ok(IntervalRewardedSetHeightsResponse { - interval_id, - heights, - }) -} - // note: I have removed the `query_rewarded_set_for_interval`, because I don't think it's appropriate // for the contract to go through so much data (i.e. all "rewarded" sets of particular interval) in one go. // To achieve the same result, the client would have to instead first call `query_rewarded_set_heights_for_interval` @@ -127,47 +108,6 @@ mod tests { identities } - #[test] - fn querying_for_rewarded_set_heights_for_interval() { - let mut deps = test_helpers::init_contract(); - - // no data - assert!( - query_rewarded_set_heights_for_interval(deps.as_ref().storage, 0) - .unwrap() - .heights - .is_empty() - ); - - // 100 heights - for i in 0..100 { - storage::REWARDED_SET_HEIGHTS_FOR_INTERVAL - .save(deps.as_mut().storage, (1, i), &0u8) - .unwrap(); - } - let expected = (0..100).collect::>(); - assert_eq!( - expected, - query_rewarded_set_heights_for_interval(deps.as_ref().storage, 1) - .unwrap() - .heights - ); - - // 100 heights for different interval - for i in 200..300 { - storage::REWARDED_SET_HEIGHTS_FOR_INTERVAL - .save(deps.as_mut().storage, (10, i), &0u8) - .unwrap(); - } - let expected = (200..300).collect::>(); - assert_eq!( - expected, - query_rewarded_set_heights_for_interval(deps.as_ref().storage, 10) - .unwrap() - .heights - ) - } - #[test] fn querying_for_rewarded_set_at_height() { let mut deps = test_helpers::init_contract(); diff --git a/contracts/mixnet/src/interval/storage.rs b/contracts/mixnet/src/interval/storage.rs index 171628700f..89d054c55a 100644 --- a/contracts/mixnet/src/interval/storage.rs +++ b/contracts/mixnet/src/interval/storage.rs @@ -18,32 +18,24 @@ type IntervalId = u32; pub(crate) const REWARDED_NODE_DEFAULT_PAGE_LIMIT: u32 = 1000; pub(crate) const REWARDED_NODE_MAX_PAGE_LIMIT: u32 = 1500; -const CURRENT_INTERVAL: Item<'_, Interval> = Item::new("cei"); -const CURRENT_EPOCH: Item<'_, Interval> = Item::new("cep"); +const CURRENT_EPOCH: Item<'_, Interval> = Item::new("ceph"); const CURRENT_EPOCH_REWARD_PARAMS: Item<'_, EpochRewardParams> = Item::new("erp"); pub(crate) const CURRENT_REWARDED_SET_HEIGHT: Item<'_, BlockHeight> = Item::new("crh"); // I've changed the `()` data to an `u8` as after serializing `()` is represented as "null", // taking more space than a single digit u8. If we don't care about what's there, why not go with more efficient approach? : ) -pub(crate) const REWARDED_SET_HEIGHTS_FOR_INTERVAL: Map<'_, (IntervalId, BlockHeight), u8> = - Map::new("rsh"); +// pub(crate) const REWARDED_SET_HEIGHTS_FOR_INTERVAL: Map<'_, (IntervalId, BlockHeight), u8> = +// Map::new("rsh"); // pub(crate) const REWARDED_SET: Map<(u64, IdentityKey), NodeStatus> = Map::new("rs"); pub(crate) const REWARDED_SET: Map<'_, (BlockHeight, IdentityKey), RewardedSetNodeStatus> = Map::new("rs"); -pub(crate) const INTERVALS: Map<'_, IntervalId, Interval> = Map::new("ins"); pub(crate) const EPOCHS: Map<'_, IntervalId, Interval> = Map::new("ephs"); -pub fn save_interval(storage: &mut dyn Storage, interval: &Interval) -> Result<(), ContractError> { - CURRENT_INTERVAL.save(storage, interval)?; - INTERVALS.save(storage, interval.id(), interval)?; - Ok(()) -} - -pub fn save_epoch(storage: &mut dyn Storage, interval: &Interval) -> Result<(), ContractError> { - CURRENT_EPOCH.save(storage, interval)?; - EPOCHS.save(storage, interval.id(), interval)?; +pub fn save_epoch(storage: &mut dyn Storage, epoch: &Interval) -> Result<(), ContractError> { + CURRENT_EPOCH.save(storage, epoch)?; + EPOCHS.save(storage, epoch.id(), epoch)?; Ok(()) } @@ -63,12 +55,8 @@ pub fn save_epoch_reward_params( Ok(()) } -pub fn current_interval(storage: &dyn Storage) -> Result { - Ok(CURRENT_INTERVAL.load(storage)?) -} - -pub fn current_epoch(storage: &dyn Storage) -> Result { - Ok(CURRENT_EPOCH.load(storage)?) +pub fn current_epoch(storage: &dyn Storage) -> Result, ContractError> { + Ok(CURRENT_EPOCH.may_load(storage)?) } pub(crate) fn save_rewarded_set( diff --git a/contracts/mixnet/src/interval/transactions.rs b/contracts/mixnet/src/interval/transactions.rs index 21b48e1e33..8cb2f9f54f 100644 --- a/contracts/mixnet/src/interval/transactions.rs +++ b/contracts/mixnet/src/interval/transactions.rs @@ -3,11 +3,11 @@ use super::storage; use crate::error::ContractError; -use crate::error::ContractError::{EpochNotInProgress, IntervalNotInProgress}; +use crate::error::ContractError::EpochInProgress; use crate::mixnet_contract_settings::storage as mixnet_params_storage; use cosmwasm_std::{DepsMut, Env, MessageInfo, Response, Storage}; use mixnet_contract_common::events::{new_advance_interval_event, new_change_rewarded_set_event}; -use mixnet_contract_common::IdentityKey; +use mixnet_contract_common::{IdentityKey, Interval}; // We've distributed the rewards to the rewarded set from the validator api before making this call (implicit order, should be solved in the future) // We now write the new rewarded set, snapshot the mixnodes and finally reconcile all delegations and undelegations. That way the rewards for the previous @@ -52,84 +52,48 @@ pub fn try_write_rewarded_set( current_height: block_height, }); } - - let current_interval = storage::current_interval(deps.storage)?.id(); let num_nodes = rewarded_set.len(); storage::save_rewarded_set(deps.storage, block_height, active_set_size, rewarded_set)?; - storage::REWARDED_SET_HEIGHTS_FOR_INTERVAL.save( - deps.storage, - (current_interval, block_height), - &0u8, - )?; storage::CURRENT_REWARDED_SET_HEIGHT.save(deps.storage, &block_height)?; Ok(Response::new().add_event(new_change_rewarded_set_event( state.params.mixnode_active_set_size, state.params.mixnode_rewarded_set_size, num_nodes as u32, - current_interval, ))) } -pub fn try_advance_interval( - env: Env, - storage: &mut dyn Storage, -) -> Result { - // in theory, we could have just changed the state and relied on its reversal upon failed - // execution, but better safe than sorry and do not modify the state at all unless we know - // all checks have succeeded. - let current_interval = storage::current_interval(storage)?; - let next_interval = current_interval.next(); - - if next_interval.start_unix_timestamp() > env.block.time.seconds() as i64 { - // the reason for this check is as follows: - // nobody, even trusted validators, should be able to continuously keep advancing intervals, - // because otherwise it would be possible for them to continuously keep rewarding nodes. - // - // Therefore, even if "trusted" validator, responsible for rewarding, is malicious, - // they can't send rewards more often than every `REWARDED_SET_REFRESH_BLOCKS` - // and changing this value requires going through governance and having agreement of - // the super-majority of the validators (by stake) - return Err(IntervalNotInProgress { - current_block_time: env.block.time.seconds(), - interval_start: next_interval.start_unix_timestamp(), - interval_end: next_interval.end_unix_timestamp(), - }); - } - - storage::save_interval(storage, &next_interval)?; - - Ok(Response::new().add_event(new_advance_interval_event(next_interval))) +fn init_epoch(storage: &mut dyn Storage, env: Env) -> Result { + let epoch = Interval::init_epoch(env); + storage::save_epoch(storage, &epoch)?; + Ok(epoch) } pub fn try_advance_epoch(env: Env, storage: &mut dyn Storage) -> Result { // in theory, we could have just changed the state and relied on its reversal upon failed // execution, but better safe than sorry and do not modify the state at all unless we know // all checks have succeeded. - let current_epoch = storage::current_epoch(storage)?; - let next_epoch = current_epoch.next(); + let current_epoch = if let Some(epoch) = storage::current_epoch(storage)? { + epoch + } else { + let epoch = init_epoch(storage, env)?; + return Ok(Response::new().add_event(new_advance_interval_event(epoch))); + }; - if next_epoch.start_unix_timestamp() > env.block.time.seconds() as i64 { - // the reason for this check is as follows: - // nobody, even trusted validators, should be able to continuously keep advancing epochs, - // because otherwise it would be possible for them to continuously keep rewarding nodes. - // - // Therefore, even if "trusted" validator, responsible for rewarding, is malicious, - // they can't send rewards more often than every `REWARDED_SET_REFRESH_BLOCKS` - // and changing this value requires going through governance and having agreement of - // the super-majority of the validators (by stake) - return Err(EpochNotInProgress { - current_block_time: env.block.time.seconds(), - epoch_start: next_epoch.start_unix_timestamp(), - epoch_end: next_epoch.end_unix_timestamp(), - }); + if current_epoch.is_over(env.clone()) { + let next_epoch = current_epoch.next_on_chain(env); + + storage::save_epoch(storage, &next_epoch)?; + storage::save_epoch_reward_params(next_epoch.id(), storage)?; + + return Ok(Response::new().add_event(new_advance_interval_event(next_epoch))); } - - storage::save_epoch(storage, &next_epoch)?; - storage::save_epoch_reward_params(next_epoch.id(), storage)?; - - Ok(Response::new().add_event(new_advance_interval_event(next_epoch))) + Err(EpochInProgress { + current_block_time: env.block.time.seconds(), + epoch_start: current_epoch.start_unix_timestamp(), + epoch_end: current_epoch.end_unix_timestamp(), + }) } #[cfg(test)] @@ -226,7 +190,6 @@ mod tests { current_state.params.mixnode_active_set_size, current_state.params.mixnode_rewarded_set_size, full_rewarded_set.len() as u32, - 0, )); assert_eq!( @@ -257,8 +220,6 @@ mod tests { ) } } - assert!(storage::REWARDED_SET_HEIGHTS_FOR_INTERVAL - .has(deps.as_ref().storage, (0, env.block.height))); assert_eq!( env.block.height, storage::CURRENT_REWARDED_SET_HEIGHT @@ -268,7 +229,7 @@ mod tests { } #[test] - fn advancing_interval() { + fn advancing_epoch() { let mut env = mock_env(); let mut deps = test_helpers::init_contract(); @@ -278,59 +239,50 @@ mod tests { // 1643673600 = 2022-02-01 // 1672531200 = 2023-01-01 - let current_interval = Interval::new( - 0, - OffsetDateTime::from_unix_timestamp(1640995200).unwrap(), - Duration::from_secs(60 * 60 * 720), - ); - let next_interval = current_interval.next(); - storage::save_interval(deps.as_mut().storage, ¤t_interval).unwrap(); + let _current_epoch = init_epoch(&mut deps.storage, env.clone()).unwrap(); - // fails if the current interval hasn't finished yet i.e. the new interval hasn't begun + // Works as its after the current epoch env.block.time = Timestamp::from_seconds(1641081600); - assert_eq!( - Err(ContractError::IntervalNotInProgress { - current_block_time: 1641081600, - interval_start: next_interval.start_unix_timestamp(), - interval_end: next_interval.end_unix_timestamp() - }), - try_advance_interval(env.clone(), deps.as_mut().storage) - ); + assert!(try_advance_epoch(env.clone(), deps.as_mut().storage).is_ok()); + + let current_epoch = crate::interval::storage::current_epoch(&mut deps.storage) + .unwrap() + .unwrap(); // same if the current blocktime is set to BEFORE the first interval has even begun // (say we decided to set the first interval to be some time in the future at initialisation) env.block.time = Timestamp::from_seconds(1609459200); assert_eq!( - Err(ContractError::IntervalNotInProgress { + Err(ContractError::EpochInProgress { current_block_time: 1609459200, - interval_start: next_interval.start_unix_timestamp(), - interval_end: next_interval.end_unix_timestamp() + epoch_start: current_epoch.start_unix_timestamp(), + epoch_end: current_epoch.end_unix_timestamp() }), - try_advance_interval(env.clone(), deps.as_mut().storage) + try_advance_epoch(env.clone(), deps.as_mut().storage) ); // works otherwise // interval that has just finished env.block.time = - Timestamp::from_seconds(next_interval.start_unix_timestamp() as u64 + 10000); - let expected_new_interval = current_interval.next(); + Timestamp::from_seconds(current_epoch.start_unix_timestamp() as u64 + 10000); + let expected_new_epoch = current_epoch.next_on_chain(env.clone()); let expected_response = - Response::new().add_event(new_advance_interval_event(expected_new_interval)); + Response::new().add_event(new_advance_interval_event(expected_new_epoch)); assert_eq!( Ok(expected_response), - try_advance_interval(env.clone(), deps.as_mut().storage) + try_advance_epoch(env.clone(), deps.as_mut().storage) ); // interval way back in the past (i.e. 'somebody' failed to advance it for a long time) env.block.time = Timestamp::from_seconds(1672531200); - storage::save_interval(deps.as_mut().storage, ¤t_interval).unwrap(); - let expected_new_interval = current_interval.next(); + storage::save_epoch(deps.as_mut().storage, ¤t_epoch).unwrap(); + let expected_new_epoch = current_epoch.next_on_chain(env.clone()); let expected_response = - Response::new().add_event(new_advance_interval_event(expected_new_interval)); + Response::new().add_event(new_advance_interval_event(expected_new_epoch)); assert_eq!( Ok(expected_response), - try_advance_interval(env.clone(), deps.as_mut().storage) + try_advance_epoch(env.clone(), deps.as_mut().storage) ); } } diff --git a/contracts/mixnet/src/mixnodes/storage.rs b/contracts/mixnet/src/mixnodes/storage.rs index 765888c2b1..8c10e22f52 100644 --- a/contracts/mixnet/src/mixnodes/storage.rs +++ b/contracts/mixnet/src/mixnodes/storage.rs @@ -61,7 +61,7 @@ pub(crate) struct StoredMixnodeBond { pub block_height: u64, pub mix_node: MixNode, pub proxy: Option, - pub accumulated_rewards: Uint128, + pub accumulated_rewards: Option, pub epoch_rewards: Option, } @@ -89,7 +89,7 @@ impl StoredMixnodeBond { block_height: u64, mix_node: MixNode, proxy: Option, - accumulated_rewards: Uint128, + accumulated_rewards: Option, epoch_rewards: Option, ) -> Self { StoredMixnodeBond { @@ -104,6 +104,10 @@ impl StoredMixnodeBond { } } + pub(crate) fn accumulated_rewards(&self) -> Uint128 { + self.accumulated_rewards.unwrap_or_else(Uint128::zero) + } + pub(crate) fn attach_delegation(self, total_delegation: Uint128) -> MixNodeBond { MixNodeBond { total_delegation: Coin { @@ -216,7 +220,7 @@ mod tests { ..tests::fixtures::mix_node_fixture() }, proxy: None, - accumulated_rewards: Uint128::zero(), + accumulated_rewards: None, epoch_rewards: None, }; diff --git a/contracts/mixnet/src/mixnodes/transactions.rs b/contracts/mixnet/src/mixnodes/transactions.rs index 08ad43f62d..60fd3e452e 100644 --- a/contracts/mixnet/src/mixnodes/transactions.rs +++ b/contracts/mixnet/src/mixnodes/transactions.rs @@ -135,7 +135,7 @@ fn _try_add_mixnode( env.block.height, mix_node, proxy.clone(), - Uint128::zero(), + None, None, ); diff --git a/contracts/mixnet/src/rewards/queries.rs b/contracts/mixnet/src/rewards/queries.rs index 4038e193bb..c33c5c01bd 100644 --- a/contracts/mixnet/src/rewards/queries.rs +++ b/contracts/mixnet/src/rewards/queries.rs @@ -35,14 +35,14 @@ pub(crate) mod tests { #[cfg(test)] mod querying_for_rewarding_status { use super::*; + use crate::constants; use crate::delegations::transactions::try_delegate_to_mixnode; use crate::interval::storage::{save_epoch, save_epoch_reward_params}; use crate::rewards::transactions::try_reward_mixnode; - use crate::{constants, support::tests::fixtures::epoch_fixture}; use config::defaults::DENOM; use cosmwasm_std::{coin, Addr}; use mixnet_contract_common::{ - RewardingResult, RewardingStatus, MIXNODE_DELEGATORS_PAGE_LIMIT, + Interval, RewardingResult, RewardingStatus, MIXNODE_DELEGATORS_PAGE_LIMIT, }; #[test] @@ -107,7 +107,7 @@ pub(crate) mod tests { let info = mock_info(rewarding_validator_address.as_ref(), &[]); - let epoch = epoch_fixture(); + let epoch = Interval::init_epoch(env.clone()); save_epoch(&mut deps.storage, &epoch).unwrap(); save_epoch_reward_params(epoch.id(), &mut deps.storage).unwrap(); diff --git a/contracts/mixnet/src/rewards/transactions.rs b/contracts/mixnet/src/rewards/transactions.rs index 38e53e553e..cf3e5a4772 100644 --- a/contracts/mixnet/src/rewards/transactions.rs +++ b/contracts/mixnet/src/rewards/transactions.rs @@ -71,7 +71,7 @@ pub fn _try_compound_operator_reward( let mut updated_bond = bond.clone(); let reward = calculate_operator_reward(storage, owner, &bond)?; - updated_bond.accumulated_rewards -= reward; + updated_bond.accumulated_rewards = Some(updated_bond.accumulated_rewards() - reward); updated_bond.pledge_amount.amount += reward; mixnodes().replace( storage, @@ -216,7 +216,7 @@ pub fn _try_compound_delegator_reward( { // Node exists all is well, life goes on, if it does not exist we'll just return the reward to the caller as there is nothing to do on the bond if let Some(mut bond) = mixnodes().may_load(storage, mix_identity)? { - bond.accumulated_rewards -= reward; + bond.accumulated_rewards = Some(bond.accumulated_rewards() - reward); mixnodes().save(storage, mix_identity, &bond, block_height)?; } }; @@ -318,7 +318,11 @@ fn verify_rewarding_state( return Err(ContractError::Unauthorized); } - let current_interval = interval_storage::current_interval(storage)?; + let current_interval = if let Some(epoch) = interval_storage::current_epoch(storage)? { + epoch + } else { + return Err(ContractError::EpochNotInitialized); + }; // make sure the transaction is sent for the correct interval // (guard ourselves against somebody trying to send stale results; @@ -415,7 +419,8 @@ pub(crate) fn try_reward_mixnode( let node_reward_result = current_bond.reward(&reward_params); let stored_node_result: StoredNodeRewardResult = node_reward_result.try_into()?; - current_bond.accumulated_rewards += stored_node_result.reward(); + current_bond.accumulated_rewards = + Some(current_bond.accumulated_rewards() + stored_node_result.reward()); let mut stored_bond: StoredMixnodeBond = current_bond.into(); // technically we don't have to set the total_delegation bucket, but it makes things easier // in different places that we can guarantee that if node exists, so does the data behind the total delegation @@ -465,23 +470,24 @@ pub mod tests { use crate::interval::storage::{ current_epoch_reward_params, save_epoch, save_epoch_reward_params, }; + use crate::interval::transactions::try_advance_epoch; use crate::mixnet_contract_settings::storage as mixnet_params_storage; use crate::mixnodes::storage as mixnodes_storage; use crate::mixnodes::storage::StoredMixnodeBond; use crate::rewards::transactions::try_reward_mixnode; use crate::support::tests; - use crate::support::tests::fixtures::epoch_fixture; use crate::support::tests::test_helpers; use az::CheckedCast; use config::defaults::DENOM; use cosmwasm_std::testing::{mock_env, mock_info}; - use cosmwasm_std::{coin, coins, Addr, Uint128}; + use cosmwasm_std::{coin, coins, Addr, Timestamp, Uint128}; use mixnet_contract_common::events::{ must_find_attribute, BOND_TOO_FRESH_VALUE, NO_REWARD_REASON_KEY, OPERATOR_REWARDING_EVENT_TYPE, }; use mixnet_contract_common::reward_params::{NodeRewardParams, RewardParams}; - use mixnet_contract_common::{Delegation, IdentityKey, Layer, MixNode}; + use mixnet_contract_common::{Delegation, IdentityKey, Interval, Layer, MixNode}; + use time::OffsetDateTime; #[test] fn rewarding_mixnodes_with_incorrect_interval_id() { @@ -620,6 +626,7 @@ pub mod tests { #[test] fn rewarding_mixnode_blockstamp_based() { let mut deps = test_helpers::init_contract(); + let mut env = mock_env(); let current_state = mixnet_params_storage::CONTRACT_STATE .load(deps.as_mut().storage) @@ -641,7 +648,7 @@ pub mod tests { ..tests::fixtures::mix_node_fixture() }, proxy: None, - accumulated_rewards: Uint128::zero(), + accumulated_rewards: None, epoch_rewards: None, }; @@ -663,6 +670,7 @@ pub mod tests { // delegation happens later, but not later enough env.block.height += constants::MINIMUM_BLOCK_AGE_FOR_REWARDING - 1; + env.block.time = Timestamp::from_seconds(OffsetDateTime::now_utc().unix_timestamp() as u64); delegations_storage::delegations() .save( @@ -680,6 +688,15 @@ pub mod tests { let info = mock_info(rewarding_validator_address.as_ref(), &[]); + let epoch = Interval::init_epoch(env.clone()); + save_epoch(&mut deps.storage, &epoch).unwrap(); + save_epoch_reward_params(epoch.id(), &mut deps.storage).unwrap(); + + let epoch_from_storage = interval_storage::current_epoch(&deps.storage) + .unwrap() + .unwrap(); + assert_eq!(epoch_from_storage.id(), 0); + let res = try_reward_mixnode( deps.as_mut(), env.clone(), @@ -712,14 +729,11 @@ pub mod tests { // reward can happen now, but only for bonded node env.block.height += 1; - test_helpers::update_env_and_progress_interval(&mut env, deps.as_mut().storage); + env.block.time = Timestamp::from_seconds(epoch.next().start_unix_timestamp() as u64); + try_advance_epoch(env.clone(), &mut deps.storage).unwrap(); let info = mock_info(rewarding_validator_address.as_ref(), &[]); - let epoch = epoch_fixture(); - save_epoch(&mut deps.storage, &epoch).unwrap(); - save_epoch_reward_params(epoch.id(), &mut deps.storage).unwrap(); - let res = try_reward_mixnode( deps.as_mut(), env.clone(), @@ -734,7 +748,7 @@ pub mod tests { .load(&deps.storage, &node_identity) .unwrap(); - assert!(mixnode.accumulated_rewards > Uint128::zero(),); + assert!(mixnode.accumulated_rewards > Some(Uint128::zero()),); assert_eq!( initial_delegation, mixnodes_storage::TOTAL_DELEGATION @@ -863,7 +877,7 @@ pub mod tests { .unwrap(); let mix_1_uptime = 100; - let epoch = epoch_fixture(); + let epoch = Interval::init_epoch(env.clone()); save_epoch(&mut deps.storage, &epoch).unwrap(); save_epoch_reward_params(epoch.id(), &mut deps.storage).unwrap(); @@ -934,7 +948,7 @@ pub mod tests { test_helpers::read_mixnode_pledge_amount(&deps.storage, &node_identity) .unwrap() .u128() - + mixnode.accumulated_rewards.u128(), + + mixnode.accumulated_rewards().u128(), pre_reward_bond + mix1_operator_reward + mix1_delegator1_reward @@ -996,7 +1010,7 @@ pub mod tests { env.block.height += constants::MINIMUM_BLOCK_AGE_FOR_REWARDING; - let epoch = epoch_fixture(); + let epoch = Interval::init_epoch(env.clone()); save_epoch(&mut deps.storage, &epoch).unwrap(); save_epoch_reward_params(epoch.id(), &mut deps.storage).unwrap(); diff --git a/contracts/mixnet/src/support/tests/fixtures.rs b/contracts/mixnet/src/support/tests/fixtures.rs index ba7fdd45b6..b174aba9c9 100644 --- a/contracts/mixnet/src/support/tests/fixtures.rs +++ b/contracts/mixnet/src/support/tests/fixtures.rs @@ -3,6 +3,7 @@ use std::time::Duration; use crate::contract::INITIAL_MIXNODE_PLEDGE; use crate::mixnodes::storage as mixnodes_storage; use crate::{mixnodes::storage::StoredMixnodeBond, support::tests}; +use az::UnwrappedAs; use config::defaults::DENOM; use cosmwasm_std::{coin, Addr, Coin, Uint128}; use mixnet_contract_common::reward_params::NodeRewardParams; @@ -59,7 +60,7 @@ pub(crate) fn stored_mixnode_bond_fixture(owner: &str) -> mixnodes_storage::Stor ..super::fixtures::mix_node_fixture() }, None, - Uint128::zero(), + None, None, ) } @@ -81,7 +82,3 @@ pub fn good_gateway_pledge() -> Vec { pub fn node_reward_params_fixture(uptime: u128) -> NodeRewardParams { NodeRewardParams::new(0, uptime, true) } - -pub fn epoch_fixture() -> Interval { - Interval::new(1, OffsetDateTime::now_utc(), Duration::from_secs(3600)) -} diff --git a/contracts/mixnet/src/support/tests/mod.rs b/contracts/mixnet/src/support/tests/mod.rs index 2dcc348363..86fabc2192 100644 --- a/contracts/mixnet/src/support/tests/mod.rs +++ b/contracts/mixnet/src/support/tests/mod.rs @@ -131,13 +131,14 @@ pub mod test_helpers { pub(crate) fn update_env_and_progress_interval(env: &mut Env, storage: &mut dyn Storage) { // make sure current block time is within the expected next interval env.block.time = Timestamp::from_seconds( - (interval_storage::current_interval(storage) + (interval_storage::current_epoch(storage) + .unwrap() .unwrap() .next() .start_unix_timestamp() + 123) as u64, ); - interval::transactions::try_advance_interval(env.clone(), storage).unwrap(); + interval::transactions::try_advance_epoch(env.clone(), storage).unwrap(); } } diff --git a/nym-wallet/src/types/rust/account.ts b/nym-wallet/src/types/rust/account.ts index 9d10a5505b..c621c7b339 100644 --- a/nym-wallet/src/types/rust/account.ts +++ b/nym-wallet/src/types/rust/account.ts @@ -1,7 +1,3 @@ -import type { Denom } from './denom'; +import type { Denom } from "./denom"; -export interface Account { - contract_address: string; - client_address: string; - denom: Denom; -} +export interface Account { contract_address: string, client_address: string, denom: Denom, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/balance.ts b/nym-wallet/src/types/rust/balance.ts index 8e00f8b92e..ea260995cf 100644 --- a/nym-wallet/src/types/rust/balance.ts +++ b/nym-wallet/src/types/rust/balance.ts @@ -1,6 +1,3 @@ -import type { Coin } from './coin'; +import type { Coin } from "./coin"; -export interface Balance { - coin: Coin; - printable_balance: string; -} +export interface Balance { coin: Coin, printable_balance: string, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/coin.ts b/nym-wallet/src/types/rust/coin.ts index 7036ab5889..fd5b6ef4e8 100644 --- a/nym-wallet/src/types/rust/coin.ts +++ b/nym-wallet/src/types/rust/coin.ts @@ -1,6 +1,3 @@ -import type { Denom } from './denom'; +import type { Denom } from "./denom"; -export interface Coin { - amount: string; - denom: Denom; -} +export interface Coin { amount: string, denom: Denom, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/corenodestatusresponse.ts b/nym-wallet/src/types/rust/corenodestatusresponse.ts index 44ac51adbe..4314f52db9 100644 --- a/nym-wallet/src/types/rust/corenodestatusresponse.ts +++ b/nym-wallet/src/types/rust/corenodestatusresponse.ts @@ -1,4 +1,2 @@ -export interface CoreNodeStatusResponse { - identity: string; - count: number; -} + +export interface CoreNodeStatusResponse { identity: string, count: number, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/createdaccount.ts b/nym-wallet/src/types/rust/createdaccount.ts index e75585c4a2..c2cb9ec483 100644 --- a/nym-wallet/src/types/rust/createdaccount.ts +++ b/nym-wallet/src/types/rust/createdaccount.ts @@ -1,6 +1,3 @@ -import type { Account } from './account'; +import type { Account } from "./account"; -export interface CreatedAccount { - account: Account; - mnemonic: string; -} +export interface CreatedAccount { account: Account, mnemonic: string, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/delegationresult.ts b/nym-wallet/src/types/rust/delegationresult.ts index 5f09b66e82..778fdd2dca 100644 --- a/nym-wallet/src/types/rust/delegationresult.ts +++ b/nym-wallet/src/types/rust/delegationresult.ts @@ -1,7 +1,3 @@ -import type { Coin } from './coin'; +import type { Coin } from "./coin"; -export interface DelegationResult { - source_address: string; - target_address: string; - amount: Coin | null; -} +export interface DelegationResult { source_address: string, target_address: string, amount: Coin | null, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/denom.ts b/nym-wallet/src/types/rust/denom.ts index 5c7fca48c1..8120eafdd0 100644 --- a/nym-wallet/src/types/rust/denom.ts +++ b/nym-wallet/src/types/rust/denom.ts @@ -1 +1,2 @@ -export type Denom = 'Major' | 'Minor'; + +export type Denom = "Major" | "Minor"; \ No newline at end of file diff --git a/nym-wallet/src/types/rust/gateway.ts b/nym-wallet/src/types/rust/gateway.ts index 1dbba0e5ed..24b3b7eb58 100644 --- a/nym-wallet/src/types/rust/gateway.ts +++ b/nym-wallet/src/types/rust/gateway.ts @@ -1,9 +1,2 @@ -export interface Gateway { - host: string; - mix_port: number; - clients_port: number; - location: string; - sphinx_key: string; - identity_key: string; - version: string; -} + +export interface Gateway { host: string, mix_port: number, clients_port: number, location: string, sphinx_key: string, identity_key: string, version: string, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/inclusionprobabilityresponse.ts b/nym-wallet/src/types/rust/inclusionprobabilityresponse.ts index ec83a70b04..8d5a4dfb94 100644 --- a/nym-wallet/src/types/rust/inclusionprobabilityresponse.ts +++ b/nym-wallet/src/types/rust/inclusionprobabilityresponse.ts @@ -1,4 +1,2 @@ -export interface InclusionProbabilityResponse { - in_active: number; - in_reserve: number; -} + +export interface InclusionProbabilityResponse { in_active: number, in_reserve: number, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/mixnode.ts b/nym-wallet/src/types/rust/mixnode.ts index d1c3a9574b..6b6d783dda 100644 --- a/nym-wallet/src/types/rust/mixnode.ts +++ b/nym-wallet/src/types/rust/mixnode.ts @@ -1,10 +1,2 @@ -export interface MixNode { - host: string; - mix_port: number; - verloc_port: number; - http_api_port: number; - sphinx_key: string; - identity_key: string; - version: string; - profit_margin_percent: number; -} + +export interface MixNode { host: string, mix_port: number, verloc_port: number, http_api_port: number, sphinx_key: string, identity_key: string, version: string, profit_margin_percent: number, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/mixnodestatus.ts b/nym-wallet/src/types/rust/mixnodestatus.ts index da89c7e8a7..a7b76b836f 100644 --- a/nym-wallet/src/types/rust/mixnodestatus.ts +++ b/nym-wallet/src/types/rust/mixnodestatus.ts @@ -1 +1,2 @@ -export type MixnodeStatus = 'active' | 'standby' | 'inactive' | 'not_found'; + +export type MixnodeStatus = "active" | "standby" | "inactive" | "not_found"; \ No newline at end of file diff --git a/nym-wallet/src/types/rust/mixnodestatusresponse.ts b/nym-wallet/src/types/rust/mixnodestatusresponse.ts index 9c2dd4f9a1..837b322eba 100644 --- a/nym-wallet/src/types/rust/mixnodestatusresponse.ts +++ b/nym-wallet/src/types/rust/mixnodestatusresponse.ts @@ -1,5 +1,3 @@ -import type { MixnodeStatus } from './mixnodestatus'; +import type { MixnodeStatus } from "./mixnodestatus"; -export interface MixnodeStatusResponse { - status: MixnodeStatus; -} +export interface MixnodeStatusResponse { status: MixnodeStatus, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/network.ts b/nym-wallet/src/types/rust/network.ts index f8615cd992..fd31bccafa 100644 --- a/nym-wallet/src/types/rust/network.ts +++ b/nym-wallet/src/types/rust/network.ts @@ -1 +1,2 @@ -export type Network = 'QA' | 'SANDBOX' | 'MAINNET'; + +export type Network = "QA" | "SANDBOX" | "MAINNET"; \ No newline at end of file diff --git a/nym-wallet/src/types/rust/operation.ts b/nym-wallet/src/types/rust/operation.ts index 405b5dbb0b..4e74dcf06d 100644 --- a/nym-wallet/src/types/rust/operation.ts +++ b/nym-wallet/src/types/rust/operation.ts @@ -1,34 +1,2 @@ -export type Operation = - | 'Upload' - | 'Init' - | 'Migrate' - | 'ChangeAdmin' - | 'Send' - | 'BondMixnode' - | 'BondMixnodeOnBehalf' - | 'UnbondMixnode' - | 'UnbondMixnodeOnBehalf' - | 'UpdateMixnodeConfig' - | 'DelegateToMixnode' - | 'DelegateToMixnodeOnBehalf' - | 'UndelegateFromMixnode' - | 'UndelegateFromMixnodeOnBehalf' - | 'BondGateway' - | 'BondGatewayOnBehalf' - | 'UnbondGateway' - | 'UnbondGatewayOnBehalf' - | 'UpdateContractSettings' - | 'BeginMixnodeRewarding' - | 'FinishMixnodeRewarding' - | 'TrackUnbondGateway' - | 'TrackUnbondMixnode' - | 'WithdrawVestedCoins' - | 'TrackUndelegation' - | 'CreatePeriodicVestingAccount' - | 'AdvanceCurrentInterval' - | 'AdvanceCurrentEpoch' - | 'WriteRewardedSet' - | 'ClearRewardedSet' - | 'UpdateMixnetAddress' - | 'CheckpointMixnodes' - | 'ReconcileDelegations'; + +export type Operation = "Upload" | "Init" | "Migrate" | "ChangeAdmin" | "Send" | "BondMixnode" | "BondMixnodeOnBehalf" | "UnbondMixnode" | "UnbondMixnodeOnBehalf" | "UpdateMixnodeConfig" | "DelegateToMixnode" | "DelegateToMixnodeOnBehalf" | "UndelegateFromMixnode" | "UndelegateFromMixnodeOnBehalf" | "BondGateway" | "BondGatewayOnBehalf" | "UnbondGateway" | "UnbondGatewayOnBehalf" | "UpdateContractSettings" | "BeginMixnodeRewarding" | "FinishMixnodeRewarding" | "TrackUnbondGateway" | "TrackUnbondMixnode" | "WithdrawVestedCoins" | "TrackUndelegation" | "CreatePeriodicVestingAccount" | "AdvanceCurrentInterval" | "AdvanceCurrentEpoch" | "WriteRewardedSet" | "ClearRewardedSet" | "UpdateMixnetAddress" | "CheckpointMixnodes" | "ReconcileDelegations"; \ No newline at end of file diff --git a/nym-wallet/src/types/rust/originalvestingresponse.ts b/nym-wallet/src/types/rust/originalvestingresponse.ts index cb57d5b456..d8c581443c 100644 --- a/nym-wallet/src/types/rust/originalvestingresponse.ts +++ b/nym-wallet/src/types/rust/originalvestingresponse.ts @@ -1,7 +1,3 @@ -import type { Coin } from './coin'; +import type { Coin } from "./coin"; -export interface OriginalVestingResponse { - amount: Coin; - number_of_periods: number; - period_duration: bigint; -} +export interface OriginalVestingResponse { amount: Coin, number_of_periods: number, period_duration: bigint, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/period.ts b/nym-wallet/src/types/rust/period.ts index 05d9890d5f..809b6c2d87 100644 --- a/nym-wallet/src/types/rust/period.ts +++ b/nym-wallet/src/types/rust/period.ts @@ -1 +1,2 @@ -export type Period = 'Before' | { In: number } | 'After'; + +export type Period = "Before" | { In: number } | "After"; \ No newline at end of file diff --git a/nym-wallet/src/types/rust/pledgedata.ts b/nym-wallet/src/types/rust/pledgedata.ts index 996a999329..c1312bdc91 100644 --- a/nym-wallet/src/types/rust/pledgedata.ts +++ b/nym-wallet/src/types/rust/pledgedata.ts @@ -1,6 +1,3 @@ -import type { Coin } from './coin'; +import type { Coin } from "./coin"; -export interface PledgeData { - amount: Coin; - block_time: bigint; -} +export interface PledgeData { amount: Coin, block_time: bigint, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/rewardedsetnodestatus.ts b/nym-wallet/src/types/rust/rewardedsetnodestatus.ts index 8ddd13d047..3f0bb8e3e6 100644 --- a/nym-wallet/src/types/rust/rewardedsetnodestatus.ts +++ b/nym-wallet/src/types/rust/rewardedsetnodestatus.ts @@ -1 +1,2 @@ -export type RewardedSetNodeStatus = 'Active' | 'Standby'; + +export type RewardedSetNodeStatus = "Active" | "Standby"; \ No newline at end of file diff --git a/nym-wallet/src/types/rust/rewardestimationresponse.ts b/nym-wallet/src/types/rust/rewardestimationresponse.ts index 6ca4481acc..a1bf4657b4 100644 --- a/nym-wallet/src/types/rust/rewardestimationresponse.ts +++ b/nym-wallet/src/types/rust/rewardestimationresponse.ts @@ -1,9 +1,2 @@ -export interface RewardEstimationResponse { - estimated_total_node_reward: bigint; - estimated_operator_reward: bigint; - estimated_delegators_reward: bigint; - current_interval_start: bigint; - current_interval_end: bigint; - current_interval_uptime: number; - as_at: bigint; -} + +export interface RewardEstimationResponse { estimated_total_node_reward: bigint, estimated_operator_reward: bigint, estimated_delegators_reward: bigint, current_interval_start: bigint, current_interval_end: bigint, current_interval_uptime: number, as_at: bigint, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/stakesaturationresponse.ts b/nym-wallet/src/types/rust/stakesaturationresponse.ts index 8f399885a4..7f651f89cc 100644 --- a/nym-wallet/src/types/rust/stakesaturationresponse.ts +++ b/nym-wallet/src/types/rust/stakesaturationresponse.ts @@ -1,4 +1,2 @@ -export interface StakeSaturationResponse { - saturation: number; - as_at: bigint; -} + +export interface StakeSaturationResponse { saturation: number, as_at: bigint, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/stateparams.ts b/nym-wallet/src/types/rust/stateparams.ts index 68c3e018e9..22f6653c0e 100644 --- a/nym-wallet/src/types/rust/stateparams.ts +++ b/nym-wallet/src/types/rust/stateparams.ts @@ -1,6 +1,2 @@ -export interface TauriContractStateParams { - minimum_mixnode_pledge: string; - minimum_gateway_pledge: string; - mixnode_rewarded_set_size: number; - mixnode_active_set_size: number; -} + +export interface TauriContractStateParams { minimum_mixnode_pledge: string, minimum_gateway_pledge: string, mixnode_rewarded_set_size: number, mixnode_active_set_size: number, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/tauritxresult.ts b/nym-wallet/src/types/rust/tauritxresult.ts index 6a9ae8ad60..013cc66412 100644 --- a/nym-wallet/src/types/rust/tauritxresult.ts +++ b/nym-wallet/src/types/rust/tauritxresult.ts @@ -1,10 +1,3 @@ -import type { TransactionDetails } from './transactiondetails'; +import type { TransactionDetails } from "./transactiondetails"; -export interface TauriTxResult { - block_height: bigint; - code: number; - details: TransactionDetails; - gas_used: bigint; - gas_wanted: bigint; - tx_hash: string; -} +export interface TauriTxResult { block_height: bigint, code: number, details: TransactionDetails, gas_used: bigint, gas_wanted: bigint, tx_hash: string, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/transactiondetails.ts b/nym-wallet/src/types/rust/transactiondetails.ts index d375b437f1..b24d2f8944 100644 --- a/nym-wallet/src/types/rust/transactiondetails.ts +++ b/nym-wallet/src/types/rust/transactiondetails.ts @@ -1,7 +1,3 @@ -import type { Coin } from './coin'; +import type { Coin } from "./coin"; -export interface TransactionDetails { - amount: Coin; - from_address: string; - to_address: string; -} +export interface TransactionDetails { amount: Coin, from_address: string, to_address: string, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/vestingaccountinfo.ts b/nym-wallet/src/types/rust/vestingaccountinfo.ts index 17d44a5983..addfc1ef87 100644 --- a/nym-wallet/src/types/rust/vestingaccountinfo.ts +++ b/nym-wallet/src/types/rust/vestingaccountinfo.ts @@ -1,10 +1,4 @@ -import type { Coin } from './coin'; -import type { VestingPeriod } from './vestingperiod'; +import type { Coin } from "./coin"; +import type { VestingPeriod } from "./vestingperiod"; -export interface VestingAccountInfo { - owner_address: string; - staking_address: string | null; - start_time: bigint; - periods: Array; - coin: Coin; -} +export interface VestingAccountInfo { owner_address: string, staking_address: string | null, start_time: bigint, periods: Array, coin: Coin, } \ No newline at end of file diff --git a/nym-wallet/src/types/rust/vestingperiod.ts b/nym-wallet/src/types/rust/vestingperiod.ts index de1089005f..fb3cf1c7b2 100644 --- a/nym-wallet/src/types/rust/vestingperiod.ts +++ b/nym-wallet/src/types/rust/vestingperiod.ts @@ -1,4 +1,2 @@ -export interface VestingPeriod { - start_time: bigint; - period_seconds: bigint; -} + +export interface VestingPeriod { start_time: bigint, period_seconds: bigint, } \ No newline at end of file diff --git a/validator-api/src/contract_cache/mod.rs b/validator-api/src/contract_cache/mod.rs index e0369abb50..4d45de77ef 100644 --- a/validator-api/src/contract_cache/mod.rs +++ b/validator-api/src/contract_cache/mod.rs @@ -23,8 +23,6 @@ use validator_client::nymd::CosmWasmClient; pub(crate) mod routes; -type Epoch = Interval; - pub struct ValidatorCacheRefresher { nymd_client: Client, cache: ValidatorCache, @@ -46,7 +44,7 @@ struct ValidatorCacheInner { active_set: Cache>, current_reward_params: Cache, - current_epoch: Cache, + current_epoch: Cache>, } fn current_unix_timestamp() -> i64 { @@ -134,7 +132,6 @@ impl ValidatorCacheRefresher { self.collect_rewarded_and_active_set_details(&mixnodes, rewarded_set_identities); let epoch_rewarding_params = self.nymd_client.get_current_epoch_reward_params().await?; - let current_interval = self.nymd_client.get_current_interval().await?; info!( "Updating validator cache. There are {} mixnodes and {} gateways", @@ -149,7 +146,6 @@ impl ValidatorCacheRefresher { rewarded_set, active_set, epoch_rewarding_params, - current_interval, ) .await; @@ -219,7 +215,6 @@ impl ValidatorCache { rewarded_set: Vec, active_set: Vec, epoch_rewarding_params: EpochRewardParams, - current_epoch: Epoch, ) { let mut inner = self.inner.write().await; @@ -228,7 +223,6 @@ impl ValidatorCache { inner.rewarded_set.update(rewarded_set); inner.active_set.update(active_set); inner.current_reward_params.update(epoch_rewarding_params); - inner.current_epoch.update(current_epoch); } pub async fn mixnodes(&self) -> Cache> { @@ -251,7 +245,7 @@ impl ValidatorCache { self.inner.read().await.current_reward_params.clone() } - pub(crate) async fn current_interval(&self) -> Cache { + pub(crate) async fn current_epoch(&self) -> Cache> { self.inner.read().await.current_epoch.clone() } @@ -320,11 +314,7 @@ impl ValidatorCacheInner { current_reward_params: Cache::new(EpochRewardParams::new_empty()), // setting it to a dummy value on creation is fine, as nothing will be able to ready from it // since 'initialised' flag won't be set - current_epoch: Cache::new(Interval::new( - u32::MAX, - OffsetDateTime::UNIX_EPOCH, - Duration::default(), - )), + current_epoch: Cache::new(None), } } } diff --git a/validator-api/src/main.rs b/validator-api/src/main.rs index dc01ec0422..037fc3911e 100644 --- a/validator-api/src/main.rs +++ b/validator-api/src/main.rs @@ -464,7 +464,8 @@ async fn run_validator_api(matches: ArgMatches<'static>) -> Result<()> { rewarded_set_update_notify, validator_cache.clone(), storage, - ); + ) + .await?; // spawn rewarded set updater tokio::spawn(async move { rewarded_set_updater.run().await.unwrap() }); diff --git a/validator-api/src/node_status_api/models.rs b/validator-api/src/node_status_api/models.rs index 4ad57950dd..bf2cbb9202 100644 --- a/validator-api/src/node_status_api/models.rs +++ b/validator-api/src/node_status_api/models.rs @@ -239,7 +239,7 @@ pub enum ValidatorApiStorageError { GatewayUptimeHistoryNotFound(String), // I don't think we want to expose errors to the user about what really happened - InternalDatabaseError, + InternalDatabaseError(String), } impl Display for ValidatorApiStorageError { @@ -265,8 +265,8 @@ impl Display for ValidatorApiStorageError { "Could not find uptime history associated with gateway {}", identity ), - ValidatorApiStorageError::InternalDatabaseError => { - write!(f, "The internal database has experienced an issue") + ValidatorApiStorageError::InternalDatabaseError(err) => { + write!(f, "The internal database has experienced an issue: {err}") } } } diff --git a/validator-api/src/node_status_api/routes.rs b/validator-api/src/node_status_api/routes.rs index 96e997f643..7f1616db20 100644 --- a/validator-api/src/node_status_api/routes.rs +++ b/validator-api/src/node_status_api/routes.rs @@ -16,6 +16,8 @@ use validator_api_requests::models::{ RewardEstimationResponse, StakeSaturationResponse, }; +use super::models::Uptime; + #[get("/mixnode//report")] pub(crate) async fn mixnode_report( storage: &State, @@ -120,17 +122,33 @@ pub(crate) async fn get_mixnode_reward_estimation( let as_at = interval_reward_params.timestamp(); let interval_reward_params = interval_reward_params.into_inner(); - let current_interval = cache.current_interval().await.into_inner(); - let uptime = storage - .get_average_mixnode_uptime_in_interval( - &identity, - current_interval.start_unix_timestamp(), - current_interval.end_unix_timestamp(), - ) - .await - .map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound))?; + let current_epoch = cache.current_epoch().await.into_inner(); + let uptime = if let Some(epoch) = current_epoch { + storage + .get_average_mixnode_uptime_in_interval( + &identity, + epoch.start_unix_timestamp(), + epoch.end_unix_timestamp(), + ) + .await + .map_err(|err| ErrorResponse::new(err.to_string(), Status::NotFound))? + } else { + Uptime::default() + }; + let node_reward_params = NodeRewardParams::new(0, uptime.u8() as u128, status.is_active()); let reward_params = RewardParams::new(interval_reward_params, node_reward_params); + let epoch_start = if let Some(epoch) = current_epoch { + epoch.start_unix_timestamp() + } else { + 0 + }; + + let epoch_end = if let Some(epoch) = current_epoch { + epoch.end_unix_timestamp() + } else { + 0 + }; match bond.estimate_reward(&reward_params) { Ok(( estimated_total_node_reward, @@ -141,8 +159,8 @@ pub(crate) async fn get_mixnode_reward_estimation( estimated_total_node_reward, estimated_operator_reward, estimated_delegators_reward, - current_interval_start: current_interval.start_unix_timestamp(), - current_interval_end: current_interval.end_unix_timestamp(), + current_interval_start: epoch_start, + current_interval_end: epoch_end, current_interval_uptime: uptime.u8(), as_at, }; diff --git a/validator-api/src/nymd_client.rs b/validator-api/src/nymd_client.rs index c6e36ca5b6..2b8a591e89 100644 --- a/validator-api/src/nymd_client.rs +++ b/validator-api/src/nymd_client.rs @@ -4,9 +4,10 @@ use crate::config::Config; use crate::rewarded_set_updater::{error::RewardingError, MixnodeToReward}; use config::defaults::{DEFAULT_NETWORK, DEFAULT_VALIDATOR_API_PORT}; +use mixnet_contract_common::Interval; use mixnet_contract_common::{ reward_params::EpochRewardParams, ContractStateParams, Delegation, ExecuteMsg, GatewayBond, - IdentityKey, Interval, MixNodeBond, MixnodeRewardingStatusResponse, RewardedSetNodeStatus, + IdentityKey, MixNodeBond, MixnodeRewardingStatusResponse, RewardedSetNodeStatus, RewardedSetUpdateDetails, }; use serde::Serialize; @@ -113,13 +114,6 @@ impl Client { Ok(time) } - pub(crate) async fn get_current_interval(&self) -> Result - where - C: CosmWasmClient + Sync, - { - self.0.read().await.get_current_interval().await - } - pub(crate) async fn get_mixnodes(&self) -> Result, ValidatorClientError> where C: CosmWasmClient + Sync, @@ -146,6 +140,13 @@ impl Client { self.0.read().await.get_contract_settings().await } + pub(crate) async fn get_current_epoch(&self) -> Result, ValidatorClientError> + where + C: CosmWasmClient + Sync, + { + Ok(self.0.read().await.get_current_epoch().await?) + } + pub(crate) async fn get_current_epoch_reward_params( &self, ) -> Result @@ -250,15 +251,6 @@ impl Client { .await } - #[allow(dead_code)] - pub(crate) async fn advance_current_interval(&self) -> Result<(), ValidatorClientError> - where - C: SigningCosmWasmClient + Sync, - { - self.0.write().await.nymd.advance_current_interval().await?; - Ok(()) - } - pub(crate) async fn advance_current_epoch(&self) -> Result<(), ValidatorClientError> where C: SigningCosmWasmClient + Sync, diff --git a/validator-api/src/rewarded_set_updater/error.rs b/validator-api/src/rewarded_set_updater/error.rs index 38640d6657..e9b75730ba 100644 --- a/validator-api/src/rewarded_set_updater/error.rs +++ b/validator-api/src/rewarded_set_updater/error.rs @@ -28,6 +28,9 @@ pub enum RewardingError { #[from] source: std::num::TryFromIntError, }, + + #[error("Epoch not initialized yet!")] + EpochNotInitialized, } impl From for RewardingError { diff --git a/validator-api/src/rewarded_set_updater/mod.rs b/validator-api/src/rewarded_set_updater/mod.rs index 5ee92e57f4..2069046ba7 100644 --- a/validator-api/src/rewarded_set_updater/mod.rs +++ b/validator-api/src/rewarded_set_updater/mod.rs @@ -26,7 +26,6 @@ use rand::rngs::OsRng; use std::collections::HashSet; use std::sync::Arc; use std::time::Duration; -use time::OffsetDateTime; use tokio::sync::Notify; use tokio::time::sleep; use validator_client::nymd::SigningNymdClient; @@ -73,24 +72,28 @@ pub struct RewardedSetUpdater { update_rewarded_set_notify: Arc, validator_cache: ValidatorCache, storage: ValidatorApiStorage, - epoch: Epoch, + epoch: Option, } impl RewardedSetUpdater { - pub(crate) fn new( + pub(crate) fn epoch(&self) -> Result { + self.epoch.ok_or(RewardingError::EpochNotInitialized) + } + + pub(crate) async fn new( nymd_client: Client, update_rewarded_set_notify: Arc, validator_cache: ValidatorCache, storage: ValidatorApiStorage, - ) -> Self { - let epoch = Epoch::new(0, OffsetDateTime::now_utc(), Duration::from_secs(3600)); - RewardedSetUpdater { + ) -> Result { + let epoch = nymd_client.get_current_epoch().await?; + Ok(RewardedSetUpdater { nymd_client, update_rewarded_set_notify, validator_cache, storage, epoch, - } + }) } fn determine_rewarded_set( @@ -131,14 +134,14 @@ impl RewardedSetUpdater { async fn rewarding_happened_at_epoch(&self) -> Result { if let Some(entry) = self .storage - .get_interval_rewarding_entry(self.epoch.start_unix_timestamp()) + .get_epoch_rewarding_entry(self.epoch()?.id().into()) .await? { // log error if the attempt wasn't finished. This error implies the process has crashed // during the rewards distribution if !entry.finished { error!( - "It seems that we haven't successfully finished distributing rewards at {}", + "It seems that we haven't successfully finished distributing rewards at {:?}", self.epoch ) } @@ -153,13 +156,13 @@ impl RewardedSetUpdater { let to_reward = self.nodes_to_reward().await?; self.storage - .insert_started_epoch_rewarding(self.epoch) + .insert_started_epoch_rewarding(self.epoch()?) .await?; - let failure_data = self.distribute_rewards(&to_reward, false).await; + let failure_data = self.distribute_rewards(&to_reward, false).await?; let mut rewarding_report = RewardingReport { - interval_rewarding_id: self.epoch.id() as i64, + interval_rewarding_id: self.epoch()?.id() as i64, eligible_mixnodes: to_reward.len() as i64, possibly_unrewarded_mixnodes: 0, }; @@ -168,7 +171,7 @@ impl RewardedSetUpdater { rewarding_report.possibly_unrewarded_mixnodes = failure_data.possibly_unrewarded.len() as i64; if let Err(err) = self - .save_failure_information(failure_data, self.epoch.id() as i64) + .save_failure_information(failure_data, self.epoch()?.id() as i64) .await { error!("failed to save information about rewarding failures!"); @@ -215,7 +218,7 @@ impl RewardedSetUpdater { &self, eligible_mixnodes: &[MixnodeToReward], retry: bool, - ) -> Option { + ) -> Result, RewardingError> { if retry { info!( "Attempting to retry rewarding {} mixnodes...", @@ -237,7 +240,7 @@ impl RewardedSetUpdater { loop { match self .nymd_client - .reward_mixnodes(eligible_mixnodes, self.epoch.id()) + .reward_mixnodes(eligible_mixnodes, self.epoch()?.id()) .await { Ok(_) => { @@ -269,7 +272,7 @@ impl RewardedSetUpdater { if success { failed_chunks = None } - failed_chunks + Ok(failed_chunks) } async fn nodes_to_reward(&self) -> Result, RewardingError> { @@ -290,8 +293,8 @@ impl RewardedSetUpdater { .storage .get_average_mixnode_uptime_in_interval( rewarded_node.identity(), - self.epoch.start_unix_timestamp(), - self.epoch.end_unix_timestamp(), + self.epoch()?.start_unix_timestamp(), + self.epoch()?.end_unix_timestamp(), ) .await?; @@ -322,14 +325,15 @@ impl RewardedSetUpdater { // Reward all the nodes in the still current, soon to be previous rewarded set if !self.rewarding_happened_at_epoch().await? { - self.reward_current_rewarded_set().await?; + if let Err(err) = self.reward_current_rewarded_set().await { + log::error!("failed to reward rewarded set - {}", err); + } } // Reconcile delegations from the previous epoch if let Err(err) = self.nymd_client.reconcile_delegations().await { log::error!("failed to reconcile delegations - {}", err); } - // Snapshot mixnodes for the next epoch if let Err(err) = self.nymd_client.checkpoint_mixnodes().await { log::error!("failed to checkpoint mixnodes - {}", err); @@ -355,7 +359,7 @@ impl RewardedSetUpdater { // the cache will notify the updater on its next round } - let cutoff = (self.epoch.end() - Duration::from_secs(86400)).unix_timestamp(); + let cutoff = (self.epoch()?.end() - Duration::from_secs(86400)).unix_timestamp(); self.storage.purge_old_statuses(cutoff).await?; Ok(()) @@ -367,7 +371,7 @@ impl RewardedSetUpdater { loop { // wait until the cache refresher determined its time to update the rewarded/active sets self.update_rewarded_set_notify.notified().await; - self.epoch = self.epoch.next(); + self.epoch = Some(self.epoch()?.next()); self.update_rewarded_set().await?; } #[allow(unreachable_code)] diff --git a/validator-api/src/storage/manager.rs b/validator-api/src/storage/manager.rs index d30dcafcb5..b4a33d26c5 100644 --- a/validator-api/src/storage/manager.rs +++ b/validator-api/src/storage/manager.rs @@ -742,17 +742,17 @@ impl StorageManager { /// # Arguments /// /// * `interval_start_timestamp`: Unix timestamp of the start of this rewarding interval. - pub(super) async fn get_interval_rewarding_entry( + pub(super) async fn get_epoch_rewarding_entry( &self, - interval_start_timestamp: i64, + epoch_id: i64, ) -> Result, sqlx::Error> { sqlx::query_as!( IntervalRewarding, r#" SELECT * FROM interval_rewarding - WHERE interval_start_timestamp = ? + WHERE id = ? "#, - interval_start_timestamp + epoch_id ) .fetch_optional(&self.connection_pool) .await diff --git a/validator-api/src/storage/mod.rs b/validator-api/src/storage/mod.rs index db7be2cbbb..a25e6dd414 100644 --- a/validator-api/src/storage/mod.rs +++ b/validator-api/src/storage/mod.rs @@ -85,7 +85,7 @@ impl ValidatorApiStorage { .manager .get_mixnode_statuses_since(identity, since) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))?; Ok(statuses) } @@ -106,7 +106,7 @@ impl ValidatorApiStorage { .manager .get_gateway_statuses_since(identity, since) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))?; Ok(statuses) } @@ -145,7 +145,7 @@ impl ValidatorApiStorage { .manager .get_mixnode_owner(identity) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))? .expect("The node doesn't have an owner even though we have status information on it!"); Ok(MixnodeStatusReport::construct_from_last_day_reports( @@ -187,7 +187,7 @@ impl ValidatorApiStorage { .manager .get_gateway_owner(identity) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))? .expect( "The gateway doesn't have an owner even though we have status information on it!", ); @@ -210,7 +210,7 @@ impl ValidatorApiStorage { .manager .get_mixnode_historical_uptimes(identity) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))?; if history.is_empty() { return Err(ValidatorApiStorageError::MixnodeUptimeHistoryNotFound( @@ -222,7 +222,7 @@ impl ValidatorApiStorage { .manager .get_mixnode_owner(identity) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))? .expect("The node doesn't have an owner even though we have uptime history for it!"); Ok(MixnodeUptimeHistory::new( @@ -240,7 +240,7 @@ impl ValidatorApiStorage { .manager .get_gateway_historical_uptimes(identity) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))?; if history.is_empty() { return Err(ValidatorApiStorageError::GatewayUptimeHistoryNotFound( @@ -252,7 +252,7 @@ impl ValidatorApiStorage { .manager .get_gateway_owner(identity) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))? .expect("The gateway doesn't have an owner even though we have uptime history for it!"); Ok(GatewayUptimeHistory::new( @@ -280,7 +280,7 @@ impl ValidatorApiStorage { .manager .get_mixnode_id(identity) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))? { Some(id) => id, None => return Ok(Uptime::zero()), @@ -291,7 +291,7 @@ impl ValidatorApiStorage { .manager .get_mixnode_statuses_by_id(mixnode_database_id, start, end) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))?; let mut total: f32 = 0.0; for mixnode_status in mixnode_statuses { @@ -337,7 +337,7 @@ impl ValidatorApiStorage { .manager .get_all_active_mixnodes_statuses_in_interval(start, end) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))? .into_iter() .map(|statuses| { MixnodeStatusReport::construct_from_last_day_reports( @@ -381,7 +381,7 @@ impl ValidatorApiStorage { .manager .get_all_active_gateways_statuses_in_interval(start, end) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))? .into_iter() .map(|statuses| { GatewayStatusReport::construct_from_last_day_reports( @@ -415,29 +415,29 @@ impl ValidatorApiStorage { .manager .get_mixnode_id(&test_route.layer_one_mix().identity_key.to_base58_string()) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? - .ok_or(ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError("".to_string()))? + .ok_or_else(|| ValidatorApiStorageError::InternalDatabaseError("".to_string()))?; let layer2_mix_id = self .manager .get_mixnode_id(&test_route.layer_two_mix().identity_key.to_base58_string()) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? - .ok_or(ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))? + .ok_or_else(|| ValidatorApiStorageError::InternalDatabaseError("".to_string()))?; let layer3_mix_id = self .manager .get_mixnode_id(&test_route.layer_three_mix().identity_key.to_base58_string()) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? - .ok_or(ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|_| ValidatorApiStorageError::InternalDatabaseError("".to_string()))? + .ok_or_else(|| ValidatorApiStorageError::InternalDatabaseError("".to_string()))?; let gateway_id = self .manager .get_gateway_id(&test_route.gateway().identity_key.to_base58_string()) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? - .ok_or(ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))? + .ok_or_else(|| ValidatorApiStorageError::InternalDatabaseError("".to_string()))?; self.manager .submit_testing_route_used(TestingRoute { @@ -448,7 +448,7 @@ impl ValidatorApiStorage { monitor_run_id, }) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))?; Ok(()) } @@ -469,7 +469,7 @@ impl ValidatorApiStorage { .manager .get_mixnode_id(identity) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))?; if let Some(node_id) = node_id { let since = since @@ -478,7 +478,7 @@ impl ValidatorApiStorage { self.manager .get_mixnode_testing_route_presence_count_since(node_id, since) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string())) } else { Ok(0) } @@ -501,7 +501,7 @@ impl ValidatorApiStorage { .manager .get_gateway_id(identity) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))?; if let Some(node_id) = node_id { let since = since @@ -510,7 +510,7 @@ impl ValidatorApiStorage { self.manager .get_gateway_testing_route_presence_count_since(node_id, since) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string())) } else { Ok(0) } @@ -538,17 +538,17 @@ impl ValidatorApiStorage { .manager .insert_monitor_run(now) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))?; self.manager .submit_mixnode_statuses(now, mixnode_results) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))?; self.manager .submit_gateway_statuses(now, gateway_results) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))?; for test_route in test_routes { self.insert_test_route(monitor_run_id, test_route).await?; @@ -572,11 +572,13 @@ impl ValidatorApiStorage { .manager .get_monitor_runs_count(since, until) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e)))?; if run_count < 0 { // I don't think it's ever possible for SQL to return a negative value from COUNT? - return Err(ValidatorApiStorageError::InternalDatabaseError); + return Err(ValidatorApiStorageError::InternalDatabaseError( + "Negative run count".to_string(), + )); } Ok(run_count as usize) } @@ -602,7 +604,7 @@ impl ValidatorApiStorage { .manager .get_mixnode_id(&report.identity) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))? { Some(node_id) => node_id, None => { @@ -617,7 +619,7 @@ impl ValidatorApiStorage { self.manager .insert_mixnode_historical_uptime(node_id, today_iso_8601, report.last_day.u8()) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))?; } for report in gateway_reports { @@ -627,7 +629,7 @@ impl ValidatorApiStorage { .manager .get_gateway_id(&report.identity) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)? + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))? { Some(node_id) => node_id, None => { @@ -642,7 +644,7 @@ impl ValidatorApiStorage { self.manager .insert_gateway_historical_uptime(node_id, today_iso_8601, report.last_day.u8()) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))?; } Ok(()) @@ -655,7 +657,7 @@ impl ValidatorApiStorage { self.manager .check_for_historical_uptime_existence(date_iso_8601) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string())) } /// Removes all ipv4 and ipv6 statuses for all mixnodes and gateways that are older than the @@ -671,11 +673,11 @@ impl ValidatorApiStorage { self.manager .purge_old_mixnode_statuses(until) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))?; self.manager .purge_old_gateway_statuses(until) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string())) } //////////////////////////////////////////////////////////////////////// @@ -696,7 +698,7 @@ impl ValidatorApiStorage { self.manager .insert_new_epoch_rewarding(epoch) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string())) } // /// Tries to obtain the most recent interval rewarding entry currently stored. @@ -718,14 +720,14 @@ impl ValidatorApiStorage { /// # Arguments /// /// * `interval_timestamp`: Unix timestamp of this rewarding interval. - pub(super) async fn get_interval_rewarding_entry( + pub(super) async fn get_epoch_rewarding_entry( &self, - interval_timestamp: i64, + epoch_id: i64, ) -> Result, ValidatorApiStorageError> { self.manager - .get_interval_rewarding_entry(interval_timestamp) + .get_epoch_rewarding_entry(epoch_id) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(format!("{}", e))) } /// Sets the `finished` field on the interval rewarding to true and inserts the rewarding report into @@ -741,12 +743,12 @@ impl ValidatorApiStorage { self.manager .update_finished_interval_rewarding(report.interval_rewarding_id) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError)?; + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string()))?; self.manager .insert_rewarding_report(report) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string())) } /// Inserts new failed mixnode reward chunk information into the database. @@ -762,7 +764,7 @@ impl ValidatorApiStorage { self.manager .insert_failed_mixnode_reward_chunk(failed_chunk) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string())) } /// Inserts information into the database about a mixnode that might have been unfairly unrewarded this interval. @@ -777,6 +779,6 @@ impl ValidatorApiStorage { self.manager .insert_possibly_unrewarded_mixnode(mixnode) .await - .map_err(|_| ValidatorApiStorageError::InternalDatabaseError) + .map_err(|e| ValidatorApiStorageError::InternalDatabaseError(e.to_string())) } }