Compare commits

...

33 Commits

Author SHA1 Message Date
Vijay
a5cfce805a
Merge c5e2fddc7a into dd96032e12 2024-12-17 17:48:36 +00:00
pasta
dd96032e12
Merge #6494: depends: update 'src/dashbls' to dashpay/bls-signatures@0bb5c5b0 as efd5c56
Some checks failed
Label Merge Conflicts / main (push) Failing after 24s
CI / Build Image (push) Failing after 52s
CI / Build (linux64_ubsan, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build Dependencies (arm-linux, arm-linux-gnueabihf) (push) Has been skipped
CI / Build Dependencies (linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (arm-linux, arm-linux, arm-linux-gnueabihf) (push) Has been skipped
CI / Build (linux64, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_cxx20, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_fuzz, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_nowallet, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_sqlite, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
CI / Build (linux64_tsan, linux64, x86_64-pc-linux-gnu) (push) Has been skipped
Check Merge Fast-Forward Only / check_merge (push) Successful in 1m35s
Guix Build / build-image (push) Failing after 3m21s
Guix Build / build (aarch64-linux-gnu) (push) Has been skipped
Guix Build / build (arm-linux-gnueabihf) (push) Has been skipped
Guix Build / build (arm64-apple-darwin) (push) Has been skipped
Guix Build / build (powerpc64-linux-gnu) (push) Has been skipped
Guix Build / build (riscv64-linux-gnu) (push) Has been skipped
Guix Build / build (x86_64-apple-darwin) (push) Has been skipped
Guix Build / build (x86_64-linux-gnu) (push) Has been skipped
Guix Build / build (x86_64-w64-mingw32) (push) Has been skipped
3bbe16c390 build: stop tracking cmake dependency relic_conf.h.in (Kittywhiskers Van Gogh)
efd5c566da Squashed 'src/dashbls/' changes from 7e747e8a07..0bb5c5b032 (Kittywhiskers Van Gogh)
257fd5ef9e revert: stop tracking cmake dependency relic_conf.h.in (Kittywhiskers Van Gogh)

Pull request description:

  ## Additional Information

  * Dependency for https://github.com/dashpay/dash/pull/6493
  * Expected subtree hash `7bec74f04710e6031590283cf405e3f141bc63310cafe5e70aae9b8d4c98cbef` (see [instructions](https://github.com/dashpay/dash/pull/6323#pullrequestreview-2357380766) to calculate)
  * Includes [bls-signatures#75](https://github.com/dashpay/bls-signatures/pull/75) and [bls-signatures#106](https://github.com/dashpay/bls-signatures/pull/106)

  ## Breaking Changes

  None expected.

  ## Checklist:

  - [x] I have performed a self-review of my own code **(note: N/A)**
  - [x]  I have commented my code, particularly in hard-to-understand areas **(note: N/A)**
  - [x] I have added or updated relevant unit/integration/functional/e2e tests **(note: N/A)**
  - [x] I have made corresponding changes to the documentation **(note: N/A)**
  - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  PastaPastaPasta:
    utACK 3bbe16c390
  UdjinM6:
    subtree looks good, utACK 3bbe16c390

Tree-SHA512: 3f6853f90dfe5e3040189742858b6728e4ab505513202216f1e2f7213569798d2f2e346d73ece7505f87dc2439fde4c3a51472461163fc7c21734a734cbc0bdb
2024-12-17 11:44:08 -06:00
pasta
a5d54006b3
Merge #6304: backport: merge bitcoin#23280 (coalesce chainstate loading sequence between {,non-}unittest codepaths)
19746513b1 refactor: move remaining `LogPrintf` usage outside (Kittywhiskers Van Gogh)
04dbaa8bd8 style-only: Remove redundant scope in *Chainstate (Kittywhiskers Van Gogh)
872158d248 Remove all #include // for * comments (Kittywhiskers Van Gogh)
09ab62948f test/setup: Use LoadChainstate (Kittywhiskers Van Gogh)
459f33983b node/chainstate: extract Dash post-`InitializeChainstate` logic (Kittywhiskers Van Gogh)
c06e07461e node/chainstate: Add options for in-memory DBs (Kittywhiskers Van Gogh)
52bb35d9c8 node/caches: Remove intermediate variables (Kittywhiskers Van Gogh)
4ab182751e node/caches: Extract cache calculation logic (Kittywhiskers Van Gogh)
d7f1e234c5 validation: VerifyDB only needs Consensus::Params (Kittywhiskers Van Gogh)
c405492874 node/chainstate: Decouple from ShutdownRequested (Kittywhiskers Van Gogh)
fdf803d013 node/chainstate: Decouple from GetTime (Kittywhiskers Van Gogh)
f7aef8d331 init: Delay RPC block notif until warmup finished (Kittywhiskers Van Gogh)
94c0ceb29c Move -checkblocks LogPrintf to AppInitMain (Kittywhiskers Van Gogh)
d3345eeccc node/chainstate: Reduce coupling of LogPrintf (Kittywhiskers Van Gogh)
a141f5d9a7 node/chainstate: Decouple from concept of uiInterface (Kittywhiskers Van Gogh)
913411ed73 Split off VerifyLoadedChainstate (Kittywhiskers Van Gogh)
53231ca29d node/chainstate: Remove do/while loop (Kittywhiskers Van Gogh)
2ea1bbc7aa Move init logistics message for BAD_GENESIS_BLOCK to init.cpp (Kittywhiskers Van Gogh)
29c736280d Move mempool nullptr Assert out of LoadChainstate (Kittywhiskers Van Gogh)
7071282a2d node/chainstate: Decouple from concept of NodeContext (Kittywhiskers Van Gogh)
ee9d3dd5fc node/chainstate: Decouple from ArgsManager (Kittywhiskers Van Gogh)
d7419e42d6 node/chainstate: Decouple from stringy errors (Kittywhiskers Van Gogh)
9ab08c42e4 node/chainstate: Decouple from GetTimeMillis (Kittywhiskers Van Gogh)
2455c06464 node: Extract chainstate loading sequence (Kittywhiskers Van Gogh)
620146bcb8 chore: sync chainstate loading logic with upstream (Kittywhiskers Van Gogh)

Pull request description:

  ## Additional Information

  * Dependent on https://github.com/dashpay/dash/pull/6296

  * Dependent on https://github.com/dashpay/dash/pull/6443

  * As one of the backport's intentions were to unify code between `init.cpp` and `setup_common.cpp`, Dash-specific initialization code (to the extent that it can be moved out non-disruptively) has been spun out into `DashChainstateSetup{,Close}()` so it can also be used in `setup_common.cpp` and `validation_chainstatemanager_tests.cpp`.

    This is also why `DashTestSetup{,Close}()` (now `DashPostChainstateSetup{,Close}()`) was introduced in [dash#5531](https://github.com/dashpay/dash/pull/5531).
    * `DashChainstateSetup{,Close}()` (as defined in `node/chainstate.cpp`) cannot take `NodeContext` in because  `node/chainstate.cpp` is used in `bitcoin-chainstate`, which doesn't include `NodeContext` ([source](https://github.com/bitcoin/bitcoin/pull/24304/files#diff-4cb884d03ebb901069e4ee5de5d02538c40dd9b39919c615d8eaa9d364bbbd77R795-R798)), this is reflected by neither `LoadChainstate` nor `VerifyLoadedChainstate` taking in `NodeContext`.

    * To make it less onerous to use in unit tests, `DashChainstateSetup{,Close}()` has been overloaded with a variant that accepts `NodeContext`.

  * To remove `LogPrintf` usage in `node/chainstate.cpp`, index enablement reporting has been pulled out of chainstate loading and BLS scheme reporting has been abstracted out using `notify_bls_state`.

  ## Breaking Changes

  None expected.

  ## Checklist

  - [x] I have performed a self-review of my own code
  - [x] I have commented my code, particularly in hard-to-understand areas **(note: N/A)**
  - [x] I have added or updated relevant unit/integration/functional/e2e tests
  - [x] I have made corresponding changes to the documentation **(note: N/A)**
  - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  UdjinM6:
    utACK 19746513b1
  PastaPastaPasta:
    utACK 19746513b1

Tree-SHA512: 8ebfce48dccc6a867339aff9374a4cb8dc7b02b0c17432db2b97c982523d0d9589a87e6527a103f314bf32be176486311ef6dcde1c4d5cdccc1eeb1f80bbb040
2024-12-17 10:04:34 -06:00
Kittywhiskers Van Gogh
3bbe16c390
build: stop tracking cmake dependency relic_conf.h.in 2024-12-17 04:34:08 +00:00
Kittywhiskers Van Gogh
43043e623f
depends: update 'src/dashbls' to dashpay/bls-signatures@0bb5c5b0 as efd5c566 2024-12-17 04:29:16 +00:00
Kittywhiskers Van Gogh
efd5c566da Squashed 'src/dashbls/' changes from 7e747e8a07..0bb5c5b032
0bb5c5b032 Merge pull request #107 from kwvg/bump_1.3.5
3170e82074 Merge pull request #106 from UdjinM6/bench_chore
6091f5c056 chore: bump version to 1.3.5
90fd986fa5 chore: drop irrelevant PopSchemeMPL benchmark
ba391e681e bench: use BasicSchemeMPL instead of AugSchemeMPL
bcc6cf9cda bench: add benchmars for Serialize/SerializeToArray
cc649f38ee feat: serialize on the stack (#75)

git-subtree-dir: src/dashbls
git-subtree-split: 0bb5c5b03249c463debb5cef5f7e52ee66f3aaab
2024-12-17 04:29:16 +00:00
Kittywhiskers Van Gogh
257fd5ef9e
revert: stop tracking cmake dependency relic_conf.h.in
reverts:
- 02260cba57.
2024-12-17 04:28:10 +00:00
Kittywhiskers Van Gogh
19746513b1
refactor: move remaining LogPrintf usage outside 2024-12-16 12:21:35 +00:00
Kittywhiskers Van Gogh
04dbaa8bd8
style-only: Remove redundant scope in *Chainstate 2024-12-16 12:21:35 +00:00
Kittywhiskers Van Gogh
872158d248
Remove all #include // for * comments 2024-12-16 12:21:35 +00:00
Kittywhiskers Van Gogh
09ab62948f
test/setup: Use LoadChainstate 2024-12-16 12:19:40 +00:00
Kittywhiskers Van Gogh
459f33983b
node/chainstate: extract Dash post-InitializeChainstate logic 2024-12-16 12:19:40 +00:00
Kittywhiskers Van Gogh
c06e07461e
node/chainstate: Add options for in-memory DBs 2024-12-16 12:19:40 +00:00
Kittywhiskers Van Gogh
52bb35d9c8
node/caches: Remove intermediate variables 2024-12-16 12:19:40 +00:00
Kittywhiskers Van Gogh
4ab182751e
node/caches: Extract cache calculation logic 2024-12-16 12:19:40 +00:00
Kittywhiskers Van Gogh
d7f1e234c5
validation: VerifyDB only needs Consensus::Params 2024-12-16 12:19:40 +00:00
Kittywhiskers Van Gogh
c405492874
node/chainstate: Decouple from ShutdownRequested 2024-12-16 12:19:40 +00:00
Kittywhiskers Van Gogh
fdf803d013
node/chainstate: Decouple from GetTime 2024-12-16 12:19:31 +00:00
Kittywhiskers Van Gogh
f7aef8d331
init: Delay RPC block notif until warmup finished 2024-12-16 12:19:31 +00:00
Kittywhiskers Van Gogh
94c0ceb29c
Move -checkblocks LogPrintf to AppInitMain 2024-12-16 12:19:31 +00:00
Kittywhiskers Van Gogh
d3345eeccc
node/chainstate: Reduce coupling of LogPrintf 2024-12-16 12:19:30 +00:00
Kittywhiskers Van Gogh
a141f5d9a7
node/chainstate: Decouple from concept of uiInterface 2024-12-16 12:19:30 +00:00
Kittywhiskers Van Gogh
913411ed73
Split off VerifyLoadedChainstate 2024-12-16 12:19:16 +00:00
Kittywhiskers Van Gogh
53231ca29d
node/chainstate: Remove do/while loop 2024-12-16 12:19:16 +00:00
Kittywhiskers Van Gogh
2ea1bbc7aa
Move init logistics message for BAD_GENESIS_BLOCK to init.cpp 2024-12-16 12:19:16 +00:00
Kittywhiskers Van Gogh
29c736280d
Move mempool nullptr Assert out of LoadChainstate 2024-12-16 12:19:16 +00:00
Kittywhiskers Van Gogh
7071282a2d
node/chainstate: Decouple from concept of NodeContext 2024-12-16 12:19:12 +00:00
Kittywhiskers Van Gogh
ee9d3dd5fc
node/chainstate: Decouple from ArgsManager 2024-12-15 09:10:45 +00:00
Kittywhiskers Van Gogh
d7419e42d6
node/chainstate: Decouple from stringy errors 2024-12-15 09:10:45 +00:00
Kittywhiskers Van Gogh
9ab08c42e4
node/chainstate: Decouple from GetTimeMillis 2024-12-15 09:10:45 +00:00
Kittywhiskers Van Gogh
2455c06464
node: Extract chainstate loading sequence 2024-12-15 09:10:45 +00:00
Kittywhiskers Van Gogh
620146bcb8
chore: sync chainstate loading logic with upstream
Match formatting with what upcoming commits expect to limit conflicts
2024-12-15 09:10:45 +00:00
MarcoFalke
c5e2fddc7a
Merge bitcoin/bitcoin#23002: Make descriptor wallets by default
9c1052a5218e191fd23c0d9fc06f2fca34b03411 wallet: Default new wallets to descriptor wallets (Andrew Chow)
f19ad404631010a5e2dac2c7cbecd057b005fe2a rpc, wallet: Descriptor wallets are no longer experimental (Andrew Chow)

Pull request description:

  Changes the default wallet type from legacy to descriptors. Descriptor wallets will now by the default type. Additionally, descriptor wallets will no longer be marked as experimental.

  This follows the timeline proposed in #20160

ACKs for top commit:
  lsilva01:
    Tested ACK 9c1052a521 on Ubuntu 20.04
  prayank23:
    tACK 9c1052a521
  meshcollider:
    Code review ACK 9c1052a5218e191fd23c0d9fc06f2fca34b03411

Tree-SHA512: 834e6fec88e0c18673af7ebe135bd5333694d1be502164eb93a90e3e76c27974165aa4e59426945100c88e4eca07356e16886ef5b05cf789683ecb23fc71a12a
2024-11-24 20:54:16 +05:30
24 changed files with 943 additions and 394 deletions

View File

@ -270,6 +270,8 @@ BITCOIN_CORE_H = \
netgroup.h \ netgroup.h \
netmessagemaker.h \ netmessagemaker.h \
node/blockstorage.h \ node/blockstorage.h \
node/caches.h \
node/chainstate.h \
node/coin.h \ node/coin.h \
node/coinstats.h \ node/coinstats.h \
node/connection_types.h \ node/connection_types.h \
@ -502,6 +504,8 @@ libbitcoin_server_a_SOURCES = \
netgroup.cpp \ netgroup.cpp \
net_processing.cpp \ net_processing.cpp \
node/blockstorage.cpp \ node/blockstorage.cpp \
node/caches.cpp \
node/chainstate.cpp \
node/coin.cpp \ node/coin.cpp \
node/coinstats.cpp \ node/coinstats.cpp \
node/connection_types.cpp \ node/connection_types.cpp \

View File

@ -31,6 +31,7 @@ static void SetupWalletToolArgs(ArgsManager& argsman)
argsman.AddArg("-dumpfile=<file name>", "When used with 'dump', writes out the records to this file. When used with 'createfromdump', loads the records into a new wallet.", ArgsManager::ALLOW_STRING, OptionsCategory::OPTIONS); argsman.AddArg("-dumpfile=<file name>", "When used with 'dump', writes out the records to this file. When used with 'createfromdump', loads the records into a new wallet.", ArgsManager::ALLOW_STRING, OptionsCategory::OPTIONS);
argsman.AddArg("-debug=<category>", "Output debugging information (default: 0).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-debug=<category>", "Output debugging information (default: 0).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-descriptors", "Create descriptors wallet. Only for 'create'", ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS); argsman.AddArg("-descriptors", "Create descriptors wallet. Only for 'create'", ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
argsman.AddArg("-legacy", "Create legacy wallet. Only for 'create'", ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
argsman.AddArg("-format=<format>", "The format of the wallet file to create. Either \"bdb\" or \"sqlite\". Only used with 'createfromdump'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-format=<format>", "The format of the wallet file to create. Either \"bdb\" or \"sqlite\". Only used with 'createfromdump'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -debug is true, 0 otherwise).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -debug is true, 0 otherwise).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);

View File

@ -1,5 +1,5 @@
AC_PREREQ([2.60]) AC_PREREQ([2.60])
AC_INIT([libdashbls],[1.3.4]) AC_INIT([libdashbls],[1.3.5])
AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4]) AC_CONFIG_MACRO_DIR([build-aux/m4])

View File

@ -59,6 +59,7 @@ public:
GTElement Pair(const G2Element &b) const; GTElement Pair(const G2Element &b) const;
uint32_t GetFingerprint(bool fLegacy = false) const; uint32_t GetFingerprint(bool fLegacy = false) const;
std::vector<uint8_t> Serialize(bool fLegacy = false) const; std::vector<uint8_t> Serialize(bool fLegacy = false) const;
std::array<uint8_t, SIZE> SerializeToArray(bool fLegacy = false) const;
G1Element Copy(); G1Element Copy();
friend bool operator==(const G1Element &a, const G1Element &b); friend bool operator==(const G1Element &a, const G1Element &b);
@ -102,6 +103,7 @@ public:
G2Element Negate() const; G2Element Negate() const;
GTElement Pair(const G1Element &a) const; GTElement Pair(const G1Element &a) const;
std::vector<uint8_t> Serialize(bool fLegacy = false) const; std::vector<uint8_t> Serialize(bool fLegacy = false) const;
std::array<uint8_t, G2Element::SIZE> SerializeToArray(bool fLegacy = false) const;
G2Element Copy(); G2Element Copy();
friend bool operator==(G2Element const &a, G2Element const &b); friend bool operator==(G2Element const &a, G2Element const &b);
@ -127,6 +129,7 @@ public:
void Serialize(uint8_t *buffer) const; void Serialize(uint8_t *buffer) const;
std::vector<uint8_t> Serialize() const; std::vector<uint8_t> Serialize() const;
std::array<uint8_t, SIZE> SerializeToArray() const;
friend bool operator==(GTElement const &a, GTElement const &b); friend bool operator==(GTElement const &a, GTElement const &b);
friend bool operator!=(GTElement const &a, GTElement const &b); friend bool operator!=(GTElement const &a, GTElement const &b);

View File

@ -82,6 +82,7 @@ class PrivateKey {
// Serialize the key into bytes // Serialize the key into bytes
void Serialize(uint8_t *buffer) const; void Serialize(uint8_t *buffer) const;
std::vector<uint8_t> Serialize(bool fLegacy = false) const; std::vector<uint8_t> Serialize(bool fLegacy = false) const;
std::array<uint8_t, PrivateKey::PRIVATE_KEY_SIZE> SerializeToArray(bool fLegacy = false) const;
G2Element SignG2( G2Element SignG2(
const uint8_t *msg, const uint8_t *msg,

View File

@ -171,11 +171,16 @@ uint32_t G1Element::GetFingerprint(const bool fLegacy) const
} }
std::vector<uint8_t> G1Element::Serialize(const bool fLegacy) const { std::vector<uint8_t> G1Element::Serialize(const bool fLegacy) const {
const auto arr = G1Element::SerializeToArray(fLegacy);
return std::vector<uint8_t>{arr.begin(), arr.end()};
}
std::array<uint8_t, G1Element::SIZE> G1Element::SerializeToArray(const bool fLegacy) const {
uint8_t buffer[G1Element::SIZE + 1]; uint8_t buffer[G1Element::SIZE + 1];
g1_write_bin(buffer, G1Element::SIZE + 1, p, 1); g1_write_bin(buffer, G1Element::SIZE + 1, p, 1);
std::array<uint8_t, G1Element::SIZE> result{};
if (buffer[0] == 0x00) { // infinity if (buffer[0] == 0x00) { // infinity
std::vector<uint8_t> result(G1Element::SIZE, 0);
result[0] = 0xc0; result[0] = 0xc0;
return result; return result;
} }
@ -187,7 +192,9 @@ std::vector<uint8_t> G1Element::Serialize(const bool fLegacy) const {
if (!fLegacy) { if (!fLegacy) {
buffer[1] |= 0x80; // indicate compression buffer[1] |= 0x80; // indicate compression
} }
return std::vector<uint8_t>(buffer + 1, buffer + 1 + G1Element::SIZE);
std::copy_n(buffer + 1, G1Element::SIZE, result.begin());
return result;
} }
bool operator==(const G1Element & a, const G1Element &b) bool operator==(const G1Element & a, const G1Element &b)
@ -386,11 +393,18 @@ G2Element G2Element::Negate() const
GTElement G2Element::Pair(const G1Element& a) const { return a & (*this); } GTElement G2Element::Pair(const G1Element& a) const { return a & (*this); }
std::vector<uint8_t> G2Element::Serialize(const bool fLegacy) const { std::vector<uint8_t> G2Element::Serialize(const bool fLegacy) const {
const auto arr = G2Element::SerializeToArray(fLegacy);
return std::vector<uint8_t>{arr.begin(), arr.end()};
}
std::array<uint8_t, G2Element::SIZE> G2Element::SerializeToArray(const bool fLegacy) const {
uint8_t buffer[G2Element::SIZE + 1]; uint8_t buffer[G2Element::SIZE + 1];
g2_write_bin(buffer, G2Element::SIZE + 1, (g2_st*)q, 1); g2_write_bin(buffer, G2Element::SIZE + 1, (g2_st*)q, 1);
std::array<uint8_t, G2Element::SIZE> result{};
if (buffer[0] == 0x00) { // infinity if (buffer[0] == 0x00) { // infinity
std::vector<uint8_t> result(G2Element::SIZE, 0); result.fill(0);
result[0] = 0xc0; result[0] = 0xc0;
return result; return result;
} }
@ -410,7 +424,6 @@ std::vector<uint8_t> G2Element::Serialize(const bool fLegacy) const {
} }
} }
std::vector<uint8_t> result(G2Element::SIZE, 0);
if (fLegacy) { if (fLegacy) {
std::memcpy(result.data(), buffer + 1, G2Element::SIZE); std::memcpy(result.data(), buffer + 1, G2Element::SIZE);
} else { } else {
@ -551,4 +564,11 @@ std::vector<uint8_t> GTElement::Serialize() const
return data; return data;
} }
std::array<uint8_t, GTElement::SIZE> GTElement::SerializeToArray() const
{
std::array<uint8_t, GTElement::SIZE> data{};
Serialize(data.data());
return data;
}
} // end namespace bls } // end namespace bls

View File

@ -284,6 +284,13 @@ std::vector<uint8_t> PrivateKey::Serialize(const bool fLegacy) const
return data; return data;
} }
std::array<uint8_t, PrivateKey::PRIVATE_KEY_SIZE> PrivateKey::SerializeToArray(bool fLegacy) const
{
std::array<uint8_t, PRIVATE_KEY_SIZE> data{};
Serialize(data.data());
return data;
}
G2Element PrivateKey::SignG2( G2Element PrivateKey::SignG2(
const uint8_t *msg, const uint8_t *msg,
size_t len, size_t len,

View File

@ -31,21 +31,21 @@ using namespace bls;
void benchSigs() { void benchSigs() {
string testName = "Signing"; string testName = "Signing";
const int numIters = 5000; const int numIters = 5000;
PrivateKey sk = AugSchemeMPL().KeyGen(getRandomSeed()); PrivateKey sk = BasicSchemeMPL().KeyGen(getRandomSeed());
vector<uint8_t> message1 = sk.GetG1Element().Serialize(); vector<uint8_t> message1 = sk.GetG1Element().Serialize();
auto start = startStopwatch(); auto start = startStopwatch();
for (int i = 0; i < numIters; i++) { for (int i = 0; i < numIters; i++) {
AugSchemeMPL().Sign(sk, message1); BasicSchemeMPL().Sign(sk, message1);
} }
endStopwatch(testName, start, numIters); endStopwatch(testName, start, numIters);
} }
void benchVerification() { void benchVerification() {
string testName = "Verification"; string testName = "Verification";
const int numIters = 10000; const int numIters = 1000;
PrivateKey sk = AugSchemeMPL().KeyGen(getRandomSeed()); PrivateKey sk = BasicSchemeMPL().KeyGen(getRandomSeed());
G1Element pk = sk.GetG1Element(); G1Element pk = sk.GetG1Element();
std::vector<G2Element> sigs; std::vector<G2Element> sigs;
@ -54,7 +54,7 @@ void benchVerification() {
uint8_t message[4]; uint8_t message[4];
Util::IntToFourBytes(message, i); Util::IntToFourBytes(message, i);
vector<uint8_t> messageBytes(message, message + 4); vector<uint8_t> messageBytes(message, message + 4);
sigs.push_back(AugSchemeMPL().Sign(sk, messageBytes)); sigs.push_back(BasicSchemeMPL().Sign(sk, messageBytes));
} }
auto start = startStopwatch(); auto start = startStopwatch();
@ -62,34 +62,36 @@ void benchVerification() {
uint8_t message[4]; uint8_t message[4];
Util::IntToFourBytes(message, i); Util::IntToFourBytes(message, i);
vector<uint8_t> messageBytes(message, message + 4); vector<uint8_t> messageBytes(message, message + 4);
bool ok = AugSchemeMPL().Verify(pk, messageBytes, sigs[i]); bool ok = BasicSchemeMPL().Verify(pk, messageBytes, sigs[i]);
ASSERT(ok); ASSERT(ok);
} }
endStopwatch(testName, start, numIters); endStopwatch(testName, start, numIters);
} }
void benchBatchVerification() { void benchBatchVerification() {
const int numIters = 100000; const int numIters = 10000;
vector<vector<uint8_t>> sig_bytes; vector<vector<uint8_t>> sig_bytes;
vector<vector<uint8_t>> pk_bytes; vector<vector<uint8_t>> pk_bytes;
vector<vector<uint8_t>> ms; vector<vector<uint8_t>> ms;
auto start = startStopwatch();
for (int i = 0; i < numIters; i++) { for (int i = 0; i < numIters; i++) {
uint8_t message[4]; uint8_t message[4];
Util::IntToFourBytes(message, i); Util::IntToFourBytes(message, i);
vector<uint8_t> messageBytes(message, message + 4); vector<uint8_t> messageBytes(message, message + 4);
PrivateKey sk = AugSchemeMPL().KeyGen(getRandomSeed()); PrivateKey sk = BasicSchemeMPL().KeyGen(getRandomSeed());
G1Element pk = sk.GetG1Element(); G1Element pk = sk.GetG1Element();
sig_bytes.push_back(AugSchemeMPL().Sign(sk, messageBytes).Serialize()); sig_bytes.push_back(BasicSchemeMPL().Sign(sk, messageBytes).Serialize());
pk_bytes.push_back(pk.Serialize()); pk_bytes.push_back(pk.Serialize());
ms.push_back(messageBytes); ms.push_back(messageBytes);
} }
endStopwatch("Batch verification preparation", start, numIters);
vector<G1Element> pks; vector<G1Element> pks;
pks.reserve(numIters); pks.reserve(numIters);
auto start = startStopwatch(); start = startStopwatch();
for (auto const& pk : pk_bytes) { for (auto const& pk : pk_bytes) {
pks.emplace_back(G1Element::FromBytes(Bytes(pk))); pks.emplace_back(G1Element::FromBytes(Bytes(pk)));
} }
@ -105,52 +107,71 @@ void benchBatchVerification() {
endStopwatch("Signature validation", start, numIters); endStopwatch("Signature validation", start, numIters);
start = startStopwatch(); start = startStopwatch();
G2Element aggSig = AugSchemeMPL().Aggregate(sigs); G2Element aggSig = BasicSchemeMPL().Aggregate(sigs);
endStopwatch("Aggregation", start, numIters); endStopwatch("Aggregation", start, numIters);
start = startStopwatch(); start = startStopwatch();
bool ok = AugSchemeMPL().AggregateVerify(pks, ms, aggSig); bool ok = BasicSchemeMPL().AggregateVerify(pks, ms, aggSig);
ASSERT(ok); ASSERT(ok);
endStopwatch("Batch verification", start, numIters); endStopwatch("Batch verification", start, numIters);
} }
void benchFastAggregateVerification() { void benchSerialize() {
const int numIters = 5000; const int numIters = 5000000;
PrivateKey sk = BasicSchemeMPL().KeyGen(getRandomSeed());
vector<G2Element> sigs; G1Element pk = sk.GetG1Element();
vector<G1Element> pks; vector<uint8_t> message = sk.GetG1Element().Serialize();
vector<uint8_t> message = {1, 2, 3, 4, 5, 6, 7, 8}; G2Element sig = BasicSchemeMPL().Sign(sk, message);
vector<G2Element> pops;
for (int i = 0; i < numIters; i++) {
PrivateKey sk = PopSchemeMPL().KeyGen(getRandomSeed());
G1Element pk = sk.GetG1Element();
sigs.push_back(PopSchemeMPL().Sign(sk, message));
pops.push_back(PopSchemeMPL().PopProve(sk));
pks.push_back(pk);
}
auto start = startStopwatch(); auto start = startStopwatch();
G2Element aggSig = PopSchemeMPL().Aggregate(sigs); for (int i = 0; i < numIters; i++) {
endStopwatch("PopScheme Aggregation", start, numIters); sk.Serialize();
}
endStopwatch("Serialize PrivateKey", start, numIters);
start = startStopwatch(); start = startStopwatch();
for (int i = 0; i < numIters; i++) { for (int i = 0; i < numIters; i++) {
bool ok = PopSchemeMPL().PopVerify(pks[i], pops[i]); pk.Serialize();
ASSERT(ok);
} }
endStopwatch("PopScheme Proofs verification", start, numIters); endStopwatch("Serialize G1Element", start, numIters);
start = startStopwatch(); start = startStopwatch();
bool ok = PopSchemeMPL().FastAggregateVerify(pks, message, aggSig); for (int i = 0; i < numIters; i++) {
ASSERT(ok); sig.Serialize();
endStopwatch("PopScheme verification", start, numIters); }
endStopwatch("Serialize G2Element", start, numIters);
}
void benchSerializeToArray() {
const int numIters = 5000000;
PrivateKey sk = BasicSchemeMPL().KeyGen(getRandomSeed());
G1Element pk = sk.GetG1Element();
vector<uint8_t> message = sk.GetG1Element().Serialize();
G2Element sig = BasicSchemeMPL().Sign(sk, message);
auto start = startStopwatch();
for (int i = 0; i < numIters; i++) {
sk.SerializeToArray();
}
endStopwatch("SerializeToArray PrivateKey", start, numIters);
start = startStopwatch();
for (int i = 0; i < numIters; i++) {
pk.SerializeToArray();
}
endStopwatch("SerializeToArray G1Element", start, numIters);
start = startStopwatch();
for (int i = 0; i < numIters; i++) {
sig.SerializeToArray();
}
endStopwatch("SerializeToArray G2Element", start, numIters);
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
benchSigs(); benchSigs();
benchVerification(); benchVerification();
benchBatchVerification(); benchBatchVerification();
benchFastAggregateVerification(); benchSerialize();
benchSerializeToArray();
} }

View File

@ -38,6 +38,8 @@
#include <netbase.h> #include <netbase.h>
#include <netgroup.h> #include <netgroup.h>
#include <node/blockstorage.h> #include <node/blockstorage.h>
#include <node/caches.h>
#include <node/chainstate.h>
#include <node/context.h> #include <node/context.h>
#include <node/interface_ui.h> #include <node/interface_ui.h>
#include <node/txreconciliation.h> #include <node/txreconciliation.h>
@ -333,15 +335,8 @@ void PrepareShutdown(NodeContext& node)
chainstate->ResetCoinsViews(); chainstate->ResetCoinsViews();
} }
} }
node.chain_helper.reset(); DashChainstateSetupClose(node.chain_helper, node.cpoolman, node.dmnman, node.mnhf_manager,
if (node.mnhf_manager) { llmq::quorumSnapshotManager, node.llmq_ctx, Assert(node.mempool.get()));
node.mnhf_manager->DisconnectManagers();
}
node.llmq_ctx.reset();
llmq::quorumSnapshotManager.reset();
node.mempool->DisconnectManagers();
node.dmnman.reset();
node.cpoolman.reset();
node.mnhf_manager.reset(); node.mnhf_manager.reset();
node.evodb.reset(); node.evodb.reset();
} }
@ -1805,37 +1800,20 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false); bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false);
// cache size calculations // cache size calculations
int64_t nTotalCache = (args.GetArg("-dbcache", nDefaultDbCache) << 20); CacheSizes cache_sizes = CalculateCacheSizes(args, g_enabled_filter_types.size());
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache
int64_t nBlockTreeDBCache = std::min(nTotalCache / 8, nMaxBlockDBCache << 20);
nTotalCache -= nBlockTreeDBCache;
int64_t nTxIndexCache = std::min(nTotalCache / 8, args.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxTxIndexCache << 20 : 0);
nTotalCache -= nTxIndexCache;
int64_t filter_index_cache = 0;
if (!g_enabled_filter_types.empty()) {
size_t n_indexes = g_enabled_filter_types.size();
int64_t max_cache = std::min(nTotalCache / 8, max_filter_index_cache << 20);
filter_index_cache = max_cache / n_indexes;
nTotalCache -= filter_index_cache * n_indexes;
}
int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20); // cap total coins db cache
nTotalCache -= nCoinDBCache;
int64_t nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
int64_t nMempoolSizeMax = args.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; int64_t nMempoolSizeMax = args.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
int64_t nEvoDbCache = 1024 * 1024 * 64; // TODO
LogPrintf("Cache configuration:\n"); LogPrintf("Cache configuration:\n");
LogPrintf("* Using %.1f MiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1f MiB for block index database\n", cache_sizes.block_tree_db * (1.0 / 1024 / 1024));
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
LogPrintf("* Using %.1f MiB for transaction index database\n", nTxIndexCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1f MiB for transaction index database\n", cache_sizes.tx_index * (1.0 / 1024 / 1024));
} }
for (BlockFilterType filter_type : g_enabled_filter_types) { for (BlockFilterType filter_type : g_enabled_filter_types) {
LogPrintf("* Using %.1f MiB for %s block filter index database\n", LogPrintf("* Using %.1f MiB for %s block filter index database\n",
filter_index_cache * (1.0 / 1024 / 1024), BlockFilterTypeName(filter_type)); cache_sizes.filter_index * (1.0 / 1024 / 1024), BlockFilterTypeName(filter_type));
} }
LogPrintf("* Using %.1f MiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1f MiB for chain state database\n", cache_sizes.coins_db * (1.0 / 1024 / 1024));
LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024));
assert(!node.mempool); assert(!node.mempool);
assert(!node.chainman); assert(!node.chainman);
@ -1862,279 +1840,155 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
node.govman = std::make_unique<CGovernanceManager>(*node.mn_metaman, *node.netfulfilledman, *node.chainman, node.dmnman, *node.mn_sync); node.govman = std::make_unique<CGovernanceManager>(*node.mn_metaman, *node.netfulfilledman, *node.chainman, node.dmnman, *node.mn_sync);
const bool fReset = fReindex; const bool fReset = fReindex;
auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
};
bilingual_str strLoadError; bilingual_str strLoadError;
uiInterface.InitMessage(_("Loading block index…").translated); uiInterface.InitMessage(_("Loading block index…").translated);
const auto load_block_index_start_time{SteadyClock::now()};
do { std::optional<ChainstateLoadingError> rv;
bool failed_verification = false; try {
const auto load_block_index_start_time{SteadyClock::now()}; rv = LoadChainstate(fReset,
chainman,
try { *node.govman,
LOCK(cs_main); *node.mn_metaman,
*node.mn_sync,
node.evodb.reset(); *node.sporkman,
node.evodb = std::make_unique<CEvoDB>(nEvoDbCache, false, fReset || fReindexChainState); node.mn_activeman,
node.chain_helper,
node.mnhf_manager.reset(); node.cpoolman,
node.mnhf_manager = std::make_unique<CMNHFManager>(*node.evodb); node.dmnman,
node.evodb,
chainman.InitializeChainstate(Assert(node.mempool.get()), *node.evodb, node.chain_helper, llmq::chainLocksHandler, llmq::quorumInstantSendManager); node.mnhf_manager,
chainman.m_total_coinstip_cache = nCoinCacheUsage; llmq::chainLocksHandler,
chainman.m_total_coinsdb_cache = nCoinDBCache; llmq::quorumInstantSendManager,
llmq::quorumSnapshotManager,
auto& pblocktree{chainman.m_blockman.m_block_tree_db}; node.llmq_ctx,
// new CBlockTreeDB tries to delete the existing file, which Assert(node.mempool.get()),
// fails if it's still open from the previous loop. Close it first: fPruneMode,
pblocktree.reset(); args.GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX),
pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, false, fReset)); is_governance_enabled,
args.GetBoolArg("-spentindex", DEFAULT_SPENTINDEX),
// Same logic as above with pblocktree args.GetBoolArg("-timestampindex", DEFAULT_TIMESTAMPINDEX),
node.dmnman.reset(); args.GetBoolArg("-txindex", DEFAULT_TXINDEX),
node.dmnman = std::make_unique<CDeterministicMNManager>(chainman.ActiveChainstate(), *node.evodb); chainparams.GetConsensus(),
node.mempool->ConnectManagers(node.dmnman.get()); chainparams.NetworkIDString(),
fReindexChainState,
node.cpoolman.reset(); cache_sizes.block_tree_db,
node.cpoolman = std::make_unique<CCreditPoolManager>(*node.evodb); cache_sizes.coins_db,
cache_sizes.coins,
llmq::quorumSnapshotManager.reset(); /*block_tree_db_in_memory=*/false,
llmq::quorumSnapshotManager.reset(new llmq::CQuorumSnapshotManager(*node.evodb)); /*coins_db_in_memory=*/false,
ShutdownRequested,
if (node.llmq_ctx) { []() {
node.llmq_ctx->Interrupt(); uiInterface.ThreadSafeMessageBox(
node.llmq_ctx->Stop(); _("Error reading from database, shutting down."),
} "", CClientUIInterface::MSG_ERROR);
node.llmq_ctx.reset(); });
node.llmq_ctx = std::make_unique<LLMQContext>(chainman, *node.dmnman, *node.evodb, *node.mn_metaman, *node.mnhf_manager, *node.sporkman, } catch (const std::exception& e) {
*node.mempool, node.mn_activeman.get(), *node.mn_sync, /*unit_tests=*/false, /*wipe=*/fReset || fReindexChainState); LogPrintf("%s\n", e.what());
// Enable CMNHFManager::{Process, Undo}Block rv = ChainstateLoadingError::ERROR_GENERIC_BLOCKDB_OPEN_FAILED;
node.mnhf_manager->ConnectManagers(node.chainman.get(), node.llmq_ctx->qman.get()); }
if (rv.has_value()) {
node.chain_helper.reset(); switch (rv.value()) {
node.chain_helper = std::make_unique<CChainstateHelper>(*node.cpoolman, *node.dmnman, *node.mnhf_manager, *node.govman, *(node.llmq_ctx->quorum_block_processor), *node.chainman, case ChainstateLoadingError::ERROR_LOADING_BLOCK_DB:
chainparams.GetConsensus(), *node.mn_sync, *node.sporkman, *(node.llmq_ctx->clhandler), *(node.llmq_ctx->qman)); strLoadError = _("Error loading block database");
break;
if (fReset) { case ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK:
pblocktree->WriteReindexing(true);
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
if (fPruneMode)
CleanupBlockRevFiles();
}
if (ShutdownRequested()) break;
// LoadBlockIndex will load m_have_pruned if we've ever removed a
// block file from disk.
// Note that it also sets fReindex based on the disk flag!
// From here on out fReindex and fReset mean something different!
if (!chainman.LoadBlockIndex()) {
if (ShutdownRequested()) break;
strLoadError = _("Error loading block database");
break;
}
if (is_governance_enabled && !args.GetBoolArg("-txindex", DEFAULT_TXINDEX) && chainparams.NetworkIDString() != CBaseChainParams::REGTEST) { // TODO remove this when pruning is fixed. See https://github.com/dashpay/dash/pull/1817 and https://github.com/dashpay/dash/pull/1743
return InitError(_("Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index."));
}
// If the loaded chain has a wrong genesis, bail out immediately // If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around). // (we're likely using a testnet datadir, or the other way around).
if (!chainman.BlockIndex().empty() && return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
!chainman.m_blockman.LookupBlockIndex(chainparams.GetConsensus().hashGenesisBlock)) { case ChainstateLoadingError::ERROR_BAD_DEVNET_GENESIS_BLOCK:
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); return InitError(_("Incorrect or no devnet genesis block found. Wrong datadir for devnet specified?"));
} case ChainstateLoadingError::ERROR_TXINDEX_DISABLED_WHEN_GOV_ENABLED:
return InitError(_("Transaction index can't be disabled with governance validation enabled. Either start with -disablegovernance command line switch or enable transaction index."));
if (!chainparams.GetConsensus().hashDevnetGenesisBlock.IsNull() && !chainman.BlockIndex().empty() && case ChainstateLoadingError::ERROR_ADDRIDX_NEEDS_REINDEX:
!chainman.m_blockman.LookupBlockIndex(chainparams.GetConsensus().hashDevnetGenesisBlock)) { strLoadError = _("You need to rebuild the database using -reindex to enable -addressindex");
return InitError(_("Incorrect or no devnet genesis block found. Wrong datadir for devnet specified?")); break;
} case ChainstateLoadingError::ERROR_SPENTIDX_NEEDS_REINDEX:
strLoadError = _("You need to rebuild the database using -reindex to enable -spentindex");
if (!fReset && !fReindexChainState) { break;
// Check for changed -addressindex state case ChainstateLoadingError::ERROR_TIMEIDX_NEEDS_REINDEX:
if (!fAddressIndex && fAddressIndex != args.GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX)) { strLoadError = _("You need to rebuild the database using -reindex to enable -timestampindex");
strLoadError = _("You need to rebuild the database using -reindex to enable -addressindex"); break;
break; case ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX:
} strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain");
break;
// Check for changed -timestampindex state case ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED:
if (!fTimestampIndex && fTimestampIndex != args.GetBoolArg("-timestampindex", DEFAULT_TIMESTAMPINDEX)) { strLoadError = _("Error initializing block database");
strLoadError = _("You need to rebuild the database using -reindex to enable -timestampindex"); break;
break; case ChainstateLoadingError::ERROR_CHAINSTATE_UPGRADE_FAILED:
} strLoadError = _("Error upgrading chainstate database");
break;
// Check for changed -spentindex state case ChainstateLoadingError::ERROR_REPLAYBLOCKS_FAILED:
if (!fSpentIndex && fSpentIndex != args.GetBoolArg("-spentindex", DEFAULT_SPENTINDEX)) { strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.");
strLoadError = _("You need to rebuild the database using -reindex to enable -spentindex"); break;
break; case ChainstateLoadingError::ERROR_LOADCHAINTIP_FAILED:
} strLoadError = _("Error initializing block database");
} break;
case ChainstateLoadingError::ERROR_GENERIC_BLOCKDB_OPEN_FAILED:
chainman.InitAdditionalIndexes();
LogPrintf("%s: address index %s\n", __func__, fAddressIndex ? "enabled" : "disabled");
LogPrintf("%s: timestamp index %s\n", __func__, fTimestampIndex ? "enabled" : "disabled");
LogPrintf("%s: spent index %s\n", __func__, fSpentIndex ? "enabled" : "disabled");
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks
// in the past, but is now trying to run unpruned.
if (chainman.m_blockman.m_have_pruned && !fPruneMode) {
strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain");
break;
}
// At this point blocktree args are consistent with what's on disk.
// If we're not mid-reindex (based on disk + args), add a genesis block on disk
// (otherwise we use the one already on disk).
// This is called again in ThreadImport after the reindex completes.
if (!fReindex && !chainman.ActiveChainstate().LoadGenesisBlock()) {
strLoadError = _("Error initializing block database");
break;
}
// At this point we're either in reindex or we've loaded a useful
// block tree into BlockIndex()!
bool failed_chainstate_init = false;
for (CChainState* chainstate : chainman.GetAll()) {
chainstate->InitCoinsDB(
/* cache_size_bytes */ nCoinDBCache,
/* in_memory */ false,
/* should_wipe */ fReset || fReindexChainState);
chainstate->CoinsErrorCatcher().AddReadErrCallback([]() {
uiInterface.ThreadSafeMessageBox(
_("Error reading from database, shutting down."),
"", CClientUIInterface::MSG_ERROR);
});
// If necessary, upgrade from older database format.
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!chainstate->CoinsDB().Upgrade()) {
strLoadError = _("Error upgrading chainstate database");
failed_chainstate_init = true;
break;
}
// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!chainstate->ReplayBlocks()) {
strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.");
failed_chainstate_init = true;
break;
}
// The on-disk coinsdb is now in a good state, create the cache
chainstate->InitCoinsCache(nCoinCacheUsage);
assert(chainstate->CanFlushToDisk());
// flush evodb
// TODO: CEvoDB instance should probably be a part of CChainState
// (for multiple chainstates to actually work in parallel)
// and not a global
if (&chainman.ActiveChainstate() == chainstate && !node.evodb->CommitRootTransaction()) {
strLoadError = _("Failed to commit EvoDB");
failed_chainstate_init = true;
break;
}
if (!is_coinsview_empty(chainstate)) {
// LoadChainTip initializes the chain based on CoinsTip()'s best block
if (!chainstate->LoadChainTip()) {
strLoadError = _("Error initializing block database");
failed_chainstate_init = true;
break; // out of the per-chainstate loop
}
assert(chainstate->m_chain.Tip() != nullptr);
}
}
if (failed_chainstate_init) {
break; // out of the chainstate activation do-while
}
if (!node.dmnman->MigrateDBIfNeeded()) {
strLoadError = _("Error upgrading evo database");
break;
}
if (!node.dmnman->MigrateDBIfNeeded2()) {
strLoadError = _("Error upgrading evo database");
break;
}
if (!node.mnhf_manager->ForceSignalDBUpdate()) {
strLoadError = _("Error upgrading evo database for EHF");
break;
}
for (CChainState* chainstate : chainman.GetAll()) {
if (!is_coinsview_empty(chainstate)) {
uiInterface.InitMessage(_("Verifying blocks…").translated);
if (chainman.m_blockman.m_have_pruned && args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n",
MIN_BLOCKS_TO_KEEP);
}
const CBlockIndex* tip = chainstate->m_chain.Tip();
RPCNotifyBlockChange(tip);
if (tip && tip->nTime > GetTime() + MAX_FUTURE_BLOCK_TIME) {
strLoadError = _("The block database contains a block which appears to be from the future. "
"This may be due to your computer's date and time being set incorrectly. "
"Only rebuild the block database if you are sure that your computer's date and time are correct");
failed_verification = true;
break;
}
const bool v19active{DeploymentActiveAfter(tip, chainparams.GetConsensus(), Consensus::DEPLOYMENT_V19)};
if (v19active) {
bls::bls_legacy_scheme.store(false);
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
}
if (!CVerifyDB().VerifyDB(
*chainstate, chainparams, chainstate->CoinsDB(),
*node.evodb,
args.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
strLoadError = _("Corrupted block database detected");
failed_verification = true;
break;
}
// VerifyDB() disconnects blocks which might result in us switching back to legacy.
// Make sure we use the right scheme.
if (v19active && bls::bls_legacy_scheme.load()) {
bls::bls_legacy_scheme.store(false);
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
}
if (args.GetArg("-checklevel", DEFAULT_CHECKLEVEL) >= 3) {
chainstate->ResetBlockFailureFlags(nullptr);
}
} else {
// TODO: CEvoDB instance should probably be a part of CChainState
// (for multiple chainstates to actually work in parallel)
// and not a global
if (&chainman.ActiveChainstate() == chainstate && !node.evodb->IsEmpty()) {
// EvoDB processed some blocks earlier but we have no blocks anymore, something is wrong
strLoadError = _("Error initializing block database");
failed_verification = true;
break;
}
}
}
} catch (const std::exception& e) {
LogPrintf("%s\n", e.what());
strLoadError = _("Error opening block database"); strLoadError = _("Error opening block database");
failed_verification = true; break;
case ChainstateLoadingError::ERROR_COMMITING_EVO_DB:
strLoadError = _("Failed to commit Evo database");
break;
case ChainstateLoadingError::ERROR_UPGRADING_EVO_DB:
strLoadError = _("Error upgrading Evo database");
break;
case ChainstateLoadingError::ERROR_UPGRADING_SIGNALS_DB:
strLoadError = _("Error upgrading evo database for EHF");
break;
case ChainstateLoadingError::SHUTDOWN_PROBED:
break; break;
} }
} else {
LogPrintf("%s: address index %s\n", __func__, fAddressIndex ? "enabled" : "disabled");
LogPrintf("%s: timestamp index %s\n", __func__, fTimestampIndex ? "enabled" : "disabled");
LogPrintf("%s: spent index %s\n", __func__, fSpentIndex ? "enabled" : "disabled");
if (!failed_verification) { std::optional<ChainstateLoadVerifyError> rv2;
try {
uiInterface.InitMessage(_("Verifying blocks…").translated);
auto check_blocks = args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
if (chainman.m_blockman.m_have_pruned && check_blocks > MIN_BLOCKS_TO_KEEP) {
LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n",
MIN_BLOCKS_TO_KEEP);
}
rv2 = VerifyLoadedChainstate(chainman,
*Assert(node.evodb.get()),
fReset,
fReindexChainState,
chainparams.GetConsensus(),
check_blocks,
args.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
static_cast<int64_t(*)()>(GetTime),
[](bool bls_state) {
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls_state);
});
} catch (const std::exception& e) {
LogPrintf("%s\n", e.what());
rv2 = ChainstateLoadVerifyError::ERROR_GENERIC_FAILURE;
}
if (rv2.has_value()) {
switch (rv2.value()) {
case ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE:
strLoadError = _("The block database contains a block which appears to be from the future. "
"This may be due to your computer's date and time being set incorrectly. "
"Only rebuild the block database if you are sure that your computer's date and time are correct");
break;
case ChainstateLoadVerifyError::ERROR_CORRUPTED_BLOCK_DB:
strLoadError = _("Corrupted block database detected");
break;
case ChainstateLoadVerifyError::ERROR_EVO_DB_SANITY_FAILED:
strLoadError = _("Error initializing block database");
break;
case ChainstateLoadVerifyError::ERROR_GENERIC_FAILURE:
strLoadError = _("Error opening block database");
break;
}
} else {
fLoaded = true; fLoaded = true;
LogPrintf(" block index %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - load_block_index_start_time)); LogPrintf(" block index %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - load_block_index_start_time));
} }
} while(false); }
if (!fLoaded && !ShutdownRequested()) { if (!fLoaded && !ShutdownRequested()) {
// first suggest a reindex // first suggest a reindex
@ -2225,14 +2079,14 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
return InitError(*error); return InitError(*error);
} }
g_txindex = std::make_unique<TxIndex>(nTxIndexCache, false, fReindex); g_txindex = std::make_unique<TxIndex>(cache_sizes.tx_index, false, fReindex);
if (!g_txindex->Start(chainman.ActiveChainstate())) { if (!g_txindex->Start(chainman.ActiveChainstate())) {
return false; return false;
} }
} }
for (const auto& filter_type : g_enabled_filter_types) { for (const auto& filter_type : g_enabled_filter_types) {
InitBlockFilterIndex(filter_type, filter_index_cache, false, fReindex); InitBlockFilterIndex(filter_type, cache_sizes.filter_index, false, fReindex);
if (!GetBlockFilterIndex(filter_type)->Start(chainman.ActiveChainstate())) { if (!GetBlockFilterIndex(filter_type)->Start(chainman.ActiveChainstate())) {
return false; return false;
} }
@ -2537,7 +2391,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 13: finished // ********************************************************* Step 13: finished
// At this point, the RPC is "started", but still in warmup, which means it
// cannot yet be called. Before we make it callable, we need to make sure
// that the RPC's view of the best block is valid and consistent with
// ChainstateManager's ActiveTip.
//
// If we do not do this, RPC's view of the best block will be height=0 and
// hash=0x0. This will lead to erroroneous responses for things like
// waitforblockheight.
RPCNotifyBlockChange(chainman.ActiveTip());
SetRPCWarmupFinished(); SetRPCWarmupFinished();
uiInterface.InitMessage(_("Done loading").translated); uiInterface.InitMessage(_("Done loading").translated);
for (const auto& client : node.chain_clients) { for (const auto& client : node.chain_clients) {

32
src/node/caches.cpp Normal file
View File

@ -0,0 +1,32 @@
// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <node/caches.h>
#include <txdb.h>
#include <util/system.h>
#include <validation.h>
CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes)
{
int64_t nTotalCache = (args.GetArg("-dbcache", nDefaultDbCache) << 20);
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache
CacheSizes sizes;
sizes.block_tree_db = std::min(nTotalCache / 8, nMaxBlockDBCache << 20);
nTotalCache -= sizes.block_tree_db;
sizes.tx_index = std::min(nTotalCache / 8, args.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxTxIndexCache << 20 : 0);
nTotalCache -= sizes.tx_index;
sizes.filter_index = 0;
if (n_indexes > 0) {
int64_t max_cache = std::min(nTotalCache / 8, max_filter_index_cache << 20);
sizes.filter_index = max_cache / n_indexes;
nTotalCache -= sizes.filter_index * n_indexes;
}
sizes.coins_db = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
sizes.coins_db = std::min(sizes.coins_db, nMaxCoinsDBCache << 20); // cap total coins db cache
nTotalCache -= sizes.coins_db;
sizes.coins = nTotalCache; // the rest goes to in-memory cache
return sizes;
}

22
src/node/caches.h Normal file
View File

@ -0,0 +1,22 @@
// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_NODE_CACHES_H
#define BITCOIN_NODE_CACHES_H
#include <cstddef>
#include <cstdint>
class ArgsManager;
struct CacheSizes {
int64_t block_tree_db;
int64_t coins_db;
int64_t coins;
int64_t tx_index;
int64_t filter_index;
};
CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes = 0);
#endif // BITCOIN_NODE_CACHES_H

328
src/node/chainstate.cpp Normal file
View File

@ -0,0 +1,328 @@
// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <node/chainstate.h>
#include <consensus/params.h>
#include <deploymentstatus.h>
#include <node/blockstorage.h>
#include <validation.h>
#include <evo/chainhelper.h>
#include <evo/creditpool.h>
#include <evo/deterministicmns.h>
#include <evo/evodb.h>
#include <evo/mnhftx.h>
#include <llmq/chainlocks.h>
#include <llmq/context.h>
#include <llmq/instantsend.h>
#include <llmq/snapshot.h>
std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
ChainstateManager& chainman,
CGovernanceManager& govman,
CMasternodeMetaMan& mn_metaman,
CMasternodeSync& mn_sync,
CSporkManager& sporkman,
std::unique_ptr<CActiveMasternodeManager>& mn_activeman,
std::unique_ptr<CChainstateHelper>& chain_helper,
std::unique_ptr<CCreditPoolManager>& cpoolman,
std::unique_ptr<CDeterministicMNManager>& dmnman,
std::unique_ptr<CEvoDB>& evodb,
std::unique_ptr<CMNHFManager>& mnhf_manager,
std::unique_ptr<llmq::CChainLocksHandler>& clhandler,
std::unique_ptr<llmq::CInstantSendManager>& isman,
std::unique_ptr<llmq::CQuorumSnapshotManager>& qsnapman,
std::unique_ptr<LLMQContext>& llmq_ctx,
CTxMemPool* mempool,
bool fPruneMode,
bool is_addrindex_enabled,
bool is_governance_enabled,
bool is_spentindex_enabled,
bool is_timeindex_enabled,
bool is_txindex_enabled,
const Consensus::Params& consensus_params,
const std::string& network_id,
bool fReindexChainState,
int64_t nBlockTreeDBCache,
int64_t nCoinDBCache,
int64_t nCoinCacheUsage,
bool block_tree_db_in_memory,
bool coins_db_in_memory,
std::function<bool()> shutdown_requested,
std::function<void()> coins_error_cb)
{
auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
};
LOCK(cs_main);
int64_t nEvoDbCache{64 * 1024 * 1024}; // TODO
evodb.reset();
evodb = std::make_unique<CEvoDB>(nEvoDbCache, false, fReset || fReindexChainState);
mnhf_manager.reset();
mnhf_manager = std::make_unique<CMNHFManager>(*evodb);
chainman.InitializeChainstate(mempool, *evodb, chain_helper, clhandler, isman);
chainman.m_total_coinstip_cache = nCoinCacheUsage;
chainman.m_total_coinsdb_cache = nCoinDBCache;
auto& pblocktree{chainman.m_blockman.m_block_tree_db};
// new CBlockTreeDB tries to delete the existing file, which
// fails if it's still open from the previous loop. Close it first:
pblocktree.reset();
pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, block_tree_db_in_memory, fReset));
DashChainstateSetup(chainman, govman, mn_metaman, mn_sync, sporkman, mn_activeman, chain_helper, cpoolman,
dmnman, evodb, mnhf_manager, qsnapman, llmq_ctx, mempool, fReset, fReindexChainState,
consensus_params);
if (fReset) {
pblocktree->WriteReindexing(true);
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
if (fPruneMode)
CleanupBlockRevFiles();
}
if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
// LoadBlockIndex will load m_have_pruned if we've ever removed a
// block file from disk.
// Note that it also sets fReindex based on the disk flag!
// From here on out fReindex and fReset mean something different!
if (!chainman.LoadBlockIndex()) {
if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
return ChainstateLoadingError::ERROR_LOADING_BLOCK_DB;
}
// TODO: Remove this when pruning is fixed.
// See https://github.com/dashpay/dash/pull/1817 and https://github.com/dashpay/dash/pull/1743
if (is_governance_enabled && !is_txindex_enabled && network_id != CBaseChainParams::REGTEST) {
return ChainstateLoadingError::ERROR_TXINDEX_DISABLED_WHEN_GOV_ENABLED;
}
if (!chainman.BlockIndex().empty() &&
!chainman.m_blockman.LookupBlockIndex(consensus_params.hashGenesisBlock)) {
return ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK;
}
if (!consensus_params.hashDevnetGenesisBlock.IsNull() && !chainman.BlockIndex().empty() &&
!chainman.m_blockman.LookupBlockIndex(consensus_params.hashDevnetGenesisBlock)) {
return ChainstateLoadingError::ERROR_BAD_DEVNET_GENESIS_BLOCK;
}
if (!fReset && !fReindexChainState) {
// Check for changed -addressindex state
if (!fAddressIndex && fAddressIndex != is_addrindex_enabled) {
return ChainstateLoadingError::ERROR_ADDRIDX_NEEDS_REINDEX;
}
// Check for changed -timestampindex state
if (!fTimestampIndex && fTimestampIndex != is_timeindex_enabled) {
return ChainstateLoadingError::ERROR_TIMEIDX_NEEDS_REINDEX;
}
// Check for changed -spentindex state
if (!fSpentIndex && fSpentIndex != is_spentindex_enabled) {
return ChainstateLoadingError::ERROR_SPENTIDX_NEEDS_REINDEX;
}
}
chainman.InitAdditionalIndexes();
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks
// in the past, but is now trying to run unpruned.
if (chainman.m_blockman.m_have_pruned && !fPruneMode) {
return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX;
}
// At this point blocktree args are consistent with what's on disk.
// If we're not mid-reindex (based on disk + args), add a genesis block on disk
// (otherwise we use the one already on disk).
// This is called again in ThreadImport after the reindex completes.
if (!fReindex && !chainman.ActiveChainstate().LoadGenesisBlock()) {
return ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED;
}
// At this point we're either in reindex or we've loaded a useful
// block tree into BlockIndex()!
for (CChainState* chainstate : chainman.GetAll()) {
chainstate->InitCoinsDB(
/* cache_size_bytes */ nCoinDBCache,
/* in_memory */ coins_db_in_memory,
/* should_wipe */ fReset || fReindexChainState);
if (coins_error_cb) {
chainstate->CoinsErrorCatcher().AddReadErrCallback(coins_error_cb);
}
// If necessary, upgrade from older database format.
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!chainstate->CoinsDB().Upgrade()) {
return ChainstateLoadingError::ERROR_CHAINSTATE_UPGRADE_FAILED;
}
// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!chainstate->ReplayBlocks()) {
return ChainstateLoadingError::ERROR_REPLAYBLOCKS_FAILED;
}
// The on-disk coinsdb is now in a good state, create the cache
chainstate->InitCoinsCache(nCoinCacheUsage);
assert(chainstate->CanFlushToDisk());
// flush evodb
// TODO: CEvoDB instance should probably be a part of CChainState
// (for multiple chainstates to actually work in parallel)
// and not a global
if (&chainman.ActiveChainstate() == chainstate && !evodb->CommitRootTransaction()) {
return ChainstateLoadingError::ERROR_COMMITING_EVO_DB;
}
if (!is_coinsview_empty(chainstate)) {
// LoadChainTip initializes the chain based on CoinsTip()'s best block
if (!chainstate->LoadChainTip()) {
return ChainstateLoadingError::ERROR_LOADCHAINTIP_FAILED;
}
assert(chainstate->m_chain.Tip() != nullptr);
}
}
if (!dmnman->MigrateDBIfNeeded() || !dmnman->MigrateDBIfNeeded2()) {
return ChainstateLoadingError::ERROR_UPGRADING_EVO_DB;
}
if (!mnhf_manager->ForceSignalDBUpdate()) {
return ChainstateLoadingError::ERROR_UPGRADING_SIGNALS_DB;
}
return std::nullopt;
}
void DashChainstateSetup(ChainstateManager& chainman,
CGovernanceManager& govman,
CMasternodeMetaMan& mn_metaman,
CMasternodeSync& mn_sync,
CSporkManager& sporkman,
std::unique_ptr<CActiveMasternodeManager>& mn_activeman,
std::unique_ptr<CChainstateHelper>& chain_helper,
std::unique_ptr<CCreditPoolManager>& cpoolman,
std::unique_ptr<CDeterministicMNManager>& dmnman,
std::unique_ptr<CEvoDB>& evodb,
std::unique_ptr<CMNHFManager>& mnhf_manager,
std::unique_ptr<llmq::CQuorumSnapshotManager>& qsnapman,
std::unique_ptr<LLMQContext>& llmq_ctx,
CTxMemPool* mempool,
bool fReset,
bool fReindexChainState,
const Consensus::Params& consensus_params)
{
// Same logic as pblocktree
dmnman.reset();
dmnman = std::make_unique<CDeterministicMNManager>(chainman.ActiveChainstate(), *evodb);
mempool->ConnectManagers(dmnman.get());
cpoolman.reset();
cpoolman = std::make_unique<CCreditPoolManager>(*evodb);
qsnapman.reset();
qsnapman.reset(new llmq::CQuorumSnapshotManager(*evodb));
if (llmq_ctx) {
llmq_ctx->Interrupt();
llmq_ctx->Stop();
}
llmq_ctx.reset();
llmq_ctx = std::make_unique<LLMQContext>(chainman, *dmnman, *evodb, mn_metaman, *mnhf_manager, sporkman,
*mempool, mn_activeman.get(), mn_sync, /*unit_tests=*/false, /*wipe=*/fReset || fReindexChainState);
// Enable CMNHFManager::{Process, Undo}Block
mnhf_manager->ConnectManagers(&chainman, llmq_ctx->qman.get());
chain_helper.reset();
chain_helper = std::make_unique<CChainstateHelper>(*cpoolman, *dmnman, *mnhf_manager, govman, *(llmq_ctx->quorum_block_processor), chainman,
consensus_params, mn_sync, sporkman, *(llmq_ctx->clhandler), *(llmq_ctx->qman));
}
void DashChainstateSetupClose(std::unique_ptr<CChainstateHelper>& chain_helper,
std::unique_ptr<CCreditPoolManager>& cpoolman,
std::unique_ptr<CDeterministicMNManager>& dmnman,
std::unique_ptr<CMNHFManager>& mnhf_manager,
std::unique_ptr<llmq::CQuorumSnapshotManager>& qsnapman,
std::unique_ptr<LLMQContext>& llmq_ctx,
CTxMemPool* mempool)
{
chain_helper.reset();
if (mnhf_manager) {
mnhf_manager->DisconnectManagers();
}
llmq_ctx.reset();
qsnapman.reset();
cpoolman.reset();
mempool->DisconnectManagers();
dmnman.reset();
}
std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManager& chainman,
CEvoDB& evodb,
bool fReset,
bool fReindexChainState,
const Consensus::Params& consensus_params,
unsigned int check_blocks,
unsigned int check_level,
std::function<int64_t()> get_unix_time_seconds,
std::function<void(bool)> notify_bls_state)
{
auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
};
LOCK(cs_main);
for (CChainState* chainstate : chainman.GetAll()) {
if (!is_coinsview_empty(chainstate)) {
const CBlockIndex* tip = chainstate->m_chain.Tip();
if (tip && tip->nTime > get_unix_time_seconds() + 2 * 60 * 60) {
return ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE;
}
const bool v19active{DeploymentActiveAfter(tip, consensus_params, Consensus::DEPLOYMENT_V19)};
if (v19active) {
bls::bls_legacy_scheme.store(false);
if (notify_bls_state) notify_bls_state(bls::bls_legacy_scheme.load());
}
if (!CVerifyDB().VerifyDB(
*chainstate, consensus_params, chainstate->CoinsDB(),
evodb,
check_level,
check_blocks)) {
return ChainstateLoadVerifyError::ERROR_CORRUPTED_BLOCK_DB;
}
// VerifyDB() disconnects blocks which might result in us switching back to legacy.
// Make sure we use the right scheme.
if (v19active && bls::bls_legacy_scheme.load()) {
bls::bls_legacy_scheme.store(false);
if (notify_bls_state) notify_bls_state(bls::bls_legacy_scheme.load());
}
if (check_level >= 3) {
chainstate->ResetBlockFailureFlags(nullptr);
}
} else {
// TODO: CEvoDB instance should probably be a part of CChainState
// (for multiple chainstates to actually work in parallel)
// and not a global
if (&chainman.ActiveChainstate() == chainstate && !evodb.IsEmpty()) {
// EvoDB processed some blocks earlier but we have no blocks anymore, something is wrong
return ChainstateLoadVerifyError::ERROR_EVO_DB_SANITY_FAILED;
}
}
}
return std::nullopt;
}

