-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Rollback unsuccessful preconfs in the mempool #3264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
30b5869
a970140
42f111e
01410e0
84b0c4a
f989aab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Rollback stale preconfirmations in the mempool when the canonical block at that height omits the preconfirmed transactions, restoring spent inputs and removing dependent transactions. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,13 +27,17 @@ pub struct SpentInputs { | |
| /// transaction spent it. Later, this information can be used to unspent | ||
| /// or fully spend the input. | ||
| spender_of_inputs: HashMap<TxId, Vec<InputKey>>, | ||
| /// Inputs permanently spent during preconfirmation processing, saved so | ||
| /// they can be rolled back if the preconfirmation turns out to be stale. | ||
| tentative_spent: HashMap<TxId, Vec<InputKey>>, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any chance that his will grow indefinitely? Seems fine to me. It's not good to test internal values anyway, but worth considering if this is a "leak" in any way.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so, unless blocks are not getting imported at all. These are always cleared for when the associated block height gets imported. |
||
| } | ||
|
|
||
| impl SpentInputs { | ||
| pub fn new(capacity: NonZeroUsize) -> Self { | ||
| Self { | ||
| spent_inputs: LruCache::new(capacity), | ||
| spender_of_inputs: HashMap::new(), | ||
| tentative_spent: HashMap::new(), | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -114,6 +118,43 @@ impl SpentInputs { | |
| pub fn is_spent_tx(&self, tx: &TxId) -> bool { | ||
| self.spent_inputs.contains(&InputKey::Tx(*tx)) | ||
| } | ||
|
|
||
| /// Record inputs that were permanently spent during preconfirmation processing. | ||
| /// The saved keys can later be rolled back via [`unspend_preconfirmed`]. | ||
| pub fn record_tentative_spend(&mut self, tx_id: TxId, inputs: &[Input]) { | ||
| let keys: Vec<InputKey> = inputs | ||
| .iter() | ||
| .filter_map(|input| { | ||
| if input.is_coin() { | ||
| input.utxo_id().cloned().map(InputKey::Utxo) | ||
| } else if input.is_message() { | ||
| input.nonce().cloned().map(InputKey::Message) | ||
| } else { | ||
| None | ||
| } | ||
| }) | ||
| .collect(); | ||
| self.tentative_spent.insert(tx_id, keys); | ||
| } | ||
|
|
||
| /// Remove the tentative-spend record for a confirmed transaction, preventing | ||
| /// a spurious rollback. Called when the preconfirmed tx is included in the | ||
| /// canonical block. | ||
| pub fn confirm_tentative_spend(&mut self, tx_id: &TxId) { | ||
| self.tentative_spent.remove(tx_id); | ||
| } | ||
|
|
||
| /// Removes the tx entry and any individually-tracked UTXO/message inputs | ||
| /// from spent inputs, allowing the same inputs to be re-used. | ||
| /// Used when rolling back a stale preconfirmation. | ||
| pub fn unspend_preconfirmed(&mut self, tx_id: TxId) { | ||
| self.spent_inputs.pop(&InputKey::Tx(tx_id)); | ||
| if let Some(saved_keys) = self.tentative_spent.remove(&tx_id) { | ||
| for key in saved_keys { | ||
| self.spent_inputs.pop(&key); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.