Derive transparent keys from mnemonic seed.
This commit is contained in:
parent
666d135e2e
commit
2885ae7643
|
@ -25,8 +25,7 @@ static void ECDSA(benchmark::State& state)
|
|||
mtx.nVersion = SAPLING_TX_VERSION;
|
||||
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
|
||||
|
||||
CKey key;
|
||||
key.MakeNewKey(false);
|
||||
CKey key = CKey::TestOnlyRandomKey(false);
|
||||
CBasicKeyStore keystore;
|
||||
keystore.AddKeyPubKey(key, key.GetPubKey());
|
||||
CKeyID hash = key.GetPubKey().GetID();
|
||||
|
|
|
@ -684,7 +684,7 @@ void ThreadImport(std::vector<fs::path> vImportFiles, const CChainParams& chainp
|
|||
*/
|
||||
bool InitSanityCheck(void)
|
||||
{
|
||||
if(!ECC_InitSanityCheck()) {
|
||||
if(!CKey::ECC_InitSanityCheck()) {
|
||||
InitError("Elliptic curve cryptography sanity check failure. Aborting.");
|
||||
return false;
|
||||
}
|
||||
|
|
17
src/key.cpp
17
src/key.cpp
|
@ -156,12 +156,14 @@ bool CKey::Check(const unsigned char *vch) {
|
|||
return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch);
|
||||
}
|
||||
|
||||
void CKey::MakeNewKey(bool fCompressedIn) {
|
||||
CKey CKey::TestOnlyRandomKey(bool fCompressedIn) {
|
||||
CKey key;
|
||||
do {
|
||||
GetRandBytes(keydata.data(), keydata.size());
|
||||
} while (!Check(keydata.data()));
|
||||
fValid = true;
|
||||
fCompressed = fCompressedIn;
|
||||
GetRandBytes(key.keydata.data(), key.keydata.size());
|
||||
} while (!Check(key.keydata.data()));
|
||||
key.fValid = true;
|
||||
key.fCompressed = fCompressedIn;
|
||||
return key;
|
||||
}
|
||||
|
||||
bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
|
||||
|
@ -330,9 +332,8 @@ void CExtKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {
|
|||
key.Set(code+42, code+BIP32_EXTKEY_SIZE, true);
|
||||
}
|
||||
|
||||
bool ECC_InitSanityCheck() {
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
bool CKey::ECC_InitSanityCheck() {
|
||||
CKey key = CKey::TestOnlyRandomKey(true);
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
return key.VerifyPubKey(pubkey);
|
||||
}
|
||||
|
|
17
src/key.h
17
src/key.h
|
@ -68,7 +68,17 @@ public:
|
|||
keydata.resize(32);
|
||||
}
|
||||
|
||||
static std::optional<CKey> FromEntropy(std::vector<unsigned char, secure_allocator<unsigned char>> keydata);
|
||||
/**
|
||||
* Construct a random key. This is used only for internal sanity checks;
|
||||
* all keys that actually control live funds should be derived from the
|
||||
* wallet's mnemonic seed.
|
||||
*/
|
||||
static CKey TestOnlyRandomKey(bool fCompressedIn);
|
||||
|
||||
static std::optional<CKey> FromEntropy(std::vector<unsigned char, secure_allocator<unsigned char>> keydata, bool fComporessedIn);
|
||||
|
||||
/** Check that required EC support is available at runtime. */
|
||||
static bool ECC_InitSanityCheck();
|
||||
|
||||
friend bool operator==(const CKey& a, const CKey& b)
|
||||
{
|
||||
|
@ -106,9 +116,6 @@ public:
|
|||
//! Initialize from a CPrivKey (serialized OpenSSL-format private key data).
|
||||
bool SetPrivKey(const CPrivKey& vchPrivKey, bool fCompressed);
|
||||
|
||||
//! Generate a new private key using a cryptographic PRNG.
|
||||
void MakeNewKey(bool fCompressed);
|
||||
|
||||
/**
|
||||
* Convert the private key to a CPrivKey (serialized OpenSSL-format private key data).
|
||||
* This is expensive.
|
||||
|
@ -199,7 +206,5 @@ void ECC_Start(void);
|
|||
/** Deinitialize the elliptic curve support. No-op if ECC_Start wasn't called first. */
|
||||
void ECC_Stop(void);
|
||||
|
||||
/** Check that required EC support is available at runtime. */
|
||||
bool ECC_InitSanityCheck(void);
|
||||
|
||||
#endif // BITCOIN_KEY_H
|
||||
|
|
|
@ -126,8 +126,7 @@ BOOST_DATA_TEST_CASE(DoS_mapOrphans, boost::unit_test::data::xrange(static_cast<
|
|||
{
|
||||
uint32_t consensusBranchId = NetworkUpgradeInfo[sample].nBranchId;
|
||||
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
CKey key = CKey::TestOnlyRandomKey(true);
|
||||
CBasicKeyStore keystore;
|
||||
keystore.AddKey(key);
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ BOOST_DATA_TEST_CASE(multisig_verify, boost::unit_test::data::xrange(static_cast
|
|||
CKey key[4];
|
||||
CAmount amount = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
key[i].MakeNewKey(true);
|
||||
key[i] = CKey::TestOnlyRandomKey(true);
|
||||
|
||||
CScript a_and_b;
|
||||
a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
|
||||
|
@ -149,7 +149,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
|
|||
{
|
||||
CKey key[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
key[i].MakeNewKey(true);
|
||||
key[i] = CKey::TestOnlyRandomKey(true);
|
||||
|
||||
txnouttype whichType;
|
||||
|
||||
|
@ -191,7 +191,7 @@ BOOST_DATA_TEST_CASE(multisig_Sign, boost::unit_test::data::xrange(static_cast<i
|
|||
CKey key[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
key[i].MakeNewKey(true);
|
||||
key[i] = CKey::TestOnlyRandomKey(true);
|
||||
keystore.AddKey(key[i]);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ BOOST_AUTO_TEST_CASE(basic_sanity)
|
|||
{
|
||||
BOOST_CHECK_MESSAGE(glibc_sanity_test() == true, "libc sanity test");
|
||||
BOOST_CHECK_MESSAGE(glibcxx_sanity_test() == true, "stdlib sanity test");
|
||||
BOOST_CHECK_MESSAGE(ECC_InitSanityCheck() == true, "ECC sanity test");
|
||||
BOOST_CHECK_MESSAGE(CKey::ECC_InitSanityCheck() == true, "ECC sanity test");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
@ -67,7 +67,7 @@ BOOST_DATA_TEST_CASE(sign, boost::unit_test::data::xrange(static_cast<int>(Conse
|
|||
CKey key[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
key[i].MakeNewKey(true);
|
||||
key[i] = CKey::TestOnlyRandomKey(true);
|
||||
keystore.AddKey(key[i]);
|
||||
}
|
||||
|
||||
|
@ -170,7 +170,7 @@ BOOST_DATA_TEST_CASE(set, boost::unit_test::data::xrange(static_cast<int>(Consen
|
|||
std::vector<CPubKey> keys;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
key[i].MakeNewKey(true);
|
||||
key[i] = CKey::TestOnlyRandomKey(true);
|
||||
keystore.AddKey(key[i]);
|
||||
keys.push_back(key[i].GetPubKey());
|
||||
}
|
||||
|
@ -282,7 +282,7 @@ BOOST_DATA_TEST_CASE(AreInputsStandard, boost::unit_test::data::xrange(static_ca
|
|||
vector<CPubKey> keys;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
key[i].MakeNewKey(true);
|
||||
key[i] = CKey::TestOnlyRandomKey(true);
|
||||
keystore.AddKey(key[i]);
|
||||
}
|
||||
for (int i = 0; i < 3; i++)
|
||||
|
|
|
@ -22,7 +22,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
|
|||
CKey keys[3];
|
||||
CPubKey pubkeys[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
keys[i].MakeNewKey(true);
|
||||
keys[i] = CKey::TestOnlyRandomKey(true);
|
||||
pubkeys[i] = keys[i].GetPubKey();
|
||||
}
|
||||
|
||||
|
@ -103,9 +103,8 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
|
||||
{
|
||||
CKey key;
|
||||
CKey key = CKey::TestOnlyRandomKey(true);
|
||||
CPubKey pubkey;
|
||||
key.MakeNewKey(true);
|
||||
pubkey = key.GetPubKey();
|
||||
|
||||
CScript s;
|
||||
|
@ -165,9 +164,8 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
|
||||
{
|
||||
CKey key;
|
||||
CKey key = CKey::TestOnlyRandomKey(true);
|
||||
CPubKey pubkey;
|
||||
key.MakeNewKey(true);
|
||||
pubkey = key.GetPubKey();
|
||||
|
||||
CScript s;
|
||||
|
@ -221,7 +219,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
|
|||
CKey keys[3];
|
||||
CPubKey pubkeys[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
keys[i].MakeNewKey(true);
|
||||
keys[i] = CKey::TestOnlyRandomKey(true);
|
||||
pubkeys[i] = keys[i].GetPubKey();
|
||||
}
|
||||
|
||||
|
@ -297,7 +295,7 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_)
|
|||
CKey keys[3];
|
||||
CPubKey pubkeys[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
keys[i].MakeNewKey(true);
|
||||
keys[i] = CKey::TestOnlyRandomKey(true);
|
||||
pubkeys[i] = keys[i].GetPubKey();
|
||||
}
|
||||
|
||||
|
@ -343,12 +341,11 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine)
|
|||
CKey keys[2];
|
||||
CPubKey pubkeys[2];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
keys[i].MakeNewKey(true);
|
||||
keys[i] = CKey::TestOnlyRandomKey(true);
|
||||
pubkeys[i] = keys[i].GetPubKey();
|
||||
}
|
||||
|
||||
CKey uncompressedKey;
|
||||
uncompressedKey.MakeNewKey(false);
|
||||
CKey uncompressedKey = CKey::TestOnlyRandomKey(false);
|
||||
CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
|
||||
|
||||
CScript scriptPubKey;
|
||||
|
|
|
@ -701,10 +701,9 @@ BOOST_DATA_TEST_CASE(script_CHECKMULTISIG12, boost::unit_test::data::xrange(stat
|
|||
uint32_t consensusBranchId = NetworkUpgradeInfo[sample].nBranchId;
|
||||
|
||||
ScriptError err;
|
||||
CKey key1, key2, key3;
|
||||
key1.MakeNewKey(true);
|
||||
key2.MakeNewKey(false);
|
||||
key3.MakeNewKey(true);
|
||||
CKey key1 = CKey::TestOnlyRandomKey(true);
|
||||
CKey key2 = CKey::TestOnlyRandomKey(false);
|
||||
CKey key3 = CKey::TestOnlyRandomKey(true);
|
||||
|
||||
CScript scriptPubKey12;
|
||||
scriptPubKey12 << OP_1 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
|
||||
|
@ -734,11 +733,10 @@ BOOST_DATA_TEST_CASE(script_CHECKMULTISIG23, boost::unit_test::data::xrange(stat
|
|||
uint32_t consensusBranchId = NetworkUpgradeInfo[sample].nBranchId;
|
||||
|
||||
ScriptError err;
|
||||
CKey key1, key2, key3, key4;
|
||||
key1.MakeNewKey(true);
|
||||
key2.MakeNewKey(false);
|
||||
key3.MakeNewKey(true);
|
||||
key4.MakeNewKey(false);
|
||||
CKey key1 = CKey::TestOnlyRandomKey(true);
|
||||
CKey key2 = CKey::TestOnlyRandomKey(false);
|
||||
CKey key3 = CKey::TestOnlyRandomKey(true);
|
||||
CKey key4 = CKey::TestOnlyRandomKey(false);
|
||||
|
||||
CScript scriptPubKey23;
|
||||
scriptPubKey23 << OP_2 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << ToByteVector(key3.GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
|
||||
|
@ -812,8 +810,7 @@ BOOST_DATA_TEST_CASE(script_combineSigs, boost::unit_test::data::xrange(static_c
|
|||
vector<CPubKey> pubkeys;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
CKey key;
|
||||
key.MakeNewKey(i%2 == 1);
|
||||
CKey key = CKey::TestOnlyRandomKey(i%2 == 1);
|
||||
keys.push_back(key);
|
||||
pubkeys.push_back(key.GetPubKey());
|
||||
keystore.AddKey(key);
|
||||
|
|
|
@ -47,8 +47,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
|
|||
std::vector<CPubKey> keys;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
CKey k;
|
||||
k.MakeNewKey(true);
|
||||
CKey k = CKey::TestOnlyRandomKey(true);
|
||||
keys.push_back(k.GetPubKey());
|
||||
}
|
||||
CScript s2 = GetScriptForMultisig(1, keys);
|
||||
|
|
|
@ -130,7 +130,7 @@ TestingSetup::~TestingSetup()
|
|||
TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
|
||||
{
|
||||
// Generate a 100-block chain:
|
||||
coinbaseKey.MakeNewKey(true);
|
||||
coinbaseKey = CKey::TestOnlyRandomKey(true);
|
||||
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
|
||||
for (int i = 0; i < COINBASE_MATURITY; i++)
|
||||
{
|
||||
|
|
|
@ -270,7 +270,7 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
|
|||
CKey key[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
key[i].MakeNewKey(i % 2);
|
||||
key[i] = CKey::TestOnlyRandomKey(i % 2);
|
||||
keystoreRet.AddKey(key[i]);
|
||||
}
|
||||
|
||||
|
@ -639,8 +639,7 @@ BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) {
|
|||
mtx.nVersion = OVERWINTER_TX_VERSION;
|
||||
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
|
||||
|
||||
CKey key;
|
||||
key.MakeNewKey(false);
|
||||
CKey key = CKey::TestOnlyRandomKey(false);
|
||||
CBasicKeyStore keystore;
|
||||
keystore.AddKeyPubKey(key, key.GetPubKey());
|
||||
CKeyID hash = key.GetPubKey().GetID();
|
||||
|
@ -731,8 +730,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
|||
t.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
|
||||
t.vout.resize(1);
|
||||
t.vout[0].nValue = 90*CENT;
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
CKey key = CKey::TestOnlyRandomKey(true);
|
||||
t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
|
||||
|
||||
string reason;
|
||||
|
@ -826,8 +824,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandardV2)
|
|||
t.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
|
||||
t.vout.resize(1);
|
||||
t.vout[0].nValue = 90*CENT;
|
||||
CKey key;
|
||||
key.MakeNewKey(true);
|
||||
CKey key = CKey::TestOnlyRandomKey(true);
|
||||
t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
|
||||
|
||||
string reason;
|
||||
|
|
|
@ -865,15 +865,26 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase, TxValues& txVa
|
|||
return t_inputs_.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a dust threshold based upon a standard p2pkh txout.
|
||||
*/
|
||||
CAmount DefaultDustThreshold(const CFeeRate& minRelayTxFee) {
|
||||
// Use the all-zeros seed, we're only constructing a key in order
|
||||
// to get a txout from which we can obtain the dust threshold.
|
||||
// Master key generation results in a compressed key.
|
||||
RawHDSeed seed(64, 0x00);
|
||||
CKey secret = CExtKey::Master(seed.data(), 64).key;
|
||||
CScript scriptPubKey = GetScriptForDestination(secret.GetPubKey().GetID());
|
||||
CTxOut txout(CAmount(1), scriptPubKey);
|
||||
return txout.GetDustThreshold(minRelayTxFee);
|
||||
}
|
||||
|
||||
bool AsyncRPCOperation_sendmany::load_inputs(TxValues& txValues) {
|
||||
// If from address is a taddr, select UTXOs to spend
|
||||
CAmount selectedUTXOAmount = 0;
|
||||
|
||||
// Get dust threshold
|
||||
CKey secret;
|
||||
secret.MakeNewKey(true);
|
||||
CScript scriptPubKey = GetScriptForDestination(secret.GetPubKey().GetID());
|
||||
CTxOut out(CAmount(1), scriptPubKey);
|
||||
CAmount dustThreshold = out.GetDustThreshold(minRelayTxFee);
|
||||
CAmount dustThreshold = DefaultDustThreshold(minRelayTxFee);
|
||||
CAmount dustChange = -1;
|
||||
|
||||
std::vector<COutput> selectedTInputs;
|
||||
|
|
|
@ -167,10 +167,10 @@ UniValue getnewaddress(const UniValue& params, bool fHelp)
|
|||
pwalletMain->TopUpKeyPool();
|
||||
|
||||
// Generate a new key that is added to wallet
|
||||
CPubKey newKey;
|
||||
if (!pwalletMain->GetKeyFromPool(newKey))
|
||||
std::optional<CPubKey> newKey = pwalletMain->GetKeyFromPool();
|
||||
if (!newKey.has_value())
|
||||
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
|
||||
CKeyID keyID = newKey.GetID();
|
||||
CKeyID keyID = newKey.value().GetID();
|
||||
|
||||
std::string dummy_account;
|
||||
pwalletMain->SetAddressBook(keyID, dummy_account, "receive");
|
||||
|
|
|
@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
|||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
CPubKey demoPubkey = pwalletMain->GenerateNewKey();
|
||||
CPubKey demoPubkey = pwalletMain->GenerateNewKey().value();
|
||||
CTxDestination demoAddress(CTxDestination(demoPubkey.GetID()));
|
||||
UniValue retValue;
|
||||
string strPurpose = "receive";
|
||||
|
@ -143,7 +143,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
|||
pwalletMain->SetAddressBook(demoPubkey.GetID(), "", strPurpose);
|
||||
});
|
||||
|
||||
CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey();
|
||||
CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey().value();
|
||||
CTxDestination setaccountDemoAddress(CTxDestination(setaccountDemoPubkey.GetID()));
|
||||
|
||||
/*********************************
|
||||
|
@ -1469,7 +1469,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_taddr_to_sapling)
|
|||
|
||||
KeyIO keyIO(Params());
|
||||
// add keys manually
|
||||
auto taddr = pwalletMain->GenerateNewKey().GetID();
|
||||
auto taddr = pwalletMain->GenerateNewKey().value().GetID();
|
||||
std::string taddr1 = keyIO.EncodeDestination(taddr);
|
||||
auto pa = DefaultSaplingAddress(pwalletMain);
|
||||
std::string zaddr1 = keyIO.EncodePaymentAddress(pa);
|
||||
|
@ -2173,7 +2173,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_internals)
|
|||
void TestWTxStatus(const Consensus::Params consensusParams, const int delta) {
|
||||
|
||||
auto AddTrx = [&consensusParams]() {
|
||||
auto taddr = pwalletMain->GenerateNewKey().GetID();
|
||||
auto taddr = pwalletMain->GenerateNewKey().value().GetID();
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(consensusParams, 1);
|
||||
CScript scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(taddr) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
mtx.vout.push_back(CTxOut(5 * COIN, scriptPubKey));
|
||||
|
|
|
@ -245,30 +245,50 @@ bool CWallet::AddSproutZKey(const libzcash::SproutSpendingKey &key)
|
|||
return true;
|
||||
}
|
||||
|
||||
CPubKey CWallet::GenerateNewKey()
|
||||
std::optional<CPubKey> CWallet::GenerateNewKey()
|
||||
{
|
||||
AssertLockHeld(cs_wallet); // mapKeyMetadata
|
||||
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
|
||||
auto seedOpt = GetMnemonicSeed();
|
||||
CHDChain& hdChain = mnemonicHDChain.value();
|
||||
if (seedOpt.has_value()) {
|
||||
// All mnemonic seeds are checked at construction to ensure that we can obtain
|
||||
// a valid spending key for the account ZCASH_LEGACY_TRANSPARENT_ACCOUNT;
|
||||
// therefore, the `value()` call here is safe.
|
||||
BIP32AccountChains accountChains = BIP32AccountChains::ForAccount(
|
||||
seedOpt.value(),
|
||||
BIP44CoinType(),
|
||||
ZCASH_LEGACY_TRANSPARENT_ACCOUNT).value();
|
||||
|
||||
CKey secret;
|
||||
secret.MakeNewKey(fCompressed);
|
||||
while (true) {
|
||||
auto extKey = accountChains.DeriveExternal(hdChain.GetLegacyTKeyCounter());
|
||||
hdChain.IncrementLegacyTKeyCounter();
|
||||
|
||||
// Compressed public keys were introduced in version 0.6.0
|
||||
if (fCompressed)
|
||||
SetMinVersion(FEATURE_COMPRPUBKEY);
|
||||
// if we did not successfully generate a key, try again.
|
||||
if (extKey.has_value()) {
|
||||
CKey secret = extKey.value().first.key;
|
||||
CPubKey pubkey = secret.GetPubKey();
|
||||
assert(secret.VerifyPubKey(pubkey));
|
||||
|
||||
CPubKey pubkey = secret.GetPubKey();
|
||||
assert(secret.VerifyPubKey(pubkey));
|
||||
// Create new metadata
|
||||
const CKeyMetadata& keyMeta = extKey.value().second;
|
||||
mapKeyMetadata[pubkey.GetID()] = keyMeta;
|
||||
if (!nTimeFirstKey || keyMeta.nCreateTime < nTimeFirstKey)
|
||||
nTimeFirstKey = keyMeta.nCreateTime;
|
||||
|
||||
// Create new metadata
|
||||
int64_t nCreationTime = GetTime();
|
||||
mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime);
|
||||
if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
|
||||
nTimeFirstKey = nCreationTime;
|
||||
if (!AddKeyPubKey(secret, pubkey))
|
||||
throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
|
||||
|
||||
if (!AddKeyPubKey(secret, pubkey))
|
||||
throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
|
||||
return pubkey;
|
||||
// Update the persisted chain information
|
||||
if (fFileBacked && !CWalletDB(strWalletFile).WriteMnemonicHDChain(hdChain)) {
|
||||
throw std::runtime_error("CWallet::GenerateNewKey(): Writing HD chain model failed");
|
||||
}
|
||||
|
||||
return pubkey;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
|
||||
|
@ -375,9 +395,9 @@ UnifiedSpendingKey CWallet::GenerateNewUnifiedSpendingKey() {
|
|||
throw std::runtime_error(std::string(__func__) + ": Wallet has no mnemonic HD seed. Please upgrade this wallet.");
|
||||
}
|
||||
|
||||
auto hdChain = GetMnemonicHDChain().value();
|
||||
CHDChain& hdChain = mnemonicHDChain.value();
|
||||
while (true) {
|
||||
auto usk = UnifiedSpendingKey::Derive(seed.value(), BIP44CoinType(), hdChain.GetAccountCounter());
|
||||
auto usk = UnifiedSpendingKey::ForAccount(seed.value(), BIP44CoinType(), hdChain.GetAccountCounter());
|
||||
hdChain.IncrementAccountCounter();
|
||||
|
||||
if (usk.has_value()) {
|
||||
|
@ -397,7 +417,7 @@ std::optional<libzcash::UnifiedSpendingKey> CWallet::GetUnifiedSpendingKeyForAcc
|
|||
auto seed = GetMnemonicSeed();
|
||||
assert(seed.has_value());
|
||||
// TODO: is there any reason to cache and not re-derive this every time?
|
||||
auto usk = UnifiedSpendingKey::Derive(seed.value(), BIP44CoinType(), accountId);
|
||||
auto usk = UnifiedSpendingKey::ForAccount(seed.value(), BIP44CoinType(), accountId);
|
||||
if (usk.has_value()) {
|
||||
return usk.value().first;
|
||||
} else {
|
||||
|
@ -4185,7 +4205,10 @@ bool CWallet::NewKeyPool()
|
|||
for (int i = 0; i < nKeys; i++)
|
||||
{
|
||||
int64_t nIndex = i+1;
|
||||
walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
|
||||
auto key = GenerateNewKey();
|
||||
if (!key.has_value())
|
||||
return false; // should have been caught by the `IsLocked` call.
|
||||
walletdb.WritePool(nIndex, CKeyPool(key.value()));
|
||||
setKeyPool.insert(nIndex);
|
||||
}
|
||||
LogPrintf("CWallet::NewKeyPool wrote %d new keys\n", nKeys);
|
||||
|
@ -4215,7 +4238,8 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
|
|||
int64_t nEnd = 1;
|
||||
if (!setKeyPool.empty())
|
||||
nEnd = *(--setKeyPool.end()) + 1;
|
||||
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
|
||||
auto newKey = GenerateNewKey();
|
||||
if (!newKey.has_value() || !walletdb.WritePool(nEnd, CKeyPool(newKey.value())))
|
||||
throw runtime_error("TopUpKeyPool(): writing generated key failed");
|
||||
setKeyPool.insert(nEnd);
|
||||
LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
|
||||
|
@ -4272,7 +4296,7 @@ void CWallet::ReturnKey(int64_t nIndex)
|
|||
LogPrintf("keypool return %d\n", nIndex);
|
||||
}
|
||||
|
||||
bool CWallet::GetKeyFromPool(CPubKey& result)
|
||||
std::optional<CPubKey> CWallet::GetKeyFromPool()
|
||||
{
|
||||
int64_t nIndex = 0;
|
||||
CKeyPool keypool;
|
||||
|
@ -4281,14 +4305,12 @@ bool CWallet::GetKeyFromPool(CPubKey& result)
|
|||
ReserveKeyFromKeyPool(nIndex, keypool);
|
||||
if (nIndex == -1)
|
||||
{
|
||||
if (IsLocked()) return false;
|
||||
result = GenerateNewKey();
|
||||
return true;
|
||||
if (IsLocked()) return std::nullopt;
|
||||
return GenerateNewKey();
|
||||
}
|
||||
KeepKey(nIndex);
|
||||
result = keypool.vchPubKey;
|
||||
return keypool.vchPubKey;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t CWallet::GetOldestKeyPoolTime()
|
||||
|
@ -4858,9 +4880,9 @@ bool CWallet::InitLoadWallet(const CChainParams& params, bool clearWitnessCaches
|
|||
if (fFirstRun)
|
||||
{
|
||||
// Create new keyUser and set as default key
|
||||
CPubKey newDefaultKey;
|
||||
if (walletInstance->GetKeyFromPool(newDefaultKey)) {
|
||||
walletInstance->SetDefaultKey(newDefaultKey);
|
||||
std::optional<CPubKey> newDefaultKey = walletInstance->GetKeyFromPool();
|
||||
if (newDefaultKey.has_value()) {
|
||||
walletInstance->SetDefaultKey(newDefaultKey.value());
|
||||
if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive"))
|
||||
return UIError(_("Cannot write default address") += "\n");
|
||||
}
|
||||
|
|
|
@ -993,7 +993,7 @@ public:
|
|||
* keystore implementation
|
||||
* Generate a new key
|
||||
*/
|
||||
CPubKey GenerateNewKey();
|
||||
std::optional<CPubKey> GenerateNewKey();
|
||||
//! Adds a key to the store, and saves it to disk.
|
||||
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
|
||||
//! Adds a key to the store, without saving it to disk (used by LoadWallet)
|
||||
|
@ -1161,7 +1161,7 @@ public:
|
|||
void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool);
|
||||
void KeepKey(int64_t nIndex);
|
||||
void ReturnKey(int64_t nIndex);
|
||||
bool GetKeyFromPool(CPubKey &key);
|
||||
std::optional<CPubKey> GetKeyFromPool();
|
||||
int64_t GetOldestKeyPoolTime();
|
||||
void GetAllReserveKeys(std::set<CKeyID>& setAddress) const;
|
||||
|
||||
|
@ -1318,7 +1318,7 @@ public:
|
|||
|
||||
/* Set the metadata for the mnemonic HD seed (chain child index counters) */
|
||||
void SetMnemonicHDChain(const CHDChain& chain, bool memonly);
|
||||
const std::optional<CHDChain> GetMnemonicHDChain() const { return mnemonicHDChain; }
|
||||
const std::optional<CHDChain>& GetMnemonicHDChain() const { return mnemonicHDChain; }
|
||||
|
||||
/* Set the metadata for the legacy HD seed (chain child index counters) */
|
||||
void SetLegacyHDChain(const CHDChain& chain, bool memonly);
|
||||
|
|
|
@ -49,6 +49,7 @@ private:
|
|||
uint256 seedFp;
|
||||
int64_t nCreateTime; // 0 means unknown
|
||||
uint32_t accountCounter;
|
||||
uint32_t legacyTKeyCounter;
|
||||
|
||||
CHDChain() { SetNull(); }
|
||||
|
||||
|
@ -58,12 +59,13 @@ private:
|
|||
seedFp.SetNull();
|
||||
nCreateTime = 0;
|
||||
accountCounter = 0;
|
||||
legacyTKeyCounter = 0;
|
||||
}
|
||||
public:
|
||||
static const int VERSION_HD_BASE = 1;
|
||||
static const int CURRENT_VERSION = VERSION_HD_BASE;
|
||||
|
||||
CHDChain(uint256 seedFpIn, int64_t nCreateTimeIn): nVersion(CHDChain::CURRENT_VERSION), seedFp(seedFpIn), nCreateTime(nCreateTimeIn), accountCounter(0) {}
|
||||
CHDChain(uint256 seedFpIn, int64_t nCreateTimeIn): nVersion(CHDChain::CURRENT_VERSION), seedFp(seedFpIn), nCreateTime(nCreateTimeIn), accountCounter(0), legacyTKeyCounter(0) {}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
|
@ -74,6 +76,7 @@ public:
|
|||
READWRITE(seedFp);
|
||||
READWRITE(nCreateTime);
|
||||
READWRITE(accountCounter);
|
||||
READWRITE(legacyTKeyCounter);
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
|
@ -91,8 +94,16 @@ public:
|
|||
return accountCounter;
|
||||
}
|
||||
|
||||
uint32_t IncrementAccountCounter() {
|
||||
return ++accountCounter;
|
||||
void IncrementAccountCounter() {
|
||||
accountCounter += 1;
|
||||
}
|
||||
|
||||
uint32_t GetLegacyTKeyCounter() {
|
||||
return legacyTKeyCounter;
|
||||
}
|
||||
|
||||
void IncrementLegacyTKeyCounter() {
|
||||
legacyTKeyCounter += 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ const libzcash::diversifier_index_t MAX_TRANSPARENT_CHILD_IDX(0x40000000);
|
|||
MnemonicSeed MnemonicSeed::Random(uint32_t bip44CoinType, Language language, size_t entropyLen)
|
||||
{
|
||||
assert(entropyLen >= 32);
|
||||
while (true) {
|
||||
while (true) { // loop until we find usable entropy
|
||||
std::vector<unsigned char> entropy(entropyLen, 0);
|
||||
GetRandBytes(entropy.data(), entropyLen);
|
||||
const char* phrase = zip339_entropy_to_phrase(language, entropy.data(), entropyLen);
|
||||
|
@ -33,9 +33,9 @@ MnemonicSeed MnemonicSeed::Random(uint32_t bip44CoinType, Language language, siz
|
|||
MnemonicSeed seed(language, mnemonic);
|
||||
|
||||
// Verify that the seed data is valid entropy for unified spending keys at
|
||||
// account 0 and account 0x7FFFFFFE
|
||||
if (libzcash::UnifiedSpendingKey::Derive(seed, bip44CoinType, 0).has_value() &&
|
||||
libzcash::DeriveZip32TransparentSpendingKey(seed, bip44CoinType, ZCASH_LEGACY_TRANSPARENT_ACCOUNT).has_value()) {
|
||||
// account 0 and at both the public & private chain levels for account 0x7FFFFFFE
|
||||
if (libzcash::UnifiedSpendingKey::ForAccount(seed, bip44CoinType, 0).has_value() &&
|
||||
libzcash::BIP32AccountChains::ForAccount(seed, bip44CoinType, ZCASH_LEGACY_TRANSPARENT_ACCOUNT).has_value()) {
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,87 @@ uint256 ovkForShieldingFromTaddr(HDSeed& seed) {
|
|||
|
||||
namespace libzcash {
|
||||
|
||||
//
|
||||
// Transparent
|
||||
//
|
||||
|
||||
std::optional<std::pair<CExtKey, CKeyMetadata>> DeriveZip32TransparentAccountKey(const HDSeed& seed, uint32_t bip44CoinType, uint32_t accountId) {
|
||||
auto rawSeed = seed.RawSeed();
|
||||
auto m = CExtKey::Master(rawSeed.data(), rawSeed.size());
|
||||
|
||||
// We use a fixed keypath scheme of m/32'/coin_type'/account'
|
||||
// Derive m/32'
|
||||
auto m_32h = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT);
|
||||
if (!m_32h.has_value()) return std::nullopt;
|
||||
|
||||
// Derive m/32'/coin_type'
|
||||
auto m_32h_cth = m_32h.value().Derive(bip44CoinType | ZIP32_HARDENED_KEY_LIMIT);
|
||||
if (!m_32h_cth.has_value()) return std::nullopt;
|
||||
|
||||
// Derive m/32'/coin_type'/account_id'
|
||||
auto result = m_32h_cth.value().Derive(accountId | ZIP32_HARDENED_KEY_LIMIT);
|
||||
if (!result.has_value()) return std::nullopt;
|
||||
|
||||
int64_t nCreationTime = GetTime();
|
||||
auto keyMeta = CKeyMetadata(nCreationTime);
|
||||
keyMeta.hdKeypath = "m/32'/" + std::to_string(bip44CoinType) + "'/" + std::to_string(accountId) + "'";
|
||||
keyMeta.seedFp = seed.Fingerprint();
|
||||
|
||||
return std::make_pair(result.value(), keyMeta);
|
||||
}
|
||||
|
||||
std::optional<BIP32AccountChains> BIP32AccountChains::ForAccount(
|
||||
const HDSeed& seed,
|
||||
uint32_t bip44CoinType,
|
||||
uint32_t accountId) {
|
||||
auto accountKeyOpt = DeriveZip32TransparentAccountKey(seed, bip44CoinType, accountId);
|
||||
if (!accountKeyOpt.has_value()) return std::nullopt;
|
||||
|
||||
auto accountKey = accountKeyOpt.value();
|
||||
auto external = accountKey.first.Derive(0);
|
||||
auto internal = accountKey.first.Derive(1);
|
||||
|
||||
if (!(external.has_value() && internal.has_value())) return std::nullopt;
|
||||
|
||||
return BIP32AccountChains(seed.Fingerprint(), bip44CoinType, accountId, external.value(), internal.value());
|
||||
}
|
||||
|
||||
std::optional<std::pair<CExtKey, CKeyMetadata>> BIP32AccountChains::DeriveExternal(uint32_t addrIndex) {
|
||||
auto childKey = external.Derive(addrIndex);
|
||||
if (!childKey.has_value()) return std::nullopt;
|
||||
|
||||
int64_t nCreationTime = GetTime();
|
||||
auto keyMeta = CKeyMetadata(nCreationTime);
|
||||
keyMeta.hdKeypath = "m/32'/"
|
||||
+ std::to_string(bip44CoinType) + "'/"
|
||||
+ std::to_string(accountId) + "'/"
|
||||
+ "0/"
|
||||
+ std::to_string(addrIndex);
|
||||
keyMeta.seedFp = seedFp;
|
||||
|
||||
return std::make_pair(childKey.value(), keyMeta);
|
||||
}
|
||||
|
||||
std::optional<std::pair<CExtKey, CKeyMetadata>> BIP32AccountChains::DeriveInternal(uint32_t addrIndex) {
|
||||
auto childKey = internal.Derive(addrIndex);
|
||||
if (!childKey.has_value()) return std::nullopt;
|
||||
|
||||
int64_t nCreationTime = GetTime();
|
||||
auto keyMeta = CKeyMetadata(nCreationTime);
|
||||
keyMeta.hdKeypath = "m/32'/"
|
||||
+ std::to_string(bip44CoinType) + "'/"
|
||||
+ std::to_string(accountId) + "'/"
|
||||
+ "1/"
|
||||
+ std::to_string(addrIndex);
|
||||
keyMeta.seedFp = seedFp;
|
||||
|
||||
return std::make_pair(childKey.value(), keyMeta);
|
||||
}
|
||||
|
||||
//
|
||||
// Sapling
|
||||
//
|
||||
|
||||
std::optional<SaplingExtendedFullViewingKey> SaplingExtendedFullViewingKey::Derive(uint32_t i) const
|
||||
{
|
||||
CDataStream ss_p(SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
@ -180,11 +261,11 @@ std::pair<SaplingExtendedSpendingKey, CKeyMetadata> SaplingExtendedSpendingKey::
|
|||
|
||||
// Create new metadata
|
||||
int64_t nCreationTime = GetTime();
|
||||
CKeyMetadata metadata(nCreationTime);
|
||||
metadata.hdKeypath = "m/32'/" + std::to_string(bip44CoinType) + "'/" + std::to_string(accountId) + "'";
|
||||
metadata.seedFp = seed.Fingerprint();
|
||||
CKeyMetadata keyMeta(nCreationTime);
|
||||
keyMeta.hdKeypath = "m/32'/" + std::to_string(bip44CoinType) + "'/" + std::to_string(accountId) + "'";
|
||||
keyMeta.seedFp = seed.Fingerprint();
|
||||
|
||||
return std::make_pair(xsk, metadata);
|
||||
return std::make_pair(xsk, keyMeta);
|
||||
}
|
||||
|
||||
SaplingExtendedFullViewingKey SaplingExtendedSpendingKey::ToXFVK() const
|
||||
|
@ -199,30 +280,17 @@ SaplingExtendedFullViewingKey SaplingExtendedSpendingKey::ToXFVK() const
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::optional<CExtKey> DeriveZip32TransparentSpendingKey(const HDSeed& seed, uint32_t bip44CoinType, uint32_t accountId) {
|
||||
auto rawSeed = seed.RawSeed();
|
||||
auto m = CExtKey::Master(rawSeed.data(), rawSeed.size());
|
||||
//
|
||||
// Unified
|
||||
//
|
||||
|
||||
// We use a fixed keypath scheme of m/32'/coin_type'/account'
|
||||
// Derive m/32'
|
||||
auto m_32h = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT);
|
||||
if (!m_32h.has_value()) return std::nullopt;
|
||||
|
||||
// Derive m/32'/coin_type'
|
||||
auto m_32h_cth = m_32h.value().Derive(bip44CoinType | ZIP32_HARDENED_KEY_LIMIT);
|
||||
if (!m_32h_cth.has_value()) return std::nullopt;
|
||||
|
||||
// Derive m/32'/coin_type'/account_id'
|
||||
return m_32h_cth.value().Derive(accountId | ZIP32_HARDENED_KEY_LIMIT);
|
||||
}
|
||||
|
||||
std::optional<std::pair<UnifiedSpendingKey, CKeyMetadata>> UnifiedSpendingKey::Derive(const HDSeed& seed, uint32_t bip44CoinType, uint32_t accountId) {
|
||||
std::optional<std::pair<UnifiedSpendingKey, CKeyMetadata>> UnifiedSpendingKey::ForAccount(const HDSeed& seed, uint32_t bip44CoinType, uint32_t accountId) {
|
||||
UnifiedSpendingKey usk;
|
||||
usk.accountId = accountId;
|
||||
|
||||
auto transparentKey = DeriveZip32TransparentSpendingKey(seed, bip44CoinType, accountId);
|
||||
auto transparentKey = DeriveZip32TransparentAccountKey(seed, bip44CoinType, accountId);
|
||||
if (!transparentKey.has_value()) return std::nullopt;
|
||||
usk.transparentKey = transparentKey.value();
|
||||
usk.transparentKey = transparentKey.value().first;
|
||||
|
||||
auto saplingKey = SaplingExtendedSpendingKey::ForAccount(seed, bip44CoinType, accountId);
|
||||
usk.saplingKey = saplingKey.first;
|
||||
|
@ -248,7 +316,9 @@ std::optional<ZcashdUnifiedAddress> UnifiedFullViewingKey::Address(diversifier_i
|
|||
ZcashdUnifiedAddress ua;
|
||||
|
||||
if (transparentKey.has_value()) {
|
||||
// ensure that the diversifier index is small enough for a t-addr
|
||||
if (MAX_TRANSPARENT_CHILD_IDX.less_than_le(j)) return std::nullopt;
|
||||
|
||||
CExtPubKey changeKey;
|
||||
if (!transparentKey.value().Derive(changeKey, 0)) {
|
||||
return std::nullopt;
|
||||
|
|
|
@ -351,7 +351,10 @@ private:
|
|||
|
||||
UnifiedSpendingKey() {}
|
||||
public:
|
||||
static std::optional<std::pair<UnifiedSpendingKey, CKeyMetadata>> Derive(const HDSeed& seed, uint32_t bip44CoinType, uint32_t accountId);
|
||||
static std::optional<std::pair<UnifiedSpendingKey, CKeyMetadata>> ForAccount(
|
||||
const HDSeed& seed,
|
||||
uint32_t bip44CoinType,
|
||||
uint32_t accountId);
|
||||
|
||||
const std::optional<CExtKey>& GetTransparentKey() const {
|
||||
return transparentKey;
|
||||
|
@ -366,7 +369,30 @@ public:
|
|||
|
||||
std::optional<unsigned long> ParseZip32KeypathAccount(const std::string& keyPath);
|
||||
|
||||
std::optional<CExtKey> DeriveZip32TransparentSpendingKey(const HDSeed& seed, uint32_t bip44CoinType, uint32_t accountId);
|
||||
std::optional<std::pair<CExtKey, CKeyMetadata>> DeriveZip32TransparentMasterKey(
|
||||
const HDSeed& seed,
|
||||
uint32_t bip44CoinType,
|
||||
uint32_t accountId);
|
||||
|
||||
class BIP32AccountChains {
|
||||
private:
|
||||
uint256 seedFp;
|
||||
uint32_t accountId;
|
||||
uint32_t bip44CoinType;
|
||||
CExtKey external;
|
||||
CExtKey internal;
|
||||
|
||||
BIP32AccountChains(uint256 seedFpIn, uint32_t bip44CoinTypeIn, uint32_t accountIdIn, CExtKey externalIn, CExtKey internalIn):
|
||||
seedFp(seedFpIn), accountId(accountIdIn), bip44CoinType(bip44CoinTypeIn), external(externalIn), internal(internalIn) {}
|
||||
public:
|
||||
static std::optional<BIP32AccountChains> ForAccount(
|
||||
const HDSeed& seed,
|
||||
uint32_t bip44CoinType,
|
||||
uint32_t accountId);
|
||||
|
||||
std::optional<std::pair<CExtKey, CKeyMetadata>> DeriveExternal(uint32_t addrIndex);
|
||||
std::optional<std::pair<CExtKey, CKeyMetadata>> DeriveInternal(uint32_t addrIndex);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -212,8 +212,7 @@ double benchmark_verify_equihash()
|
|||
double benchmark_large_tx(size_t nInputs)
|
||||
{
|
||||
// Create priv/pub key
|
||||
CKey priv;
|
||||
priv.MakeNewKey(false);
|
||||
CKey priv = CKey::TestOnlyRandomKey(true);
|
||||
auto pub = priv.GetPubKey();
|
||||
CBasicKeyStore tempKeystore;
|
||||
tempKeystore.AddKey(priv);
|
||||
|
|
Loading…
Reference in New Issue