162
src/node/chainstate.h Normal file
View File

@ -0,0 +1,162 @@
// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_NODE_CHAINSTATE_H
#define BITCOIN_NODE_CHAINSTATE_H
#include <cstdint>
#include <functional>
#include <memory>
#include <optional>
#include <string>
class CActiveMasternodeManager;
class CChainstateHelper;
class CCreditPoolManager;
class CDeterministicMNManager;
class CEvoDB;
class CGovernanceManager;
class ChainstateManager;
class CMasternodeMetaMan;
class CMasternodeSync;
class CMNHFManager;
class CSporkManager;
class CTxMemPool;
struct LLMQContext;
namespace llmq {
class CChainLocksHandler;
class CInstantSendManager;
class CQuorumSnapshotManager;
}
namespace Consensus {
struct Params;
}
enum class ChainstateLoadingError {
ERROR_LOADING_BLOCK_DB,
ERROR_BAD_GENESIS_BLOCK,
ERROR_BAD_DEVNET_GENESIS_BLOCK,
ERROR_TXINDEX_DISABLED_WHEN_GOV_ENABLED,
ERROR_ADDRIDX_NEEDS_REINDEX,
ERROR_SPENTIDX_NEEDS_REINDEX,
ERROR_TIMEIDX_NEEDS_REINDEX,
ERROR_PRUNED_NEEDS_REINDEX,
ERROR_LOAD_GENESIS_BLOCK_FAILED,
ERROR_CHAINSTATE_UPGRADE_FAILED,
ERROR_REPLAYBLOCKS_FAILED,
ERROR_LOADCHAINTIP_FAILED,
ERROR_GENERIC_BLOCKDB_OPEN_FAILED,
ERROR_COMMITING_EVO_DB,
ERROR_UPGRADING_EVO_DB,
ERROR_UPGRADING_SIGNALS_DB,
SHUTDOWN_PROBED,
};
/** This sequence can have 4 types of outcomes:
*
* 1. Success
* 2. Shutdown requested
* - nothing failed but a shutdown was triggered in the middle of the
* sequence
* 3. Soft failure
* - a failure that might be recovered from with a reindex
* 4. Hard failure
* - a failure that definitively cannot be recovered from with a reindex
*
* Currently, LoadChainstate returns a std::optional<ChainstateLoadingError>
* which:
*
* - if has_value()
* - Either "Soft failure", "Hard failure", or "Shutdown requested",
* differentiable by the specific enumerator.
*
* Note that a return value of SHUTDOWN_PROBED means ONLY that "during
* this sequence, when we explicitly checked shutdown_requested() at
* arbitrary points, one of those calls returned true". Therefore, a
* return value other than SHUTDOWN_PROBED does not guarantee that
* shutdown_requested() hasn't been called indirectly.
* - else
* - Success!
*/
std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
ChainstateManager& chainman,
CGovernanceManager& govman,
CMasternodeMetaMan& mn_metaman,
CMasternodeSync& mn_sync,
CSporkManager& sporkman,
std::unique_ptr<CActiveMasternodeManager>& mn_activeman,
std::unique_ptr<CChainstateHelper>& chain_helper,
std::unique_ptr<CCreditPoolManager>& cpoolman,
std::unique_ptr<CDeterministicMNManager>& dmnman,
std::unique_ptr<CEvoDB>& evodb,
std::unique_ptr<CMNHFManager>& mnhf_manager,
std::unique_ptr<llmq::CChainLocksHandler>& clhandler,
std::unique_ptr<llmq::CInstantSendManager>& isman,
std::unique_ptr<llmq::CQuorumSnapshotManager>& qsnapman,
std::unique_ptr<LLMQContext>& llmq_ctx,
CTxMemPool* mempool,
bool fPruneMode,
bool is_addrindex_enabled,
bool is_governance_enabled,
bool is_spentindex_enabled,
bool is_timeindex_enabled,
bool is_txindex_enabled,
const Consensus::Params& consensus_params,
const std::string& network_id,
bool fReindexChainState,
int64_t nBlockTreeDBCache,
int64_t nCoinDBCache,
int64_t nCoinCacheUsage,
bool block_tree_db_in_memory,
bool coins_db_in_memory,
std::function<bool()> shutdown_requested = nullptr,
std::function<void()> coins_error_cb = nullptr);
/** Initialize Dash-specific components during chainstate initialization */
void DashChainstateSetup(ChainstateManager& chainman,
CGovernanceManager& govman,
CMasternodeMetaMan& mn_metaman,
CMasternodeSync& mn_sync,
CSporkManager& sporkman,
std::unique_ptr<CActiveMasternodeManager>& mn_activeman,
std::unique_ptr<CChainstateHelper>& chain_helper,
std::unique_ptr<CCreditPoolManager>& cpoolman,
std::unique_ptr<CDeterministicMNManager>& dmnman,
std::unique_ptr<CEvoDB>& evodb,
std::unique_ptr<CMNHFManager>& mnhf_manager,
std::unique_ptr<llmq::CQuorumSnapshotManager>& qsnapman,
std::unique_ptr<LLMQContext>& llmq_ctx,
CTxMemPool* mempool,
bool fReset,
bool fReindexChainState,
const Consensus::Params& consensus_params);
void DashChainstateSetupClose(std::unique_ptr<CChainstateHelper>& chain_helper,
std::unique_ptr<CCreditPoolManager>& cpoolman,
std::unique_ptr<CDeterministicMNManager>& dmnman,
std::unique_ptr<CMNHFManager>& mnhf_manager,
std::unique_ptr<llmq::CQuorumSnapshotManager>& qsnapman,
std::unique_ptr<LLMQContext>& llmq_ctx,
CTxMemPool* mempool);
enum class ChainstateLoadVerifyError {
ERROR_BLOCK_FROM_FUTURE,
ERROR_CORRUPTED_BLOCK_DB,
ERROR_EVO_DB_SANITY_FAILED,
ERROR_GENERIC_FAILURE,
};
std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManager& chainman,
CEvoDB& evodb,
bool fReset,
bool fReindexChainState,
const Consensus::Params& consensus_params,
unsigned int check_blocks,
unsigned int check_level,
std::function<int64_t()> get_unix_time_seconds,
std::function<void(bool)> notify_bls_state = nullptr);
#endif // BITCOIN_NODE_CHAINSTATE_H

