Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Wallet] HD Wallet - v2. #1327

Merged
merged 51 commits into from
Mar 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
4198824
[Crypter] vMasterKey protected to be able to get it in the child clas…
furszy Feb 12, 2020
5276621
[Refactor] CExtKey, SetSeed changed to SetMaster following upstream's…
furszy Feb 12, 2020
922a831
KeyOriginInfo struct created.
furszy Feb 12, 2020
c731f26
memory.h file created, upstream backport.
furszy Feb 12, 2020
4b33cef
[Backport] Simple GetScriptForRawPubKey coming from upstream.
furszy Feb 12, 2020
ffb719f
CHDChain class created.
furszy Feb 12, 2020
155a8d9
HD Wallet connected to the wallet.
furszy Feb 12, 2020
698bd64
[Backport] key_io.h/cpp
furszy Feb 4, 2020
99f6071
test framework, at least 10 keys in the keypool to be able to generat…
furszy Feb 4, 2020
beb5fcb
Remove DecodeBase58Check warning
furszy Feb 4, 2020
80a8407
BIP44 derivation path + HD wallet functional tests passing.
furszy Feb 4, 2020
c791b7a
[RPC] getaddressinfo implemented.
furszy Feb 4, 2020
3e79435
[Wallet] SPKM single account.
furszy Feb 4, 2020
37d89f6
[RPC] sethdseed implemented.
furszy Feb 4, 2020
ac87b5c
[Wallet] HD chain scan + mark unused addresses flow implemented.
furszy Feb 4, 2020
198e70e
key_io DecodeSecret backported.
furszy Feb 4, 2020
23aeeb5
[Wallet] Use internal key for tx change.
furszy Feb 4, 2020
bcc8796
[Tests] Backport HD wallet functional test.
furszy Feb 4, 2020
eebb3fc
[Test] wallet_keypool_topup fix.
furszy Feb 4, 2020
ac16d22
[Test] Test runner, wallet_hd.py added.
furszy Feb 4, 2020
2864d82
rpc: Prevent `dumpwallet` from overwriting files.
furszy Feb 7, 2020
84a8403
[RPC] `dumpwallet` exporting hd key path.
furszy Feb 7, 2020
70ba39b
[RPC] `importwallet` hdseed key type added.
furszy Feb 7, 2020
5fb1b7f
[Build] missing HD new files.
furszy Feb 10, 2020
8377ef4
[Cleanup] Unifying internal/external chain counter increment.
furszy Feb 10, 2020
e0621f4
KeyIO namespace.
furszy Feb 10, 2020
811fb29
linux link issue fix
furszy Feb 10, 2020
9a7d0fd
[Wallet] HD Wallet, staking chain counter.
furszy Feb 11, 2020
403ff69
[SPKM] Staking addresses derivation path.
furszy Feb 11, 2020
7a8a1fd
[Unittest] Remove rpc_wallet_tests.cpp.
furszy Feb 11, 2020
4a79a08
[Wallet] GetKeyFromPool using the new keypool type instead of the int…
furszy Feb 11, 2020
0f87145
[Cleanup] Removing unused NewKeyPool from the wallet class.
furszy Feb 12, 2020
a7ea0b0
keyOrigin size validation fix.
furszy Feb 18, 2020
deef0b3
[Wallet] Default keypool size decreased to 100.
furszy Feb 21, 2020
2580cab
[Wallet] CanSupportFeature(FEATURE_HD_SPLIT) moved to IsHDEnabled.
furszy Feb 22, 2020
d0325eb
[RPC] getwalletinfo keypoolsize_hd_staking count added.
furszy Feb 22, 2020
25ee29b
Cleanup: dumpwallet never empty str check removed + duplicated line c…
furszy Feb 22, 2020
cc1a60b
[Wallet] Upgrade to HD flow with -upgradewallet flag.
furszy Feb 25, 2020
805ed41
[RPC] sethdseed help text corrections.
furszy Feb 25, 2020
025c02a
[Cleanup] Removing not used methods.
furszy Feb 28, 2020
69e57c2
[Wallet] throw error if staking key was misclassified.
furszy Feb 28, 2020
5b94a2f
[Wallet] GetOldestKeyPoolTime implemented inside the SPKM.
furszy Feb 28, 2020
051a4c5
[Bug] Return key to the proper keypool.
furszy Feb 28, 2020
1f426ac
[Wallet] Not used wallet feature versions commented (plus init bug fix).
furszy Feb 28, 2020
cc2f0eb
[Wallet] Bugfix, CReservedKey internal flag initialized.
furszy Feb 28, 2020
5748d39
[Test] HD wallet upgrade functional test.
furszy Feb 29, 2020
7f7ffae
[Wallet] Upgrade to HD from a locked wallet error notification + furt…
furszy Mar 5, 2020
2072ebc
[Tests] Replace invalid `/` separator for OS specific separator.
furszy Mar 6, 2020
1cccdea
[Doc] HD Wallet release notes.
furszy Mar 6, 2020
a40cc8a
[Lint] Do not check for trailing spaces in release-notes.md file.
furszy Mar 6, 2020
818dac7
[RPC] Missing sethdseed.
furszy Mar 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -348,9 +348,11 @@ set(WALLET_SOURCES
./src/masternodeman.cpp
./src/messagesigner.cpp
./src/zpiv/mintpool.cpp
./src/wallet/hdchain.cpp
./src/wallet/rpcdump.cpp
./src/zpiv/deterministicmint.cpp
./src/zpiv/zerocoin.cpp
./src/wallet/scriptpubkeyman.cpp
./src/wallet/rpcwallet.cpp
./src/kernel.cpp
./src/wallet/wallet.cpp
Expand Down Expand Up @@ -448,6 +450,7 @@ set(COMMON_SOURCES
./src/bip38.cpp
./src/chainparams.cpp
./src/coins.cpp
./src/key_io.cpp
./src/compressor.cpp
./src/consensus/merkle.cpp
./src/consensus/tx_verify.cpp
Expand Down
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ EXTRA_DIST += \
test/util/data/txcreatescript1.json \
test/util/data/txcreatesign.hex \
test/util/data/txcreatesign.json \
test/util/data/pre_hd_wallet.dat \
test/util/rpcauth-test.py

CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER)
Expand Down
6 changes: 3 additions & 3 deletions contrib/devtools/lint-whitespace.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
# Copyright (c) 2017 The Bitcoin Core developers
# Copyright (c) 2017-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
Expand Down Expand Up @@ -31,14 +31,14 @@ if [ -z "${TRAVIS_COMMIT_RANGE}" ]; then
fi

showdiff() {
if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- "." ":(exclude)depends/patches/" ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/" ":(exclude)build-aux/snap/local/patches/"; then
if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- "." ":(exclude)depends/patches/" ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes.md" ":(exclude)doc/release-notes/" ":(exclude)build-aux/snap/local/patches/"; then
echo "Failed to get a diff"
exit 1
fi
}

showcodediff() {
if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- *.cpp *.h *.md *.py *.sh ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/" ":(exclude)build-aux/snap/local/patches/"; then
if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- *.cpp *.h *.md *.py *.sh ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes.md" ":(exclude)doc/release-notes/" ":(exclude)build-aux/snap/local/patches/"; then
echo "Failed to get a diff"
exit 1
fi
Expand Down
34 changes: 34 additions & 0 deletions doc/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,37 @@ Notable Changes

(Developers: add your notes here as part of your pull requests whenever possible)

### Hierarchical Deterministic Wallet (HD Wallet)

Wallets under a tree derivation structure in which keypairs are generated deterministically from a single seed, which can be shared partially or entirely with different systems, each with or without the ability to spend coins, [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki).

Enabling major improvements over the keystore management, the PIVX wallet doesn't require regular backups as before, keys are following a deterministic creation path that can be verified at any time (before HD Wallet, every keypair was randomly created and added to the keypool, forcing the user to backup the wallet every certain amount of time or could end up loosing coins forever if the latest `wallet.dat` was not being used).
As well as new possibilities like the account extended public key that enables deterministic public keys creation without the private keys requisite inside the wallet (A good use case could be online stores generating fresh addresses).

This work includes a customization/extension to the [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) standard. We have included an unique staking keys derivation path which introduced the deterministic generation/recovery of staking addresses.

An extended description of this large work can be found in the PR [here](https://github.com/PIVX-Project/PIVX/pull/1327).

#### HD Wallet FAQ

- How do i upgrade to HD Wallet?

GUI:
1) A dialog will appear on every wallet startup notifying you that you are running a pre-HD wallet and letting you upgrade it from there.
2) If you haven't upgraded your wallet, the topbar (bar with icons that appears at the top of your wallet) will have an "HD" icon. Click it and the upgrade dialog will be launched.

RPC:
1) If your wallet is unlocked, use the `-upgradewallet` flag at startup and will automatically upgrade your wallet.
2) If your wallet is encrypted, use the `upgradewallet` rpc command. It will upgrade your wallet to the latest wallet version.

