mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-07-12 15:52:40 +02:00
Merge bitcoin/bitcoin#28251: validation: fix coins disappearing mid-package evaluation
32c1dd1ad6
[test] mempool coins disappearing mid-package evaluation (glozow)a67f460c3f
[refactor] split setup in mempool_limit test (glozow)d08696120e
[test framework] add ability to spend only confirmed utxos (glozow)3ea71feb11
[validation] don't LimitMempoolSize in any subpackage submissions (glozow)d227b7234c
[validation] return correct result when already-in-mempool tx gets evicted (glozow)9698b81828
[refactor] back-fill results in AcceptPackage (glozow)8ad7ad3392
[validation] make PackageMempoolAcceptResult members mutable (glozow)03b87c11ca
[validation] add AcceptSubPackage to delegate Accept* calls and clean up m_view (glozow)3f01a3dab1
[CCoinsViewMemPool] track non-base coins and allow Reset (glozow)7d7f7a1189
[policy] check for duplicate txids in package (glozow) Pull request description: While we are evaluating a package, we split it into "subpackages" for evaluation (currently subpackages all have size 1 except the last one). If a subpackage has size 1, we may add a tx to mempool and call `LimitMempoolSize()`, which evicts transactions if the mempool gets full. We handle the case where the just-submitted transaction is evicted immediately, but we don't handle the case in which a transaction from a previous subpackage (either just submitted or already in mempool) is evicted. Mainly, since the coins created by the evicted transaction are cached in `m_view`, we don't realize the UTXO has disappeared until `CheckInputsFromMempoolAndCache` asserts that they exist. Also, the returned `PackageMempoolAcceptResult` reports that the transaction is in mempool even though it isn't anymore. Fix this by not calling `LimitMempoolSize()` until the very end, and editing the results map with "mempool full" if things fall out. Pointed out by instagibbs infaeed687e5
on top of the v3 PR. ACKs for top commit: instagibbs: reACK32c1dd1ad6
Tree-SHA512: 61e7f69db4712e5e5bfa27d037ab66bdd97f1bf60a8d9ffb96adb1f0609af012c810d681102ee5c7baec7b5fe8cb7c304a60c63ccc445d00d86a2b7f0e7ddb90
This commit is contained in:
@ -208,7 +208,7 @@ class MiniWallet:
|
||||
assert_equal(self._mode, MiniWalletMode.ADDRESS_OP_TRUE)
|
||||
return self._address
|
||||
|
||||
def get_utxo(self, *, txid: str = '', vout: Optional[int] = None, mark_as_spent=True) -> dict:
|
||||
def get_utxo(self, *, txid: str = '', vout: Optional[int] = None, mark_as_spent=True, confirmed_only=False) -> dict:
|
||||
"""
|
||||
Returns a utxo and marks it as spent (pops it from the internal list)
|
||||
|
||||
@ -224,19 +224,23 @@ class MiniWallet:
|
||||
utxo_filter = reversed(mature_coins) # By default the largest utxo
|
||||
if vout is not None:
|
||||
utxo_filter = filter(lambda utxo: vout == utxo['vout'], utxo_filter)
|
||||
if confirmed_only:
|
||||
utxo_filter = filter(lambda utxo: utxo['confirmations'] > 0, utxo_filter)
|
||||
index = self._utxos.index(next(utxo_filter))
|
||||
if mark_as_spent:
|
||||
return self._utxos.pop(index)
|
||||
else:
|
||||
return self._utxos[index]
|
||||
|
||||
def get_utxos(self, *, include_immature_coinbase=False, mark_as_spent=True):
|
||||
def get_utxos(self, *, include_immature_coinbase=False, mark_as_spent=True, confirmed_only=False):
|
||||
"""Returns the list of all utxos and optionally mark them as spent"""
|
||||
if not include_immature_coinbase:
|
||||
blocks_height = self._test_node.getblockchaininfo()['blocks']
|
||||
utxo_filter = filter(lambda utxo: not utxo['coinbase'] or COINBASE_MATURITY - 1 <= blocks_height - utxo['height'], self._utxos)
|
||||
else:
|
||||
utxo_filter = self._utxos
|
||||
if confirmed_only:
|
||||
utxo_filter = filter(lambda utxo: utxo['confirmations'] > 0, utxo_filter)
|
||||
utxos = deepcopy(list(utxo_filter))
|
||||
if mark_as_spent:
|
||||
self._utxos = []
|
||||
@ -286,14 +290,15 @@ class MiniWallet:
|
||||
locktime=0,
|
||||
sequence=0,
|
||||
fee_per_output=1000,
|
||||
target_weight=0
|
||||
target_weight=0,
|
||||
confirmed_only=False
|
||||
):
|
||||
"""
|
||||
Create and return a transaction that spends the given UTXOs and creates a
|
||||
certain number of outputs with equal amounts. The output amounts can be
|
||||
set by amount_per_output or automatically calculated with a fee_per_output.
|
||||
"""
|
||||
utxos_to_spend = utxos_to_spend or [self.get_utxo()]
|
||||
utxos_to_spend = utxos_to_spend or [self.get_utxo(confirmed_only=confirmed_only)]
|
||||
sequence = [sequence] * len(utxos_to_spend) if type(sequence) is int else sequence
|
||||
assert_equal(len(utxos_to_spend), len(sequence))
|
||||
|
||||
@ -333,9 +338,17 @@ class MiniWallet:
|
||||
"tx": tx,
|
||||
}
|
||||
|
||||
def create_self_transfer(self, *, fee_rate=Decimal("0.003"), fee=Decimal("0"), utxo_to_spend=None, locktime=0, sequence=0, target_weight=0):
|
||||
def create_self_transfer(self, *,
|
||||
fee_rate=Decimal("0.003"),
|
||||
fee=Decimal("0"),
|
||||
utxo_to_spend=None,
|
||||
locktime=0,
|
||||
sequence=0,
|
||||
target_weight=0,
|
||||
confirmed_only=False
|
||||
):
|
||||
"""Create and return a tx with the specified fee. If fee is 0, use fee_rate, where the resulting fee may be exact or at most one satoshi higher than needed."""
|
||||
utxo_to_spend = utxo_to_spend or self.get_utxo()
|
||||
utxo_to_spend = utxo_to_spend or self.get_utxo(confirmed_only=confirmed_only)
|
||||
assert fee_rate >= 0
|
||||
assert fee >= 0
|
||||
# calculate fee
|
||||
|
Reference in New Issue
Block a user