View File

@ -107,6 +107,9 @@
<property name="text"> <property name="text">
<string>Descriptor Wallet (EXPERIMENTAL)</string> <string>Descriptor Wallet (EXPERIMENTAL)</string>
</property> </property>
<property name="checked">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>

View File

@ -1642,7 +1642,7 @@ static RPCHelpMan verifychain()
CChainState& active_chainstate = chainman.ActiveChainstate(); CChainState& active_chainstate = chainman.ActiveChainstate();
return CVerifyDB().VerifyDB( return CVerifyDB().VerifyDB(
active_chainstate, Params(), active_chainstate.CoinsTip(), *CHECK_NONFATAL(node.evodb), check_level, check_depth); active_chainstate, Params().GetConsensus(), active_chainstate.CoinsTip(), *CHECK_NONFATAL(node.evodb), check_level, check_depth);
}, },
}; };
} }

View File

@ -816,8 +816,8 @@ void FuncVerifyDB(TestChainSetup& setup)
// Verify db consistency // Verify db consistency
LOCK(cs_main); LOCK(cs_main);
BOOST_REQUIRE(CVerifyDB().VerifyDB(chainman.ActiveChainstate(), Params(), chainman.ActiveChainstate().CoinsTip(), BOOST_REQUIRE(CVerifyDB().VerifyDB(chainman.ActiveChainstate(), Params().GetConsensus(),
*(setup.m_node.evodb), 4, 2)); chainman.ActiveChainstate().CoinsTip(), *(setup.m_node.evodb), 4, 2));
} }
BOOST_AUTO_TEST_SUITE(evo_dip3_activation_tests) BOOST_AUTO_TEST_SUITE(evo_dip3_activation_tests)

