X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fwallet.cpp;h=5976cb544d308e11d14329fda809382a33189d08;hb=989736e823e0841ce4ba4ac21554ba6426f3f4a4;hp=5595052f1002d31e3aead64a7984ade3d924cf2d;hpb=0dd25284c30dfdbfeff9a882dd801be8cacd0859;p=novacoin.git diff --git a/src/wallet.cpp b/src/wallet.cpp index 5595052..5976cb5 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -57,6 +57,28 @@ CPubKey CWallet::GenerateNewKey() return key.GetPubKey(); } +CMalleableKeyView CWallet::GenerateNewMalleableKey() +{ + RandAddSeedPerfmon(); + + // Compressed public keys were introduced in version 0.6.0 + SetMinVersion(FEATURE_MALLKEY); + + CMalleableKey mKey; + mKey.MakeNewKeys(); + const CMalleableKeyView &keyView(mKey); + + // Create new metadata + int64_t nCreationTime = GetTime(); + mapMalleableKeyMetadata[keyView] = CKeyMetadata(nCreationTime); + if (!nTimeFirstKey || nCreationTime < nTimeFirstKey) + nTimeFirstKey = nCreationTime; + + if (!AddMalleableKey(mKey)) + throw std::runtime_error("CWallet::GenerateNewMalleableKey() : AddMalleableKey failed"); + return CMalleableKeyView(mKey); +} + bool CWallet::AddKey(const CKey& key) { CPubKey pubkey = key.GetPubKey(); @@ -69,6 +91,38 @@ bool CWallet::AddKey(const CKey& key) return true; } +bool CWallet::AddMalleableKey(const CMalleableKey& mKey) +{ + CMalleableKeyView keyView = CMalleableKeyView(mKey); + CSecret vchSecretH = mKey.GetSecretH(); + if (!CCryptoKeyStore::AddMalleableKey(keyView, vchSecretH)) + return false; + if (!fFileBacked) + return true; + if (!IsCrypted()) + return CWalletDB(strWalletFile).WriteMalleableKey(keyView, vchSecretH, mapMalleableKeyMetadata[keyView]); + return true; +} + +bool CWallet::AddCryptedMalleableKey(const CMalleableKeyView& keyView, const std::vector &vchCryptedSecretH) +{ + if (!CCryptoKeyStore::AddCryptedMalleableKey(keyView, vchCryptedSecretH)) + return false; + + if (!fFileBacked) + return true; + + { + LOCK(cs_wallet); + if (pwalletdbEncryption) + return pwalletdbEncryption->WriteCryptedMalleableKey(keyView, vchCryptedSecretH, mapMalleableKeyMetadata[keyView]); + else + return CWalletDB(strWalletFile).WriteCryptedMalleableKey(keyView, vchCryptedSecretH, mapMalleableKeyMetadata[keyView]); + } + + return true; +} + bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector &vchCryptedSecret) { if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) @@ -101,6 +155,15 @@ bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta) return true; } +bool CWallet::LoadMalleableKeyMetadata(const CMalleableKeyView &keyView, const CKeyMetadata &metadata) +{ + if (metadata.nCreateTime && (!nTimeFirstKey || metadata.nCreateTime < nTimeFirstKey)) + nTimeFirstKey = metadata.nCreateTime; + + mapMalleableKeyMetadata[keyView] = metadata; + return true; +} + bool CWallet::AddCScript(const CScript& redeemScript) { if (!CCryptoKeyStore::AddCScript(redeemScript)) @@ -417,6 +480,16 @@ bool CWallet::DecryptWallet(const SecureString& strWalletPassphrase) mi++; } + MalleableKeyMap::const_iterator mi2 = mapMalleableKeys.begin(); + while (mi2 != mapMalleableKeys.end()) + { + const CSecret &vchSecretH = mi2->second; + const CMalleableKeyView &keyView = mi2->first; + pwalletdbDecryption->EraseCryptedMalleableKey(keyView); + pwalletdbDecryption->WriteMalleableKey(keyView, vchSecretH, mapMalleableKeyMetadata[keyView]); + mi2++; + } + // Erase master keys MasterKeyMap::const_iterator mk = mapMasterKeys.begin(); while (mk != mapMasterKeys.end()) @@ -1615,8 +1688,8 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CScript scriptChange; // coin control: send change to custom address - if (coinControl && !boost::get(&coinControl->destChange)) - scriptChange.SetDestination(coinControl->destChange); + if (coinControl && coinControl->destChange.IsValid()) + scriptChange.SetAddress(coinControl->destChange); // no coin control: send change to newly generated address else @@ -1688,7 +1761,7 @@ bool CWallet::CreateTransaction(CScript scriptPubKey, int64_t nValue, CWalletTx& void CWallet::GetStakeWeightFromValue(const int64_t& nTime, const int64_t& nValue, uint64_t& nWeight) { - int64_t nTimeWeight = GetWeight(nTime, (int64_t)GetTime()); + int64_t nTimeWeight = GetWeight(nTime, GetTime()); // If time weight is lower or equal to zero then weight is zero. if (nTimeWeight <= 0) @@ -1895,7 +1968,7 @@ bool CWallet::CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nGenerati if (setCoins.empty()) return false; - bool fMaxTimeWeight = false; + bool fDontSplitCoins = false; if (GetWeight((int64_t)wtx.nTime, (int64_t)nGenerationTime) == nStakeMaxAge) { // Only one output for old kernel inputs @@ -1938,16 +2011,29 @@ bool CWallet::CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nGenerati vwtxPrev.push_back(pcoin->first); } - fMaxTimeWeight = true; + fDontSplitCoins = true; } else { - // Split stake input if maximum weight isn't reached yet - txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); - txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); + int64_t nSplitThreshold = GetArg("-splitthreshold", nCombineThreshold); if (fDebug && GetBoolArg("-printcoinstake")) - printf("CreateCoinStake : maximum time weight isn't reached, splitting coinstake\n"); + printf("CreateCoinStake : nSplitThreshold=%" PRId64 "\n", nSplitThreshold); + + if (nCredit > nSplitThreshold) + { + // Split stake input if credit is lower than combine threshold and maximum weight isn't reached yet + txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); + txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); + + if (fDebug && GetBoolArg("-printcoinstake")) + printf("CreateCoinStake : splitting coinstake\n"); + } + else + { + txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); + fDontSplitCoins = true; + } } // Calculate coin age reward @@ -1961,7 +2047,7 @@ bool CWallet::CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nGenerati while (true) { // Set output amount - if (fMaxTimeWeight) + if (fDontSplitCoins) txNew.vout[1].nValue = nCredit - nMinFee; else { @@ -2035,7 +2121,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) AddToWallet(wtxNew); // Mark old coins as spent - set setCoins; BOOST_FOREACH(const CTxIn& txin, wtxNew.vin) { CWalletTx &coin = mapWallet[txin.prevout.hash]; @@ -2058,6 +2143,12 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, bool fAskFee) { + // Check amount + if (nValue <= 0) + return _("Invalid amount"); + if (nValue + nTransactionFee > GetBalance()) + return _("Insufficient funds"); + CReserveKey reservekey(this); int64_t nFeeRequired; @@ -2093,26 +2184,6 @@ string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNe return ""; } - - -string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nValue, CWalletTx& wtxNew, bool fAskFee) -{ - // Check amount - if (nValue <= 0) - return _("Invalid amount"); - if (nValue + nTransactionFee > GetBalance()) - return _("Insufficient funds"); - - // Parse Bitcoin address - CScript scriptPubKey; - scriptPubKey.SetDestination(address); - - return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee); -} - - - - DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { if (!fFileBacked) @@ -2670,55 +2741,50 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) } } -void CWallet::GetKeyBirthTimes(std::map &mapKeyBirth) const { - mapKeyBirth.clear(); +void CWallet::GetAddresses(std::map &mapAddresses) const { + mapAddresses.clear(); // get birth times for keys with metadata - for (std::map::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++) - if (it->second.nCreateTime) - mapKeyBirth[it->first] = it->second.nCreateTime; - - // map in which we'll infer heights of other keys - CBlockIndex *pindexMax = FindBlockByHeight(std::max(0, nBestHeight - 144)); // the tip can be reorganised; use a 144-block safety margin - std::map mapKeyFirstBlock; - std::set setKeys; - GetKeys(setKeys); - BOOST_FOREACH(const CKeyID &keyid, setKeys) { - if (mapKeyBirth.count(keyid) == 0) - mapKeyFirstBlock[keyid] = pindexMax; - } - setKeys.clear(); - - // if there are no such keys, we're done - if (mapKeyFirstBlock.empty()) - return; + for (std::map::const_iterator it = mapMalleableKeyMetadata.begin(); it != mapMalleableKeyMetadata.end(); it++) { + CBitcoinAddress addr(it->first.GetMalleablePubKey()); + mapAddresses[addr] = it->second.nCreateTime ? it->second.nCreateTime : 0; + } + + for (std::map::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++) { + CBitcoinAddress addr(it->first); + mapAddresses[addr] = it->second.nCreateTime ? it->second.nCreateTime : 0; + } - // find first block that affects those keys, if there are any left - std::vector vAffected; for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) { // iterate over all wallet transactions... const CWalletTx &wtx = (*it).second; - std::map::const_iterator blit = mapBlockIndex.find(wtx.hashBlock); - if (blit != mapBlockIndex.end() && blit->second->IsInMainChain()) { - // ... which are already in a block - int nHeight = blit->second->nHeight; - BOOST_FOREACH(const CTxOut &txout, wtx.vout) { - // iterate over all their outputs - ::ExtractAffectedKeys(*this, txout.scriptPubKey, vAffected); - BOOST_FOREACH(const CKeyID &keyid, vAffected) { - // ... and all their affected keys - std::map::iterator rit = mapKeyFirstBlock.find(keyid); - if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight) - rit->second = blit->second; + if (wtx.hashBlock == 0) + continue; // skip unconfirmed transactions + + for(std::vector::const_iterator it2 = wtx.vout.begin(); it2 != wtx.vout.end(); it2++) { + const CTxOut &out = (*it2); + // iterate over all their outputs + CBitcoinAddress addressRet; + if (const_cast(this)->ExtractAddress(out.scriptPubKey, addressRet)) { + if (mapAddresses.find(addressRet) != mapAddresses.end() && (mapAddresses[addressRet] == 0 || mapAddresses[addressRet] > wtx.nTime)) + mapAddresses[addressRet] = wtx.nTime; + } + else { + // multisig output affects more than one key + std::vector vAffected; + ::ExtractAffectedKeys(*this, out.scriptPubKey, vAffected); + + for(std::vector::const_iterator it3 = vAffected.begin(); it3 != vAffected.end(); it3++) { + CBitcoinAddress addrAffected(*it3); + + if (mapAddresses.find(addrAffected) != mapAddresses.end() && (mapAddresses[addrAffected] == 0 || mapAddresses[addrAffected] > wtx.nTime)) + mapAddresses[addrAffected] = wtx.nTime; } vAffected.clear(); } } - } - // Extract block timestamps for those keys - for (std::map::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++) - mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off + } } void CWallet::ClearOrphans() @@ -2738,3 +2804,39 @@ void CWallet::ClearOrphans() for(list::const_iterator it = orphans.begin(); it != orphans.end(); ++it) EraseFromWallet(*it); } + +bool CWallet::ExtractAddress(const CScript& scriptPubKey, CBitcoinAddress& addressRet) +{ + vector vSolutions; + txnouttype whichType; + if (!Solver(scriptPubKey, whichType, vSolutions)) + return false; + + if (whichType == TX_PUBKEY) + { + addressRet = CBitcoinAddress(CPubKey(vSolutions[0]).GetID()); + return true; + } + if (whichType == TX_PUBKEY_DROP) + { + // Pay-to-Pubkey-R + CMalleableKeyView view; + if (!CheckOwnership(CPubKey(vSolutions[0]), CPubKey(vSolutions[1]), view)) + return false; + + addressRet = CBitcoinAddress(view.GetMalleablePubKey()); + return true; + } + else if (whichType == TX_PUBKEYHASH) + { + addressRet = CBitcoinAddress(CKeyID(uint160(vSolutions[0]))); + return true; + } + else if (whichType == TX_SCRIPTHASH) + { + addressRet = CBitcoinAddress(CScriptID(uint160(vSolutions[0]))); + return true; + } + // Multisig txns have more than one address... + return false; +}