// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <regex>
+
#include "txdb.h"
#include "wallet.h"
#include "walletdb.h"
#include "base58.h"
#include "kernel.h"
#include "coincontrol.h"
-#include <boost/algorithm/string/replace.hpp>
#include <openssl/bio.h>
#include "main.h"
// mapWallet
//
+CWallet::CWallet()
+{
+ SetNull();
+}
+
+CWallet::CWallet(std::string strWalletFileIn)
+{
+ SetNull();
+
+ strWalletFile = strWalletFileIn;
+ fFileBacked = true;
+}
+
+void CWallet::SetNull()
+{
+ nWalletVersion = FEATURE_BASE;
+ nWalletMaxVersion = FEATURE_BASE;
+ fFileBacked = false;
+ nMasterKeyMaxID = 0;
+ pwalletdbEncryption = NULL;
+ pwalletdbDecryption = NULL;
+ nNextResend = 0;
+ nLastResend = 0;
+ nOrderPosNext = 0;
+ nKernelsTried = 0;
+ nCoinDaysTried = 0;
+ nTimeFirstKey = 0;
+}
+
struct CompareValueOnly
{
bool operator()(const pair<int64_t, pair<const CWalletTx*, unsigned int> >& t1,
return true;
}
+bool CWallet::LoadMinVersion(int nVersion)
+{
+ nWalletVersion = nVersion;
+ nWalletMaxVersion = max(nWalletMaxVersion, nVersion);
+ return true;
+}
+
bool CWallet::AddCScript(const CScript& redeemScript)
{
if (!CCryptoKeyStore::AddCScript(redeemScript))
// notify an external script when a wallet transaction comes in or is updated
auto strCmd = GetArg("-walletnotify", "");
- if ( !strCmd.empty())
- {
- boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
- boost::thread t(runCommand, strCmd); // thread runs free
- }
+ if (!strCmd.empty())
+ // thread runs free
+ boost::thread t(runCommand, regex_replace(strCmd, static_cast<regex>("%s"), wtxIn.GetHash().GetHex()));
}
return true;
return MINE_NO;
}
+
+CWalletTx::CWalletTx()
+{
+ Init(NULL);
+}
+
+CWalletTx::CWalletTx(const CWallet* pwalletIn)
+{
+ Init(pwalletIn);
+}
+
+CWalletTx::CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn)
+{
+ Init(pwalletIn);
+}
+
+CWalletTx::CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn)
+{
+ Init(pwalletIn);
+}
+
+void CWalletTx::Init(const CWallet* pwalletIn)
+{
+ pwallet = pwalletIn;
+ vtxPrev.clear();
+ mapValue.clear();
+ vOrderForm.clear();
+ fTimeReceivedIsTxTime = false;
+ nTimeReceived = 0;
+ nTimeSmart = 0;
+ fFromMe = false;
+ strFromAccount.clear();
+ vfSpent.clear();
+ fDebitCached = false;
+ fWatchDebitCached = false;
+ fCreditCached = false;
+ fWatchCreditCached = false;
+ fAvailableCreditCached = false;
+ fAvailableWatchCreditCached = false;
+ fImmatureCreditCached = false;
+ fImmatureWatchCreditCached = false;
+ fChangeCached = false;
+ nDebitCached = 0;
+ nWatchDebitCached = 0;
+ nCreditCached = 0;
+ nWatchCreditCached = 0;
+ nAvailableCreditCached = 0;
+ nAvailableWatchCreditCached = 0;
+ nImmatureCreditCached = 0;
+ nImmatureWatchCreditCached = 0;
+ nChangeCached = 0;
+ nOrderPos = -1;
+}
+
// marks certain txout's as spent
// returns true if any update took place
bool CWalletTx::UpdateSpent(const vector<char>& vfNewSpent)
int64_t CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const
{
- int64_t nDebit = 0;
+ CBigNum nDebit = 0;
for(const CTxIn& txin : tx.vin)
{
- nDebit += GetDebit(txin, filter);
- if (!MoneyRange(nDebit))
+ auto nValue = GetDebit(txin, filter);
+ nDebit += nValue;
+ if (!MoneyRange(nValue) || !MoneyRange(nDebit))
throw runtime_error("CWallet::GetDebit() : value out of range");
}
- return nDebit;
+ return nDebit.getint64();
}
int64_t CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const
{
- int64_t nCredit = 0;
+ CBigNum nCredit = 0;
for(const CTxOut& txout : tx.vout)
{
- nCredit += GetCredit(txout, filter);
- if (!MoneyRange(nCredit))
+ auto nValue = GetCredit(txout, filter);
+ nCredit += nValue;
+ if (!MoneyRange(nValue) || !MoneyRange(nCredit))
throw runtime_error("CWallet::GetCredit() : value out of range");
}
- return nCredit;
+ return nCredit.getint64();
}
int64_t CWallet::GetChange(const CTransaction& tx) const
{
- int64_t nChange = 0;
+ CBigNum nChange = 0;
for(const CTxOut& txout : tx.vout)
{
- nChange += GetChange(txout);
- if (!MoneyRange(nChange))
+ int64_t nValue = GetChange(txout);
+ nChange += nValue;
+ if (!MoneyRange(nValue) || !MoneyRange(nChange))
throw runtime_error("CWallet::GetChange() : value out of range");
}
- return nChange;
+ return nChange.getint64();
}
int64_t CWalletTx::GetTxTime() const
return nAvailableCreditCached;
}
- int64_t nCredit = 0;
- for (unsigned int i = 0; i < vout.size(); i++)
+ CBigNum nCredit = 0;
+ for (uint32_t i = 0; i < vout.size(); i++)
{
if (!IsSpent(i))
{
const CTxOut &txout = vout[i];
- nCredit += pwallet->GetCredit(txout, MINE_SPENDABLE);
- if (!MoneyRange(nCredit))
+ int64_t nValue = pwallet->GetCredit(txout, MINE_SPENDABLE);
+ nCredit += nValue;
+ if (!MoneyRange(nValue) || !MoneyRange(nCredit))
throw runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
}
}
- nAvailableCreditCached = nCredit;
+ nAvailableCreditCached = nCredit.getint64();
fAvailableCreditCached = true;
- return nCredit;
+ return nCredit.getint64();
}
int64_t CWalletTx::GetAvailableWatchCredit(bool fUseCache) const
return nAvailableWatchCreditCached;
}
- int64_t nCredit = 0;
+ CBigNum nCredit = 0;
for (unsigned int i = 0; i < vout.size(); i++)
{
if (!IsSpent(i))
{
const CTxOut &txout = vout[i];
- nCredit += pwallet->GetCredit(txout, MINE_WATCH_ONLY);
- if (!MoneyRange(nCredit))
+ int64_t nValue = pwallet->GetCredit(txout, MINE_WATCH_ONLY);
+ nCredit += nValue;
+ if (!MoneyRange(nValue) || !MoneyRange(nCredit))
throw runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
}
}
- nAvailableWatchCreditCached = nCredit;
+ nAvailableWatchCreditCached = nCredit.getint64();
fAvailableWatchCreditCached = true;
- return nCredit;
+ return nCredit.getint64();
}
int64_t CWalletTx::GetChange() const
wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
// Sign
- int nIn = 0;
+ uint32_t nIn = 0;
for(const auto& coin : setCoins)
if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
return false;
if (wtxNew.vout[0].nValue <= 0)
return false;
- for (unsigned int i = 0; i < wtxNew.vin.size(); i++) {
+ for (uint32_t i = 0; i < wtxNew.vin.size(); i++) {
const CWalletTx *txin = vwtxPrev[i];
// Sign all scripts again
}
// Sign
- int nIn = 0;
+ uint32_t nIn = 0;
for(const CWalletTx* pcoin : vwtxPrev)
{
if (!SignSignature(*this, *pcoin, txNew, nIn++))
}
// Limit size
- unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
+ auto nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
return error("CreateCoinStake : exceeded coinstake size limit\n");
{
// Check amount
if (nValue <= 0)
- return _("Invalid amount");
+ return "Invalid amount";
if (nValue + nTransactionFee > GetBalance())
- return _("Insufficient funds");
+ return "Insufficient funds";
CReserveKey reservekey(this);
int64_t nFeeRequired;
if (IsLocked())
{
- string strError = _("Error: Wallet locked, unable to create transaction ");
+ string strError("Error: Wallet locked, unable to create transaction ");
printf("SendMoney() : %s", strError.c_str());
return strError;
}
if (fWalletUnlockMintOnly)
{
- string strError = _("Error: Wallet unlocked for block minting only, unable to create transaction.");
+ string strError("Error: Wallet unlocked for block minting only, unable to create transaction.");
printf("SendMoney() : %s", strError.c_str());
return strError;
}
return "ABORTED";
if (!CommitTransaction(wtxNew, reservekey))
- return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
+ return "Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.";
return "";
}
printf("\n");
}
+void CWallet::Inventory(const uint256 &hash)
+{
+ {
+ LOCK(cs_wallet);
+ auto mi = mapRequestCount.find(hash);
+ if (mi != mapRequestCount.end())
+ (*mi).second++;
+ }
+}
+
bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
{
{
{
CWalletTx *pcoin = &walletEntry.second;
- if (pcoin->vin.size() > 0 && IsMine(pcoin->vin[0]))
+ if (pcoin->vin.size() > 0)
{
+ bool any_mine = false;
// group all input addresses with each other
for(CTxIn txin : pcoin->vin)
{
CBitcoinAddress address;
+ if(!IsMine(txin)) // If this input isn't mine, ignore it
+ continue;
if(!ExtractAddress(*this, mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address))
continue;
grouping.insert(address);
+ any_mine = true;
}
// group change with input addresses
+ if (any_mine)
+ {
for(CTxOut txout : pcoin->vout)
if (IsChange(txout))
{
- auto tx = mapWallet[pcoin->vin[0].prevout.hash];
CBitcoinAddress txoutAddr;
if(!ExtractAddress(*this, txout.scriptPubKey, txoutAddr))
continue;
grouping.insert(txoutAddr);
}
- groupings.insert(grouping);
- grouping.clear();
+ }
+ if (!grouping.empty())
+ {
+ groupings.insert(grouping);
+ grouping.clear();
+ }
}
// group lone addrs by themselves