View File

@ -30,6 +30,8 @@
#include <net.h> #include <net.h>
#include <net_processing.h> #include <net_processing.h>
#include <noui.h> #include <noui.h>
#include <node/blockstorage.h>
#include <node/chainstate.h>
#include <node/miner.h> #include <node/miner.h>
#include <policy/fees.h> #include <policy/fees.h>
#include <pow.h> #include <pow.h>
@ -38,6 +40,7 @@
#include <rpc/server.h> #include <rpc/server.h>
#include <scheduler.h> #include <scheduler.h>
#include <script/sigcache.h> #include <script/sigcache.h>
#include <shutdown.h>
#include <spork.h> #include <spork.h>
#include <stats/client.h> #include <stats/client.h>
#include <streams.h> #include <streams.h>
@ -103,37 +106,38 @@ std::ostream& operator<<(std::ostream& os, const uint256& num)
return os; return os;
} }
void DashTestSetup(NodeContext& node, const CChainParams& chainparams) void DashChainstateSetup(ChainstateManager& chainman,
NodeContext& node,
bool fReset,
bool fReindexChainState,
const Consensus::Params& consensus_params)
{ {
CChainState& chainstate = Assert(node.chainman)->ActiveChainstate(); DashChainstateSetup(chainman, *Assert(node.govman.get()), *Assert(node.mn_metaman.get()), *Assert(node.mn_sync.get()),
*Assert(node.sporkman.get()), node.mn_activeman, node.chain_helper, node.cpoolman, node.dmnman,
node.evodb, node.mnhf_manager, llmq::quorumSnapshotManager, node.llmq_ctx,
Assert(node.mempool.get()), fReset, fReindexChainState, consensus_params);
}
node.dmnman = std::make_unique<CDeterministicMNManager>(chainstate, *node.evodb); void DashChainstateSetupClose(NodeContext& node)
node.mempool->ConnectManagers(node.dmnman.get()); {
DashChainstateSetupClose(node.chain_helper, node.cpoolman, node.dmnman, node.mnhf_manager,
llmq::quorumSnapshotManager, node.llmq_ctx, Assert(node.mempool.get()));
}
void DashPostChainstateSetup(NodeContext& node)
{
node.cj_ctx = std::make_unique<CJContext>(*node.chainman, *node.connman, *node.dmnman, *node.mn_metaman, *node.mempool, node.cj_ctx = std::make_unique<CJContext>(*node.chainman, *node.connman, *node.dmnman, *node.mn_metaman, *node.mempool,
/*mn_activeman=*/nullptr, *node.mn_sync, node.peerman, /*relay_txes=*/true); /*mn_activeman=*/nullptr, *node.mn_sync, node.peerman, /*relay_txes=*/true);
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
node.coinjoin_loader = interfaces::MakeCoinJoinLoader(*node.cj_ctx->walletman); node.coinjoin_loader = interfaces::MakeCoinJoinLoader(*node.cj_ctx->walletman);
#endif // ENABLE_WALLET #endif // ENABLE_WALLET
node.llmq_ctx = std::make_unique<LLMQContext>(*node.chainman, *node.dmnman, *node.evodb, *node.mn_metaman, *node.mnhf_manager, *node.sporkman, *node.mempool,
/*mn_activeman=*/nullptr, *node.mn_sync, /*unit_tests=*/true, /*wipe=*/false);
Assert(node.mnhf_manager)->ConnectManagers(node.chainman.get(), node.llmq_ctx->qman.get());
node.chain_helper = std::make_unique<CChainstateHelper>(*node.cpoolman, *node.dmnman, *node.mnhf_manager, *node.govman, *(node.llmq_ctx->quorum_block_processor), *node.chainman,
chainparams.GetConsensus(), *node.mn_sync, *node.sporkman, *(node.llmq_ctx->clhandler), *(node.llmq_ctx->qman));
} }
void DashTestSetupClose(NodeContext& node) void DashPostChainstateSetupClose(NodeContext& node)
{ {
node.chain_helper.reset();
node.llmq_ctx->Interrupt();
node.llmq_ctx->Stop();
Assert(node.mnhf_manager)->DisconnectManagers();
node.llmq_ctx.reset();
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
node.coinjoin_loader.reset(); node.coinjoin_loader.reset();
#endif // ENABLE_WALLET #endif // ENABLE_WALLET
node.mempool->DisconnectManagers();
node.dmnman.reset();
node.cj_ctx.reset(); node.cj_ctx.reset();
} }
@ -240,8 +244,10 @@ ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::ve
m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(); m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
m_node.mempool = std::make_unique<CTxMemPool>(m_node.fee_estimator.get(), 1); m_node.mempool = std::make_unique<CTxMemPool>(m_node.fee_estimator.get(), 1);
m_cache_sizes = CalculateCacheSizes(m_args);
m_node.chainman = std::make_unique<ChainstateManager>(); m_node.chainman = std::make_unique<ChainstateManager>();
m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<CBlockTreeDB>(1 << 20, true); m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<CBlockTreeDB>(m_cache_sizes.block_tree_db, true);
m_node.mn_metaman = std::make_unique<CMasternodeMetaMan>(); m_node.mn_metaman = std::make_unique<CMasternodeMetaMan>();
m_node.netfulfilledman = std::make_unique<CNetFulfilledRequestManager>(); m_node.netfulfilledman = std::make_unique<CNetFulfilledRequestManager>();
@ -280,19 +286,38 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
// instead of unit tests, but for now we need these here. // instead of unit tests, but for now we need these here.
RegisterAllCoreRPCCommands(tableRPC); RegisterAllCoreRPCCommands(tableRPC);
{ auto rv = LoadChainstate(fReindex.load(),
LOCK(::cs_main); *Assert(m_node.chainman.get()),
*Assert(m_node.govman.get()),
m_node.chainman->InitializeChainstate(m_node.mempool.get(), *m_node.evodb, m_node.chain_helper, llmq::chainLocksHandler, llmq::quorumInstantSendManager); *Assert(m_node.mn_metaman.get()),
m_node.chainman->ActiveChainstate().InitCoinsDB( *Assert(m_node.mn_sync.get()),
/* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); *Assert(m_node.sporkman.get()),
assert(!m_node.chainman->ActiveChainstate().CanFlushToDisk()); m_node.mn_activeman,
m_node.chainman->ActiveChainstate().InitCoinsCache(1 << 23); m_node.chain_helper,
assert(m_node.chainman->ActiveChainstate().CanFlushToDisk()); m_node.cpoolman,
if (!m_node.chainman->ActiveChainstate().LoadGenesisBlock()) { m_node.dmnman,
throw std::runtime_error("LoadGenesisBlock failed."); m_node.evodb,
} m_node.mnhf_manager,
} llmq::chainLocksHandler,
llmq::quorumInstantSendManager,
llmq::quorumSnapshotManager,
m_node.llmq_ctx,
Assert(m_node.mempool.get()),
fPruneMode,
m_args.GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX),
!m_args.GetBoolArg("-disablegovernance", !DEFAULT_GOVERNANCE_ENABLE),
m_args.GetBoolArg("-spentindex", DEFAULT_SPENTINDEX),
m_args.GetBoolArg("-timestampindex", DEFAULT_TIMESTAMPINDEX),
m_args.GetBoolArg("-txindex", DEFAULT_TXINDEX),
chainparams.GetConsensus(),
chainparams.NetworkIDString(),
m_args.GetBoolArg("-reindex-chainstate", false),
m_cache_sizes.block_tree_db,
m_cache_sizes.coins_db,
m_cache_sizes.coins,
/*block_tree_db_in_memory=*/true,
/*coins_db_in_memory=*/true);
assert(!rv.has_value());
m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman, m_node.banman.get(), m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman, m_node.banman.get(),
@ -305,7 +330,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
m_node.connman->Init(options); m_node.connman->Init(options);
} }
DashTestSetup(m_node, chainparams); DashPostChainstateSetup(m_node);
BlockValidationState state; BlockValidationState state;
if (!m_node.chainman->ActiveChainstate().ActivateBestChain(state)) { if (!m_node.chainman->ActiveChainstate().ActivateBestChain(state)) {
@ -315,8 +340,21 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
TestingSetup::~TestingSetup() TestingSetup::~TestingSetup()
{ {
DashTestSetupClose(m_node); DashPostChainstateSetupClose(m_node);
m_node.connman->Stop();
// Interrupt() and PrepareShutdown() routines
if (m_node.llmq_ctx) {
m_node.llmq_ctx->Interrupt();
m_node.llmq_ctx->Stop();
}
if (m_node.connman) {
m_node.connman->Stop();
}
// DashChainstateSetup() is called by LoadChainstate() internally but
// winding them down is our responsibility
DashChainstateSetupClose(m_node);
m_node.peerman.reset(); m_node.peerman.reset();
m_node.banman.reset(); m_node.banman.reset();
} }

View File

@ -10,6 +10,7 @@
#include <fs.h> #include <fs.h>
#include <key.h> #include <key.h>
#include <util/system.h> #include <util/system.h>
#include <node/caches.h>
#include <node/context.h> #include <node/context.h>
#include <pubkey.h> #include <pubkey.h>
#include <random.h> #include <random.h>
@ -24,6 +25,9 @@
#include <vector> #include <vector>
class CChainParams; class CChainParams;
namespace Consensus {
struct Params;
};
/** This is connected to the logger. Can be used to redirect logs to any other log */ /** This is connected to the logger. Can be used to redirect logs to any other log */
extern const std::function<void(const std::string&)> G_TEST_LOG_FUN; extern const std::function<void(const std::string&)> G_TEST_LOG_FUN;
@ -79,9 +83,17 @@ static inline bool InsecureRandBool() { return g_insecure_rand_ctx.randbool(); }
static constexpr CAmount CENT{1000000}; static constexpr CAmount CENT{1000000};
/* Initialize Dash-specific components after chainstate initialization */ /** Initialize Dash-specific components during chainstate initialization (NodeContext-friendly aliases) */
void DashTestSetup(NodeContext& node, const CChainParams& chainparams); void DashChainstateSetup(ChainstateManager& chainman,
void DashTestSetupClose(NodeContext& node); NodeContext& node,
bool fReset,
bool fReindexChainState,
const Consensus::Params& consensus_params);
void DashChainstateSetupClose(NodeContext& node);
/** Initialize Dash-specific components after chainstate initialization */
void DashPostChainstateSetup(NodeContext& node);
void DashPostChainstateSetupClose(NodeContext& node);
/** Basic testing setup. /** Basic testing setup.
* This just configures logging, data dir and chain parameters. * This just configures logging, data dir and chain parameters.
@ -101,6 +113,8 @@ struct BasicTestingSetup {
* initialization behaviour. * initialization behaviour.
*/ */
struct ChainTestingSetup : public BasicTestingSetup { struct ChainTestingSetup : public BasicTestingSetup {
CacheSizes m_cache_sizes{};
explicit ChainTestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {}); explicit ChainTestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {});
~ChainTestingSetup(); ~ChainTestingSetup();
}; };