- How do i know if i'm already running an HD Wallet?

1) GUI: Go to settings, press on the Debug option, then Information.
2) RPC: call `getwalletinfo`, the `walletversion` field must be `169900` (HD Wallet Feature).


### Functional Changes

Automatic zPIV backup has been disabled. Thus, the following configuration options have been removed (either as entries in the pivx.conf file or as startup flags):
- `autozpivbackup`
- `backupzpiv`
Expand Down Expand Up @@ -72,6 +103,9 @@ RPC Changes

- `setstakesplitthreshold` now accepts decimal amounts. If the provided value is `0`, split staking gets disabled. `getstakesplitthreshold` returns a double.

- `dumpwallet` no longer allows overwriting files. This is a security measure
as well as prevents dangerous user mistakes.

### Removed commands

The following commands have been removed from the RPC interface:
Expand Down
8 changes: 8 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ BITCOIN_CORE_H = \
kernel.h \
swifttx.h \
key.h \
key_io.h \
keystore.h \
leveldbwrapper.h \
limitedmap.h \
Expand Down Expand Up @@ -154,6 +155,7 @@ BITCOIN_CORE_H = \
rpc/server.h \
scheduler.h \
script/interpreter.h \
script/keyorigin.h \
script/script.h \
script/sigcache.h \
script/sign.h \
Expand All @@ -176,6 +178,7 @@ BITCOIN_CORE_H = \
guiinterface.h \
uint256.h \
undo.h \
util/memory.h \
util.h \
util/macros.h \
util/threadnames.h \
Expand All @@ -184,6 +187,8 @@ BITCOIN_CORE_H = \
utiltime.h \
validationinterface.h \
version.h \
wallet/hdchain.h \
wallet/scriptpubkeyman.h \
wallet/wallet.h \
wallet/wallet_ismine.h \
wallet/walletdb.h \
Expand Down Expand Up @@ -269,6 +274,7 @@ libbitcoin_wallet_a_SOURCES = \
wallet/db.cpp \
addressbook.cpp \
crypter.cpp \
key_io.cpp \
swifttx.cpp \
masternode.cpp \
masternode-budget.cpp \
Expand All @@ -280,6 +286,8 @@ libbitcoin_wallet_a_SOURCES = \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
kernel.cpp \
wallet/hdchain.cpp \
wallet/scriptpubkeyman.cpp \
wallet/wallet.cpp \
wallet/wallet_ismine.cpp \
wallet/wallet_zerocoin.cpp \
Expand Down
3 changes: 1 addition & 2 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ BITCOIN_TESTS =\
if ENABLE_WALLET
BITCOIN_TESTS += \
test/accounting_tests.cpp \
wallet/test/wallet_tests.cpp \
test/rpc_wallet_tests.cpp
wallet/test/wallet_tests.cpp
endif

