mirror of
https://github.com/kvazar-network/kevacoin.git
synced 2025-01-17 18:40:09 +00:00
Merge pull request #3671 from gavinandresen/txn_conflicts
Report transaction conflicts, and tentative account balance fix
This commit is contained in:
commit
085c62149a
@ -88,8 +88,10 @@ B2ADDRESS=$( $CLI $B2ARGS getnewaddress )
|
|||||||
# Have B1 create two transactions; second will
|
# Have B1 create two transactions; second will
|
||||||
# spend change from first, since B1 starts with only a single
|
# spend change from first, since B1 starts with only a single
|
||||||
# 50 bitcoin output:
|
# 50 bitcoin output:
|
||||||
TXID1=$( $CLI $B1ARGS sendtoaddress $B2ADDRESS 1.0 )
|
$CLI $B1ARGS move "" "foo" 10.0
|
||||||
TXID2=$( $CLI $B1ARGS sendtoaddress $B2ADDRESS 2.0 )
|
$CLI $B1ARGS move "" "bar" 10.0
|
||||||
|
TXID1=$( $CLI $B1ARGS sendfrom foo $B2ADDRESS 1.0 0)
|
||||||
|
TXID2=$( $CLI $B1ARGS sendfrom bar $B2ADDRESS 2.0 0)
|
||||||
|
|
||||||
# Mutate TXID1 and add it to B2's memory pool:
|
# Mutate TXID1 and add it to B2's memory pool:
|
||||||
RAWTX1=$( $CLI $B1ARGS getrawtransaction $TXID1 )
|
RAWTX1=$( $CLI $B1ARGS getrawtransaction $TXID1 )
|
||||||
@ -122,7 +124,9 @@ echo "Mutated: " $MUTATEDTXID
|
|||||||
$CLI $B2ARGS addnode 127.0.0.1:11000 onetry
|
$CLI $B2ARGS addnode 127.0.0.1:11000 onetry
|
||||||
WaitPeers "$B1ARGS" 1
|
WaitPeers "$B1ARGS" 1
|
||||||
|
|
||||||
$CLI $B2ARGS setgenerate true 1
|
$CLI $B2ARGS setgenerate true 3
|
||||||
|
WaitBlocks
|
||||||
|
$CLI $B1ARGS setgenerate true 3
|
||||||
WaitBlocks
|
WaitBlocks
|
||||||
|
|
||||||
$CLI $B2ARGS stop > /dev/null 2>&1
|
$CLI $B2ARGS stop > /dev/null 2>&1
|
||||||
|
@ -51,7 +51,12 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
|
|||||||
entry.push_back(Pair("blockindex", wtx.nIndex));
|
entry.push_back(Pair("blockindex", wtx.nIndex));
|
||||||
entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
|
entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime)));
|
||||||
}
|
}
|
||||||
entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
|
uint256 hash = wtx.GetHash();
|
||||||
|
entry.push_back(Pair("txid", hash.GetHex()));
|
||||||
|
Array conflicts;
|
||||||
|
BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
|
||||||
|
conflicts.push_back(conflict.GetHex());
|
||||||
|
entry.push_back(Pair("walletconflicts", conflicts));
|
||||||
entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
|
entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
|
||||||
entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived));
|
entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived));
|
||||||
BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
|
BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
|
||||||
@ -621,7 +626,7 @@ Value getbalance(const Array& params, bool fHelp)
|
|||||||
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
|
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
|
||||||
{
|
{
|
||||||
const CWalletTx& wtx = (*it).second;
|
const CWalletTx& wtx = (*it).second;
|
||||||
if (!wtx.IsTrusted())
|
if (!wtx.IsTrusted() || wtx.GetBlocksToMaturity() > 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int64_t allFee;
|
int64_t allFee;
|
||||||
@ -1325,6 +1330,8 @@ Value listaccounts(const Array& params, bool fHelp)
|
|||||||
string strSentAccount;
|
string strSentAccount;
|
||||||
list<pair<CTxDestination, int64_t> > listReceived;
|
list<pair<CTxDestination, int64_t> > listReceived;
|
||||||
list<pair<CTxDestination, int64_t> > listSent;
|
list<pair<CTxDestination, int64_t> > listSent;
|
||||||
|
if (wtx.GetBlocksToMaturity() > 0)
|
||||||
|
continue;
|
||||||
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
|
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
|
||||||
mapAccountBalances[strSentAccount] -= nFee;
|
mapAccountBalances[strSentAccount] -= nFee;
|
||||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
|
BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
|
||||||
|
100
src/wallet.cpp
100
src/wallet.cpp
@ -231,6 +231,82 @@ bool CWallet::SetMaxVersion(int nVersion)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set<uint256> CWallet::GetConflicts(const uint256& txid) const
|
||||||
|
{
|
||||||
|
set<uint256> result;
|
||||||
|
AssertLockHeld(cs_wallet);
|
||||||
|
|
||||||
|
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid);
|
||||||
|
if (it == mapWallet.end())
|
||||||
|
return result;
|
||||||
|
const CWalletTx& wtx = it->second;
|
||||||
|
|
||||||
|
std::pair<TxConflicts::const_iterator, TxConflicts::const_iterator> range;
|
||||||
|
|
||||||
|
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||||
|
{
|
||||||
|
range = mapTxConflicts.equal_range(txin.prevout);
|
||||||
|
for (TxConflicts::const_iterator it = range.first; it != range.second; ++it)
|
||||||
|
result.insert(it->second);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWallet::SyncMetaData(pair<TxConflicts::iterator, TxConflicts::iterator> range)
|
||||||
|
{
|
||||||
|
// We want all the wallet transactions in range to have the same metadata as
|
||||||
|
// the oldest (smallest nOrderPos).
|
||||||
|
// So: find smallest nOrderPos:
|
||||||
|
|
||||||
|
int nMinOrderPos = std::numeric_limits<int>::max();
|
||||||
|
const CWalletTx* copyFrom = NULL;
|
||||||
|
for (TxConflicts::iterator it = range.first; it != range.second; ++it)
|
||||||
|
{
|
||||||
|
const uint256& hash = it->second;
|
||||||
|
int n = mapWallet[hash].nOrderPos;
|
||||||
|
if (n < nMinOrderPos)
|
||||||
|
{
|
||||||
|
nMinOrderPos = n;
|
||||||
|
copyFrom = &mapWallet[hash];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now copy data from copyFrom to rest:
|
||||||
|
for (TxConflicts::iterator it = range.first; it != range.second; ++it)
|
||||||
|
{
|
||||||
|
const uint256& hash = it->second;
|
||||||
|
CWalletTx* copyTo = &mapWallet[hash];
|
||||||
|
if (copyFrom == copyTo) continue;
|
||||||
|
copyTo->mapValue = copyFrom->mapValue;
|
||||||
|
copyTo->vOrderForm = copyFrom->vOrderForm;
|
||||||
|
// fTimeReceivedIsTxTime not copied on purpose
|
||||||
|
// nTimeReceived not copied on purpose
|
||||||
|
copyTo->nTimeSmart = copyFrom->nTimeSmart;
|
||||||
|
copyTo->fFromMe = copyFrom->fFromMe;
|
||||||
|
copyTo->strFromAccount = copyFrom->strFromAccount;
|
||||||
|
// vfSpent not copied on purpose
|
||||||
|
// nOrderPos not copied on purpose
|
||||||
|
// cached members not copied on purpose
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWallet::AddToConflicts(const uint256& wtxhash)
|
||||||
|
{
|
||||||
|
assert(mapWallet.count(wtxhash));
|
||||||
|
CWalletTx& thisTx = mapWallet[wtxhash];
|
||||||
|
if (thisTx.IsCoinBase())
|
||||||
|
return;
|
||||||
|
|
||||||
|
BOOST_FOREACH(const CTxIn& txin, thisTx.vin)
|
||||||
|
{
|
||||||
|
mapTxConflicts.insert(make_pair(txin.prevout, wtxhash));
|
||||||
|
|
||||||
|
pair<TxConflicts::iterator, TxConflicts::iterator> range;
|
||||||
|
range = mapTxConflicts.equal_range(txin.prevout);
|
||||||
|
if (range.first != range.second)
|
||||||
|
SyncMetaData(range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
|
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
|
||||||
{
|
{
|
||||||
if (IsCrypted())
|
if (IsCrypted())
|
||||||
@ -385,9 +461,16 @@ void CWallet::MarkDirty()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::AddToWallet(const CWalletTx& wtxIn)
|
bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
|
||||||
{
|
{
|
||||||
uint256 hash = wtxIn.GetHash();
|
uint256 hash = wtxIn.GetHash();
|
||||||
|
|
||||||
|
if (fFromLoadWallet)
|
||||||
|
{
|
||||||
|
mapWallet[hash] = wtxIn;
|
||||||
|
AddToConflicts(hash);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
// Inserts only if not already there, returns tx inserted or tx found
|
// Inserts only if not already there, returns tx inserted or tx found
|
||||||
@ -445,6 +528,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
|
|||||||
wtxIn.GetHash().ToString(),
|
wtxIn.GetHash().ToString(),
|
||||||
wtxIn.hashBlock.ToString());
|
wtxIn.hashBlock.ToString());
|
||||||
}
|
}
|
||||||
|
AddToConflicts(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fUpdated = false;
|
bool fUpdated = false;
|
||||||
@ -907,6 +991,18 @@ void CWalletTx::RelayWalletTransaction()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set<uint256> CWalletTx::GetConflicts() const
|
||||||
|
{
|
||||||
|
set<uint256> result;
|
||||||
|
if (pwallet != NULL)
|
||||||
|
{
|
||||||
|
uint256 myHash = GetHash();
|
||||||
|
result = pwallet->GetConflicts(myHash);
|
||||||
|
result.erase(myHash);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void CWallet::ResendWalletTransactions()
|
void CWallet::ResendWalletTransactions()
|
||||||
{
|
{
|
||||||
// Do this infrequently and randomly to avoid giving away
|
// Do this infrequently and randomly to avoid giving away
|
||||||
@ -980,7 +1076,7 @@ int64_t CWallet::GetUnconfirmedBalance() const
|
|||||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||||
{
|
{
|
||||||
const CWalletTx* pcoin = &(*it).second;
|
const CWalletTx* pcoin = &(*it).second;
|
||||||
if (!IsFinalTx(*pcoin) || !pcoin->IsTrusted())
|
if (!IsFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
|
||||||
nTotal += pcoin->GetAvailableCredit();
|
nTotal += pcoin->GetAvailableCredit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
src/wallet.h
14
src/wallet.h
@ -108,6 +108,12 @@ private:
|
|||||||
int64_t nNextResend;
|
int64_t nNextResend;
|
||||||
int64_t nLastResend;
|
int64_t nLastResend;
|
||||||
|
|
||||||
|
// Used to detect and report conflicted transactions:
|
||||||
|
typedef std::multimap<COutPoint, uint256> TxConflicts;
|
||||||
|
TxConflicts mapTxConflicts;
|
||||||
|
void AddToConflicts(const uint256& wtxhash);
|
||||||
|
void SyncMetaData(std::pair<TxConflicts::iterator, TxConflicts::iterator>);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Main wallet lock.
|
/// Main wallet lock.
|
||||||
/// This lock protects all the fields added by CWallet
|
/// This lock protects all the fields added by CWallet
|
||||||
@ -151,6 +157,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::map<uint256, CWalletTx> mapWallet;
|
std::map<uint256, CWalletTx> mapWallet;
|
||||||
|
|
||||||
int64_t nOrderPosNext;
|
int64_t nOrderPosNext;
|
||||||
std::map<uint256, int> mapRequestCount;
|
std::map<uint256, int> mapRequestCount;
|
||||||
|
|
||||||
@ -223,7 +230,7 @@ public:
|
|||||||
TxItems OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount = "");
|
TxItems OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount = "");
|
||||||
|
|
||||||
void MarkDirty();
|
void MarkDirty();
|
||||||
bool AddToWallet(const CWalletTx& wtxIn);
|
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet=false);
|
||||||
void SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock);
|
void SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock);
|
||||||
bool AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate);
|
bool AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate);
|
||||||
void EraseFromWallet(const uint256 &hash);
|
void EraseFromWallet(const uint256 &hash);
|
||||||
@ -358,6 +365,9 @@ public:
|
|||||||
// get the current wallet format (the oldest client version guaranteed to understand this wallet)
|
// get the current wallet format (the oldest client version guaranteed to understand this wallet)
|
||||||
int GetVersion() { AssertLockHeld(cs_wallet); return nWalletVersion; }
|
int GetVersion() { AssertLockHeld(cs_wallet); return nWalletVersion; }
|
||||||
|
|
||||||
|
// Get wallet transactions that conflict with given transaction (spend same outputs)
|
||||||
|
std::set<uint256> GetConflicts(const uint256& txid) const;
|
||||||
|
|
||||||
/** Address book entry changed.
|
/** Address book entry changed.
|
||||||
* @note called with lock cs_wallet held.
|
* @note called with lock cs_wallet held.
|
||||||
*/
|
*/
|
||||||
@ -753,6 +763,8 @@ public:
|
|||||||
void AddSupportingTransactions();
|
void AddSupportingTransactions();
|
||||||
bool AcceptWalletTransaction();
|
bool AcceptWalletTransaction();
|
||||||
void RelayWalletTransaction();
|
void RelayWalletTransaction();
|
||||||
|
|
||||||
|
std::set<uint256> GetConflicts() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -382,7 +382,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||||||
if (wtx.nOrderPos == -1)
|
if (wtx.nOrderPos == -1)
|
||||||
wss.fAnyUnordered = true;
|
wss.fAnyUnordered = true;
|
||||||
|
|
||||||
pwallet->mapWallet[hash] = wtx;
|
pwallet->AddToWallet(wtx, true);
|
||||||
//// debug print
|
//// debug print
|
||||||
//LogPrintf("LoadWallet %s\n", wtx.GetHash().ToString());
|
//LogPrintf("LoadWallet %s\n", wtx.GetHash().ToString());
|
||||||
//LogPrintf(" %12"PRId64" %s %s %s\n",
|
//LogPrintf(" %12"PRId64" %s %s %s\n",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user