View File

@ -8,7 +8,9 @@
#include <index/txindex.h> #include <index/txindex.h>
#include <llmq/blockprocessor.h> #include <llmq/blockprocessor.h>
#include <llmq/chainlocks.h> #include <llmq/chainlocks.h>
#include <llmq/context.h>
#include <llmq/instantsend.h> #include <llmq/instantsend.h>
#include <node/chainstate.h>
#include <node/utxo_snapshot.h> #include <node/utxo_snapshot.h>
#include <random.h> #include <random.h>
#include <rpc/blockchain.h> #include <rpc/blockchain.h>
@ -33,7 +35,7 @@ BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, ChainTestingSetup)
//! First create a legacy (IBD) chainstate, then create a snapshot chainstate. //! First create a legacy (IBD) chainstate, then create a snapshot chainstate.
BOOST_AUTO_TEST_CASE(chainstatemanager) BOOST_AUTO_TEST_CASE(chainstatemanager)
{ {
const CChainParams& chainparams = Params(); const Consensus::Params& consensus_params = Params().GetConsensus();
ChainstateManager& manager = *m_node.chainman; ChainstateManager& manager = *m_node.chainman;
CTxMemPool& mempool = *m_node.mempool; CTxMemPool& mempool = *m_node.mempool;
CEvoDB& evodb = *m_node.evodb; CEvoDB& evodb = *m_node.evodb;
@ -49,7 +51,8 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
/* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false);
WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23)); WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23));
DashTestSetup(m_node, chainparams); DashChainstateSetup(manager, m_node, /*fReset=*/false, /*fReindexChainState=*/false, consensus_params);
DashPostChainstateSetup(m_node);
BOOST_CHECK(!manager.IsSnapshotActive()); BOOST_CHECK(!manager.IsSnapshotActive());
BOOST_CHECK(WITH_LOCK(::cs_main, return !manager.IsSnapshotValidated())); BOOST_CHECK(WITH_LOCK(::cs_main, return !manager.IsSnapshotValidated()));
@ -67,7 +70,12 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
BOOST_CHECK(!manager.SnapshotBlockhash().has_value()); BOOST_CHECK(!manager.SnapshotBlockhash().has_value());
DashTestSetupClose(m_node); DashPostChainstateSetupClose(m_node);
if (m_node.llmq_ctx) {
m_node.llmq_ctx->Interrupt();
m_node.llmq_ctx->Stop();
}
DashChainstateSetupClose(m_node);
// Create a snapshot-based chainstate. // Create a snapshot-based chainstate.
// //
@ -78,7 +86,8 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
); );
chainstates.push_back(&c2); chainstates.push_back(&c2);
DashTestSetup(m_node, chainparams); DashChainstateSetup(manager, m_node, /*fReset=*/false, /*fReindexChainState=*/false, consensus_params);
DashPostChainstateSetup(m_node);
BOOST_CHECK_EQUAL(manager.SnapshotBlockhash().value(), snapshot_blockhash); BOOST_CHECK_EQUAL(manager.SnapshotBlockhash().value(), snapshot_blockhash);
@ -113,7 +122,12 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
// Let scheduler events finish running to avoid accessing memory that is going to be unloaded // Let scheduler events finish running to avoid accessing memory that is going to be unloaded
SyncWithValidationInterfaceQueue(); SyncWithValidationInterfaceQueue();
DashTestSetupClose(m_node); DashPostChainstateSetupClose(m_node);
if (m_node.llmq_ctx) {
m_node.llmq_ctx->Interrupt();
m_node.llmq_ctx->Stop();
}
DashChainstateSetupClose(m_node);
} }
//! Test rebalancing the caches associated with each chainstate. //! Test rebalancing the caches associated with each chainstate.