test_test_pivx_SOURCES = $(BITCOIN_TEST_SUITE) $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
Expand Down
2 changes: 1 addition & 1 deletion src/base58.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRe
* Decode a base58-encoded string (str) that includes a checksum into a byte
* vector (vchRet), return true if decoding is successful
*/
inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet);
bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can probably remove it from the overloaded DecodeBase58Check too.


/**
* Base class for all base58-encoded data
Expand Down
5 changes: 3 additions & 2 deletions src/crypter.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,6 @@ bool DecryptAES256(const SecureString& sKey, const std::string& sCiphertext, con
class CCryptoKeyStore : public CBasicKeyStore
{
private:
CKeyingMaterial vMasterKey;

//! if fUseCrypto is true, mapKeys must be empty
//! if fUseCrypto is false, vMasterKey must be empty
bool fUseCrypto;
Expand All @@ -132,6 +130,9 @@ class CCryptoKeyStore : public CBasicKeyStore
bool fDecryptionThoroughlyChecked;

protected:
// TODO: In the future, move this variable to the wallet class directly following upstream's structure.
CKeyingMaterial vMasterKey;

bool SetCrypted();

//! will encrypt previously unencrypted keys
Expand Down
60 changes: 43 additions & 17 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ static void registerSignalHandler(int signal, void(*handler)(int))

bool static InitError(const std::string& str)
{
uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR);
uiInterface.ThreadSafeMessageBox(str, "Init Error", CClientUIInterface::MSG_ERROR);
return false;
}

Expand Down Expand Up @@ -1671,23 +1671,44 @@ bool AppInit2()
strErrors << _("Error loading wallet.dat") << "\n";
}

int prev_version = pwalletMain->GetVersion();
if (GetBoolArg("-upgradewallet", fFirstRun)) {
int nMaxVersion = GetArg("-upgradewallet", 0);
if (nMaxVersion == 0) // the -upgradewallet without argument case
{
LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
nMaxVersion = CLIENT_VERSION;
pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
} else
LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
if (nMaxVersion < pwalletMain->GetVersion())
strErrors << _("Cannot downgrade wallet") << "\n";
pwalletMain->SetMaxVersion(nMaxVersion);

if (prev_version <= FEATURE_PRE_PIVX && pwalletMain->IsLocked()) {
// Cannot upgrade a locked wallet
std::string strProblem = "Cannot upgrade a locked wallet.\n";
strErrors << _("Error: ") << strProblem;
LogPrintf("%s", strErrors.str());
return InitError(strProblem);
} else {

int nMaxVersion = GetArg("-upgradewallet", 0);
if (nMaxVersion == 0) // the -upgradewallet without argument case
{
LogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
nMaxVersion = FEATURE_LATEST;
pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
} else
LogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
if (nMaxVersion < pwalletMain->GetVersion())
strErrors << _("Cannot downgrade wallet") << "\n";
pwalletMain->SetMaxVersion(nMaxVersion);
}
}

// Upgrade to HD if explicit upgrade was requested.
std::string upgradeError;
if (!pwalletMain->Upgrade(upgradeError, prev_version)) {
strErrors << upgradeError << "\n";
}

if (fFirstRun) {
// Create new keyUser and set as default key
CPubKey newDefaultKey;
// Create new HD Wallet
LogPrintf("Creating HD Wallet\n");
// Ensure this wallet.dat can only be opened by clients supporting HD.
pwalletMain->SetMinVersion(FEATURE_LATEST);
pwalletMain->SetupSPKM();
furszy marked this conversation as resolved.
Show resolved Hide resolved

// Top up the keypool
if (!pwalletMain->TopUpKeyPool()) {
// Error generating keys
Expand Down Expand Up @@ -1954,9 +1975,14 @@ bool AppInit2()
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
LogPrintf("chainActive.Height() = %d\n", chainActive.Height());
#ifdef ENABLE_WALLET
LogPrintf("setKeyPool.size() = %u\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0);
LogPrintf("mapWallet.size() = %u\n", pwalletMain ? pwalletMain->mapWallet.size() : 0);
LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
{
if (pwalletMain) {
LOCK(pwalletMain->cs_wallet);
LogPrintf("setKeyPool.size() = %u\n", pwalletMain ? pwalletMain->GetKeyPoolSize() : 0);
LogPrintf("mapWallet.size() = %u\n", pwalletMain ? pwalletMain->mapWallet.size() : 0);
LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
}
}
#endif

if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
Expand Down
2 changes: 1 addition & 1 deletion src/key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ bool CExtKey::Derive(CExtKey& out, unsigned int nChild) const
return key.Derive(out.key, out.chaincode, nChild, chaincode);
}

void CExtKey::SetMaster(const unsigned char* seed, unsigned int nSeedLen)
void CExtKey::SetSeed(const unsigned char* seed, unsigned int nSeedLen)
{
static const unsigned char hashkey[] = {'B', 'i', 't', 'c', 'o', 'i', 'n', ' ', 's', 'e', 'e', 'd'};
std::vector<unsigned char, secure_allocator<unsigned char>> vout(64);
Expand Down
2 changes: 1 addition & 1 deletion src/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ struct CExtKey {
void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
bool Derive(CExtKey& out, unsigned int nChild) const;
CExtPubKey Neuter() const;
void SetMaster(const unsigned char* seed, unsigned int nSeedLen);
void SetSeed(const unsigned char* seed, unsigned int nSeedLen);
};

/** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */
Expand Down
70 changes: 70 additions & 0 deletions src/key_io.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) 2014-2019 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 "key_io.h"

