mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-31 19:06:10 +02:00
[RPC] bumpfee
This command allows a user to increase the fee on a wallet transaction T, creating a "bumper" transaction B. T must signal that it is BIP-125 replaceable. T's change output is decremented to pay the additional fee. (B will not add inputs to T.) T cannot have any descendant transactions. Once B bumps T, neither T nor B's outputs can be spent until either T or (more likely) B is mined. Includes code by @jonasschnelli and @ryanofsky
This commit is contained in:
committed by
Russell Yanofsky
parent
52dde66770
commit
cc0243ad32
@@ -411,6 +411,13 @@ set<uint256> CWallet::GetConflicts(const uint256& txid) const
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CWallet::HasWalletSpend(const uint256& txid) const
|
||||
{
|
||||
AssertLockHeld(cs_wallet);
|
||||
auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0));
|
||||
return (iter != mapTxSpends.end() && iter->first.hash == txid);
|
||||
}
|
||||
|
||||
void CWallet::Flush(bool shutdown)
|
||||
{
|
||||
bitdb.Flush(shutdown);
|
||||
@@ -826,6 +833,35 @@ void CWallet::MarkDirty()
|
||||
}
|
||||
}
|
||||
|
||||
bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
|
||||
auto mi = mapWallet.find(originalHash);
|
||||
|
||||
// There is a bug if MarkReplaced is not called on an existing wallet transaction.
|
||||
assert(mi != mapWallet.end());
|
||||
|
||||
CWalletTx& wtx = (*mi).second;
|
||||
|
||||
// Ensure for now that we're not overwriting data
|
||||
assert(wtx.mapValue.count("replaced_by_txid") == 0);
|
||||
|
||||
wtx.mapValue["replaced_by_txid"] = newHash.ToString();
|
||||
|
||||
CWalletDB walletdb(strWalletFile, "r+");
|
||||
|
||||
bool success = true;
|
||||
if (!walletdb.WriteTx(wtx)) {
|
||||
LogPrintf("%s: Updating walletdb tx %s failed", __func__, wtx.GetHash().ToString());
|
||||
success = false;
|
||||
}
|
||||
|
||||
NotifyTransactionChanged(this, originalHash, CT_UPDATED);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
@@ -1981,6 +2017,37 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
|
||||
if (nDepth == 0 && !pcoin->InMempool())
|
||||
continue;
|
||||
|
||||
// We should not consider coins from transactions that are replacing
|
||||
// other transactions.
|
||||
//
|
||||
// Example: There is a transaction A which is replaced by bumpfee
|
||||
// transaction B. In this case, we want to prevent creation of
|
||||
// a transaction B' which spends an output of B.
|
||||
//
|
||||
// Reason: If transaction A were initially confirmed, transactions B
|
||||
// and B' would no longer be valid, so the user would have to create
|
||||
// a new transaction C to replace B'. However, in the case of a
|
||||
// one-block reorg, transactions B' and C might BOTH be accepted,
|
||||
// when the user only wanted one of them. Specifically, there could
|
||||
// be a 1-block reorg away from the chain where transactions A and C
|
||||
// were accepted to another chain where B, B', and C were all
|
||||
// accepted.
|
||||
if (nDepth == 0 && fOnlyConfirmed && pcoin->mapValue.count("replaces_txid")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Similarly, we should not consider coins from transactions that
|
||||
// have been replaced. In the example above, we would want to prevent
|
||||
// creation of a transaction A' spending an output of A, because if
|
||||
// transaction B were initially confirmed, conflicting with A and
|
||||
// A', we wouldn't want to the user to create a transaction D
|
||||
// intending to replace A', but potentially resulting in a scenario
|
||||
// where A, A', and D could all be accepted (instead of just B and
|
||||
// D, or just A and A' like the user would want).
|
||||
if (nDepth == 0 && fOnlyConfirmed && pcoin->mapValue.count("replaced_by_txid")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {
|
||||
isminetype mine = IsMine(pcoin->tx->vout[i]);
|
||||
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
|
||||
|
||||
Reference in New Issue
Block a user