View File

@ -4139,7 +4139,7 @@ CVerifyDB::~CVerifyDB()
bool CVerifyDB::VerifyDB( bool CVerifyDB::VerifyDB(
CChainState& chainstate, CChainState& chainstate,
const CChainParams& chainparams, const Consensus::Params& consensus_params,
CCoinsView& coinsview, CCoinsView& coinsview,
CEvoDB& evoDb, CEvoDB& evoDb,
int nCheckLevel, int nCheckDepth) int nCheckLevel, int nCheckDepth)
@ -4185,10 +4185,10 @@ bool CVerifyDB::VerifyDB(
} }
CBlock block; CBlock block;
// check level 0: read from disk // check level 0: read from disk
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) if (!ReadBlockFromDisk(block, pindex, consensus_params))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 1: verify block validity // check level 1: verify block validity
if (nCheckLevel >= 1 && !CheckBlock(block, state, chainparams.GetConsensus())) if (nCheckLevel >= 1 && !CheckBlock(block, state, consensus_params))
return error("%s: *** found bad block at %d, hash=%s (%s)\n", __func__, return error("%s: *** found bad block at %d, hash=%s (%s)\n", __func__,
pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString()); pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString());
// check level 2: verify undo validity // check level 2: verify undo validity
@ -4236,7 +4236,7 @@ bool CVerifyDB::VerifyDB(
uiInterface.ShowProgress(_("Verifying blocks…").translated, percentageDone, false); uiInterface.ShowProgress(_("Verifying blocks…").translated, percentageDone, false);
pindex = chainstate.m_chain.Next(pindex); pindex = chainstate.m_chain.Next(pindex);
CBlock block; CBlock block;
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) if (!ReadBlockFromDisk(block, pindex, consensus_params))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
if (!chainstate.ConnectBlock(block, state, pindex, coins)) if (!chainstate.ConnectBlock(block, state, pindex, coins))
return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString()); return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString());

