X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fwallet.cpp;h=88d661e1fb39de14f0d5bc560a0651f0aaee1150;hb=24c742a46d44c8f10a2a94d1bd5227e8a0ae30ed;hp=3ad87cbf52a13fe7921df25e5aae7ff27c0c3c08;hpb=77a43545b4491b9703d803765da9059d2bdd5aaa;p=novacoin.git diff --git a/src/wallet.cpp b/src/wallet.cpp index 3ad87cb..88d661e 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -62,7 +62,6 @@ CPubKey CWallet::GenerateNewKey() bool CWallet::AddKey(const CKey& key) { CPubKey pubkey = key.GetPubKey(); - if (!CCryptoKeyStore::AddKey(key)) return false; if (!fFileBacked) @@ -76,6 +75,13 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector MAX_SCRIPT_ELEMENT_SIZE) + { + std::string strAddr = CBitcoinAddress(redeemScript.GetID()).ToString(); + printf("LoadCScript() : Warning: This wallet contains a redeemScript of size %" PRIszu " which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", + redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr.c_str()); + return true; + } + + return CCryptoKeyStore::AddCScript(redeemScript); +} + + bool CWallet::AddWatchOnly(const CScript &dest) { if (!CCryptoKeyStore::AddWatchOnly(dest)) return false; nTimeFirstKey = 1; // No birthday information for watch-only keys. + NotifyWatchonlyChanged(true); if (!fFileBacked) return true; return CWalletDB(strWalletFile).WriteWatchOnly(dest); } +bool CWallet::RemoveWatchOnly(const CScript &dest) +{ + LOCK(cs_wallet); + if (!CCryptoKeyStore::RemoveWatchOnly(dest)) + return false; + if (!HaveWatchOnly()) + NotifyWatchonlyChanged(false); + if (fFileBacked) + if (!CWalletDB(strWalletFile).EraseWatchOnly(dest)) + return false; + + return true; +} + bool CWallet::LoadWatchOnly(const CScript &dest) { return CCryptoKeyStore::AddWatchOnly(dest); @@ -229,13 +267,6 @@ bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, if (fFileBacked) { CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile); - if (nWalletVersion >= 40000) - { - // Versions prior to 0.4.0 did not support the "minversion" record. - // Use a CCorruptAddress to make them crash instead. - CCorruptAddress corruptAddress; - pwalletdb->WriteSetting("addrIncoming", corruptAddress); - } if (nWalletVersion > 40000) pwalletdb->WriteMinVersion(nWalletVersion); if (!pwalletdbIn) @@ -267,7 +298,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE); RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); - CMasterKey kMasterKey(nDerivationMethodIndex); + CMasterKey kMasterKey; RandAddSeedPerfmon(); kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE); @@ -337,6 +368,77 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) return true; } +bool CWallet::DecryptWallet(const SecureString& strWalletPassphrase) +{ + if (!IsCrypted()) + return false; + + CCrypter crypter; + CKeyingMaterial vMasterKey; + + { + LOCK(cs_wallet); + BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys) + { + if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) + return false; + if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) + return false; + if (!CCryptoKeyStore::Unlock(vMasterKey)) + return false; + } + + if (fFileBacked) + { + pwalletdbDecryption = new CWalletDB(strWalletFile); + if (!pwalletdbDecryption->TxnBegin()) + return false; + } + + if (!DecryptKeys(vMasterKey)) + { + if (fFileBacked) + pwalletdbDecryption->TxnAbort(); + exit(1); //We now probably have half of our keys decrypted in memory, and half not...die and let the user reload their encrypted wallet. + } + + if (fFileBacked) + { + // Overwrite crypted keys + KeyMap::const_iterator mi = mapKeys.begin(); + while (mi != mapKeys.end()) + { + CKey key; + key.SetSecret((*mi).second.first, (*mi).second.second); + pwalletdbDecryption->EraseCryptedKey(key.GetPubKey()); + pwalletdbDecryption->WriteKey(key.GetPubKey(), key.GetPrivKey(), mapKeyMetadata[(*mi).first]); + mi++; + } + + // Erase master keys + MasterKeyMap::const_iterator mk = mapMasterKeys.begin(); + while (mk != mapMasterKeys.end()) + { + pwalletdbDecryption->EraseMasterKey((*mk).first); + mk++; + } + + if (!pwalletdbDecryption->TxnCommit()) + exit(1); //We now have keys decrypted in memory, but no on disk...die to avoid confusion and let the user reload their encrypted wallet. + + delete pwalletdbDecryption; + pwalletdbDecryption = NULL; + } + + // Need to completely rewrite the wallet file; if we don't, bdb might keep + // encrypted private keys in the database file which can be a reason of consistency issues. + CDB::Rewrite(strWalletFile); + } + NotifyStatusChanged(this); + + return true; +} + int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) { int64_t nRet = nOrderPosNext++; @@ -389,7 +491,7 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx, bool fBlock) printf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString().c_str()); else if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n])) { - printf("WalletUpdateSpent found spent coin %snvc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); + printf("WalletUpdateSpent found spent coin %snvc %s\n", FormatMoney(wtx.GetCredit(MINE_ALL)).c_str(), wtx.GetHash().ToString().c_str()); wtx.MarkSpent(txin.prevout.n); wtx.WriteToDisk(); NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED); @@ -926,7 +1028,7 @@ void CWallet::ReacceptWalletTransactions() } if (fUpdated) { - printf("ReacceptWalletTransactions found spent coin %snvc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); + printf("ReacceptWalletTransactions found spent coin %snvc %s\n", FormatMoney(wtx.GetCredit(MINE_ALL)).c_str(), wtx.GetHash().ToString().c_str()); wtx.MarkDirty(); wtx.WriteToDisk(); } @@ -979,7 +1081,7 @@ void CWallet::ResendWalletTransactions() { // Do this infrequently and randomly to avoid giving away // that these are our transactions. - static int64_t nNextTime; + static int64_t nNextTime = GetRand(GetTime() + 30 * 60); if (GetTime() < nNextTime) return; bool fFirst = (nNextTime == 0); @@ -988,7 +1090,7 @@ void CWallet::ResendWalletTransactions() return; // Only do it if there's been a new block since last time - static int64_t nLastTime; + static int64_t nLastTime = 0; if (nTimeBestReceived < nLastTime) return; nLastTime = GetTime(); @@ -1503,26 +1605,6 @@ bool CWallet::CreateTransaction(const vector >& vecSend, } int64_t nChange = nValueIn - nValue - nFeeRet; - // if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE - // or until nChange becomes zero - // NOTE: this depends on the exact behaviour of GetMinFee - if (wtxNew.nTime < FEE_SWITCH_TIME && !fTestNet) - { - if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT) - { - int64_t nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet); - nChange -= nMoveToFee; - nFeeRet += nMoveToFee; - } - - // sub-cent change is moved to fee - if (nChange > 0 && nChange < CENT) - { - nFeeRet += nChange; - nChange = 0; - } - } - if (nChange > 0) { // Fill a vout to ourself @@ -1574,15 +1656,8 @@ bool CWallet::CreateTransaction(const vector >& vecSend, dPriority /= nBytes; // Check that enough fee is included - int64_t nPayFee = nTransactionFee * (1 + (int64_t)nBytes / 1000); bool fAllowFree = CTransaction::AllowFree(dPriority); - - // Disable free transactions until 1 July 2014 - if (!fTestNet && wtxNew.nTime < FEE_SWITCH_TIME) - { - fAllowFree = false; - } - + int64_t nPayFee = nTransactionFee * (1 + (int64_t)nBytes / 1000); int64_t nMinFee = wtxNew.GetMinFee(1, fAllowFree, GMF_SEND, nBytes); if (nFeeRet < max(nPayFee, nMinFee)) @@ -1782,7 +1857,7 @@ bool CWallet::MergeCoins(const int64_t& nAmount, const int64_t& nMinValue, const } -bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, CTransaction& txNew, CKey& key) +bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, uint32_t nSearchInterval, CTransaction& txNew, CKey& key) { // The following combine threshold is important to security // Should not be adjusted if you don't understand the consequences @@ -1844,7 +1919,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int continue; // Add meta record - // txid => ((txindex, (tx, vout.n)), (block, modifier)) + // (txid, vout.n) => ((txindex, (tx, vout.n)), (block, modifier)) mapMeta[make_pair(pcoin->first->GetHash(), pcoin->second)] = make_pair(make_pair(txindex, *pcoin), make_pair(block, nStakeModifier)); if (fDebug) @@ -1864,18 +1939,11 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int int64_t nCredit = 0; CScript scriptPubKeyKernel; - KernelSearchSettings settings; - settings.nBits = nBits; - settings.nTime = txNew.nTime; - settings.nOffset = 0; - settings.nLimit = mapMeta.size(); - settings.nSearchInterval = nSearchInterval; - unsigned int nTimeTx, nBlockTime; COutPoint prevoutStake; CoinsSet::value_type kernelcoin; - if (ScanForStakeKernelHash(mapMeta, settings, kernelcoin, nTimeTx, nBlockTime, nKernelsTried, nCoinDaysTried)) + if (ScanForStakeKernelHash(mapMeta, nBits, txNew.nTime, nSearchInterval, kernelcoin, nTimeTx, nBlockTime, nKernelsTried, nCoinDaysTried)) { // Found a kernel if (fDebug && GetBoolArg("-printcoinstake")) @@ -2041,9 +2109,24 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) { { - LOCK2(cs_main, cs_wallet); printf("CommitTransaction:\n%s", wtxNew.ToString().c_str()); + + // Track how many getdata requests our transaction gets + mapRequestCount[wtxNew.GetHash()] = 0; + + // Try to broadcast before saving + if (!wtxNew.AcceptToMemoryPool()) + { + // This must not fail. The transaction has already been signed. + printf("CommitTransaction() : Error: Transaction not valid"); + return false; + } + + wtxNew.RelayWalletTransaction(); + { + LOCK2(cs_main, cs_wallet); + // This is only to keep the database open to defeat the auto-flush for the // duration of this scope. This is the only place where this optimization // maybe makes sense; please don't do it anywhere else. @@ -2071,18 +2154,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) if (fFileBacked) delete pwalletdb; } - - // Track how many getdata requests our transaction gets - mapRequestCount[wtxNew.GetHash()] = 0; - - // Broadcast - if (!wtxNew.AcceptToMemoryPool()) - { - // This must not fail. The transaction has already been signed and recorded. - printf("CommitTransaction() : Error: Transaction not valid"); - return false; - } - wtxNew.RelayWalletTransaction(); } return true; } @@ -2172,6 +2243,28 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) return DB_LOAD_OK; } +DBErrors CWallet::ZapWalletTx() +{ + if (!fFileBacked) + return DB_LOAD_OK; + DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this); + if (nZapWalletTxRet == DB_NEED_REWRITE) + { + if (CDB::Rewrite(strWalletFile, "\x04pool")) + { + LOCK(cs_wallet); + setKeyPool.clear(); + // Note: can't top-up keypool here, because wallet is locked. + // User will be prompted to unlock wallet the next operation + // the requires a new key. + } + } + + if (nZapWalletTxRet != DB_LOAD_OK) + return nZapWalletTxRet; + + return DB_LOAD_OK; +} bool CWallet::SetAddressBookName(const CTxDestination& address, const string& strName) { @@ -2197,17 +2290,16 @@ void CWallet::PrintWallet(const CBlock& block) { { LOCK(cs_wallet); - if (block.IsProofOfWork() && mapWallet.count(block.vtx[0].GetHash())) - { - CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; - printf(" mine: %d %d %" PRId64 "", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); - } if (block.IsProofOfStake() && mapWallet.count(block.vtx[1].GetHash())) { CWalletTx& wtx = mapWallet[block.vtx[1].GetHash()]; - printf(" stake: %d %d %" PRId64 "", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); - } - + printf(" PoS: %d %d %" PRId64 "", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit(MINE_ALL)); + } + else if (mapWallet.count(block.vtx[0].GetHash())) + { + CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; + printf(" PoW: %d %d %" PRId64 "", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit(MINE_ALL)); + } } printf("\n"); } @@ -2249,7 +2341,7 @@ bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut) // Mark old keypool keys as used, // and generate all new keys // -bool CWallet::NewKeyPool() +bool CWallet::NewKeyPool(unsigned int nSize) { { LOCK(cs_wallet); @@ -2261,14 +2353,19 @@ bool CWallet::NewKeyPool() if (IsLocked()) return false; - int64_t nKeys = max(GetArg("-keypool", 100), (int64_t)0); - for (int i = 0; i < nKeys; i++) + uint64_t nKeys; + if (nSize > 0) + nKeys = nSize; + else + nKeys = max(GetArg("-keypool", 100), 0); + + for (uint64_t i = 0; i < nKeys; i++) { - int64_t nIndex = i+1; + uint64_t nIndex = i+1; walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey())); setKeyPool.insert(nIndex); } - printf("CWallet::NewKeyPool wrote %" PRId64 " new keys\n", nKeys); + printf("CWallet::NewKeyPool wrote %" PRIu64 " new keys\n", nKeys); } return true; } @@ -2284,21 +2381,21 @@ bool CWallet::TopUpKeyPool(unsigned int nSize) CWalletDB walletdb(strWalletFile); // Top up key pool - unsigned int nTargetSize; + uint64_t nTargetSize; if (nSize > 0) nTargetSize = nSize; else - nTargetSize = max(GetArg("-keypool", 100), 0LL); + nTargetSize = max(GetArg("-keypool", 100), 0); while (setKeyPool.size() < (nTargetSize + 1)) { - int64_t nEnd = 1; + uint64_t nEnd = 1; if (!setKeyPool.empty()) nEnd = *(--setKeyPool.end()) + 1; if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) throw runtime_error("TopUpKeyPool() : writing generated key failed"); setKeyPool.insert(nEnd); - printf("keypool added key %" PRId64 ", size=%" PRIszu "\n", nEnd, setKeyPool.size()); + printf("keypool added key %" PRIu64 ", size=%" PRIszu "\n", nEnd, setKeyPool.size()); } } return true;