#include "base58.h"
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>

#include <assert.h>
#include <string.h>
#include <algorithm>

namespace KeyIO {

CKey DecodeSecret(const std::string &str) {
CKey key;
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char> &privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
if ((data.size() == 32 + privkey_prefix.size() ||
(data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
bool compressed = data.size() == 33 + privkey_prefix.size();
key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
}
}
if (!data.empty()) {
memory_cleanse(data.data(), data.size());
}
return key;
}

std::string EncodeSecret(const CKey &key) {
assert(key.IsValid());
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
data.insert(data.end(), key.begin(), key.end());
if (key.IsCompressed()) {
data.push_back(1);
}
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
}

CExtKey DecodeExtKey(const std::string &str) {
CExtKey key;
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char> &prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() &&
std::equal(prefix.begin(), prefix.end(), data.begin())) {
key.Decode(data.data() + prefix.size());
}
}
return key;
}

std::string EncodeExtKey(const CExtKey &key) {
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
size_t size = data.size();
data.resize(size + BIP32_EXTKEY_SIZE);
key.Encode(data.data() + size);
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
}

}// namespace
28 changes: 28 additions & 0 deletions src/key_io.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 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 PIVX_KEY_IO_H
#define PIVX_KEY_IO_H

#include "chainparams.h"
#include "key.h"
#include "pubkey.h"
#include "script/standard.h"

#include <string>

namespace KeyIO {

CKey DecodeSecret(const std::string &str);

std::string EncodeSecret(const CKey &key);

CExtKey DecodeExtKey(const std::string &str);

std::string EncodeExtKey(const CExtKey &extkey);

}

#endif //PIVX_KEY_IO_H
Loading