View File

@ -367,7 +367,7 @@ public:
~CVerifyDB(); ~CVerifyDB();
bool VerifyDB( bool VerifyDB(
CChainState& chainstate, CChainState& chainstate,
const CChainParams& chainparams, const Consensus::Params& consensus_params,
CCoinsView& coinsview, CCoinsView& coinsview,
CEvoDB& evoDb, CEvoDB& evoDb,
int nCheckLevel, int nCheckLevel,

View File

@ -2986,7 +2986,7 @@ static RPCHelpMan createwallet()
{"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using upgradetohd (by mnemonic) or sethdseed (WIF private key)."}, {"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using upgradetohd (by mnemonic) or sethdseed (WIF private key)."},
{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Encrypt the wallet with this passphrase."}, {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Encrypt the wallet with this passphrase."},
{"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{false}, "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."}, {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{false}, "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
{"descriptors", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation. This feature is well-tested but still considered experimental."}, {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation. This feature is well-tested but still considered experimental."},
{"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."}, {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
}, },
RPCResult{ RPCResult{
@ -3027,7 +3027,7 @@ static RPCHelpMan createwallet()
if (!request.params[4].isNull() && request.params[4].get_bool()) { if (!request.params[4].isNull() && request.params[4].get_bool()) {
flags |= WALLET_FLAG_AVOID_REUSE; flags |= WALLET_FLAG_AVOID_REUSE;
} }
if (!request.params[5].isNull() && request.params[5].get_bool()) { if (request.params[5].isNull() || request.params[5].get_bool()) {
#ifndef USE_SQLITE #ifndef USE_SQLITE
throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without sqlite support (required for descriptor wallets)"); throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without sqlite support (required for descriptor wallets)");
#endif #endif
@ -3035,7 +3035,6 @@ static RPCHelpMan createwallet()
throw JSONRPCError(RPC_INVALID_PARAMETER, "The createwallet RPC requires specifying the 'load_on_startup' flag when creating descriptor wallets. Dash Core v21 introduced this requirement due to breaking changes in the createwallet RPC."); throw JSONRPCError(RPC_INVALID_PARAMETER, "The createwallet RPC requires specifying the 'load_on_startup' flag when creating descriptor wallets. Dash Core v21 introduced this requirement due to breaking changes in the createwallet RPC.");
} }
flags |= WALLET_FLAG_DESCRIPTORS; flags |= WALLET_FLAG_DESCRIPTORS;
warnings.emplace_back(Untranslated("Wallet is an experimental descriptor wallet"));
} }
#ifndef USE_BDB #ifndef USE_BDB

View File

@ -128,6 +128,10 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
tfm::format(std::cerr, "The -descriptors option can only be used with the 'create' command.\n"); tfm::format(std::cerr, "The -descriptors option can only be used with the 'create' command.\n");
return false; return false;
} }
if (args.IsArgSet("-legacy") && command != "create") {
tfm::format(std::cerr, "The -legacy option can only be used with the 'create' command.\n");
return false;
}
if (command == "create" && !args.IsArgSet("-wallet")) { if (command == "create" && !args.IsArgSet("-wallet")) {
tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n"); tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n");
return false; return false;
@ -138,7 +142,19 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
if (command == "create") { if (command == "create") {
DatabaseOptions options; DatabaseOptions options;
options.require_create = true; options.require_create = true;
if (args.GetBoolArg("-descriptors", false)) { // If -legacy is set, use it. Otherwise default to false.
bool make_legacy = args.GetBoolArg("-legacy", false);
// If neither -legacy nor -descriptors is set, default to true. If -descriptors is set, use its value.
bool make_descriptors = (!args.IsArgSet("-descriptors") && !args.IsArgSet("-legacy")) || (args.IsArgSet("-descriptors") && args.GetBoolArg("-descriptors", true));
if (make_legacy && make_descriptors) {
tfm::format(std::cerr, "Only one of -legacy or -descriptors can be set to true, not both\n");
return false;
}
if (!make_legacy && !make_descriptors) {
tfm::format(std::cerr, "One of -legacy or -descriptors must be set to true (or omitted)\n");
return false;
}
if (make_descriptors) {
options.create_flags |= WALLET_FLAG_DESCRIPTORS; options.create_flags |= WALLET_FLAG_DESCRIPTORS;
options.require_format = DatabaseFormat::SQLITE; options.require_format = DatabaseFormat::SQLITE;
} }

View File

@ -30,8 +30,8 @@ class ToolWalletTest(BitcoinTestFramework):
def dash_wallet_process(self, *args): def dash_wallet_process(self, *args):
binary = self.config["environment"]["BUILDDIR"] + '/src/dash-wallet' + self.config["environment"]["EXEEXT"] binary = self.config["environment"]["BUILDDIR"] + '/src/dash-wallet' + self.config["environment"]["EXEEXT"]
default_args = ['-datadir={}'.format(self.nodes[0].datadir), '-chain=%s' % self.chain] default_args = ['-datadir={}'.format(self.nodes[0].datadir), '-chain=%s' % self.chain]
if self.options.descriptors and 'create' in args: if not self.options.descriptors and 'create' in args:
default_args.append('-descriptors') default_args.append('-legacy')
return subprocess.Popen([binary] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) return subprocess.Popen([binary] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)