In Core, a payment appearing under removed does not necessarily mean the recipient is unpaid. In our controlled two- test, the same transaction appeared in both the transactions and removed arrays of a listsinceblock response. It was confirmed in the active chain.
The old had lost its place in the winning history. The payment had found a place in a different block. Reading the word removed without checking what it referred to would have turned a valid payment into an apparent failure.
We followed the signed transaction through two private chain splits, then checked a competing spend as well. The useful lesson is about evidence: a transaction identifier, a block record and a 's current payment status answer different questions.
Removed from which history?
A does not permanently attach a payment to a particular block or number of . The same signed payment can remain unchanged while the chain around it changes. In this test we also compare the complete serialized bytes; matching txids alone would not prove that matched. The txid and wtxid guide explains that distinction.
When a node switches to a valid branch with more accumulated work, blocks on the old branch stop contributing to the active chain. Transactions in those blocks need to be reconsidered against the winning history. Some can return to the , some can already be present in the new branch, and some can conflict with a confirmed spend.
Our consensus and reorganizations guide explains that wider process. Here we look at the records a person or payment service actually has to interpret.
One transaction, more than one current status
We called the first payment P. It sent 1 LTC to our clean receiving wallet and first confirmed in node A's block 104. Node B, disconnected from A, built a different branch from their common block 103. Its branch reached height 106 with more accumulated work and without P.
| Observation | Active tip | Wallet confirmations | In A's mempool? |
|---|---|---|---|
| First confirmation | 104 | 1 | No |
| After adopting B's branch | 106 | 0 | Yes |
| Confirmed in the winning branch | 107 | 1 | No |
After reconnection, A accepted B's higher-work history and re-admitted P to its own mempool. At that snapshot B's mempool was empty. We explicitly submitted the same signed P bytes to B before its next block. The re-confirmation therefore does not establish automatic or instantaneous relay between the two nodes.
A zero-confirmation wallet result alone is not enough to say the payment is waiting in a mempool. In our returned-payment case we also checked the node's actual mempool. A wallet can know about a transaction without that node currently holding it for mining.
When the payment confirmed again, its transaction ID was unchanged. Its block association changed. The new confirmations were counted on the winning branch, rather than added to the old branch's confirmations.
Why Core reported the payment twice
listsinceblock is a way to ask a wallet what happened after a saved block checkpoint. When the supplied checkpoint belongs to a branch that has been displaced, its removed entries help describe what came out of that old history.
The pinned Litecoin Core RPC implementation explicitly documents that transactions added back to the active chain may occur in removed with positive confirmations. That field is not a permanent verdict that their outputs are unpaid.
In the recipient wallet at height 107, the saved old-block checkpoint returned one receive entry for P in each array. Both entries carried the same txid, output index and 1 LTC amount, and both reported one current confirmation in the new block 107. Treating the arrays as two different payments would overcount. Treating every removed entry as an instruction to erase a credit would make the opposite mistake.
Read the response as information for reconciliation. The same transaction can be relevant to both the change in history and the current active history. Individual wallet entries can also describe different outputs or send/receive effects; the number of rows is not a count of independent invoices.
A competing spend produced a different result
The second split used a new payment Q, sending 1 LTC to our original recipient. Q confirmed in A's block 108. Separately, we signed transaction R spending the same input but paying 2 LTC to a different wallet on B. B confirmed R in its own block 108 and extended that branch to 110.
After reconnection, Q had confirmations: -3 in both the sender and original recipient wallets. R had three confirmations. The original recipient's trusted balance fell from 2 LTC to 1 LTC: the earlier P payment remained confirmed, while Q no longer contributed.
There was a second trap in the raw response. The recipient's gettransaction result for Q still contained amount: 1, alongside confirmations: -3, empty details and empty walletconflicts. Summing that amount without reading its state would have kept credit for a conflicted payment.
This is the distinction that a single label hides. A transaction coming out of an old block may still pay the intended recipient later. A transaction losing to an incompatible confirmed spend cannot be counted as that same payment merely because the wallet still remembers it.
Negative wallet confirmations describe a known confirmed conflict. They are different from the -1 returned for a block that is outside the active chain. Check which RPC object supplied the value before interpreting it.
walletconflicts is also a wallet's view. A sender's wallet and a recipient's wallet need not know the same competing transactions. In particular, a competing payment to somebody else need not appear as a received transaction in the original recipient's wallet.
An old block can still contain the transaction
At height 107 we asked for P's bytes specifically from its old block 104. Core returned the unchanged transaction, with in_active_chain: false and zero confirmations for that old block association. The wallet, meanwhile, reported P confirmed in the new block.
| Query | Recorded result | What it describes |
|---|---|---|
| Wallet gettransaction(P) | 1 confirmation, block 107 | P's current wallet state |
| getrawtransaction(P, true, old block) | 0 confirmations; in_active_chain=false | P's inclusion in the specified stale block |
| getblockheader(old block) | -1 confirmation | The old block is outside the active chain |
The raw-transaction RPC documents the explicit block-hash lookup. The old block remaining readable does not make it active.
This matters when a support ticket includes an old explorer screenshot or a proof tied to a saved header. Check the block's current place in the active chain, as well as whether the transaction is in it. Our inclusion-proof guide explains what a can establish.
A payment record needs an identity and a revisable status
Keep the identity of an expected payment separate from its changing confirmation state. For an ordinary transparent Litecoin output, record the network, transaction ID, output index, expected destination or script and amount, and the invoice or other obligation it is meant to satisfy.
The output index matters because a transaction can contain several outputs. The invoice reference matters because transaction data alone does not explain which bill the sender intended to pay. A wallet label is useful local context, but it is not a rule.
Do not confuse a received payment with an output that is still unspent. The recipient may later spend a correctly received output. Our gettxout guide shows why a null lookup alone cannot establish that a bill was never paid.
Store the observed block hash and height as observations, with the time and source of the check. Update the status when the active chain changes. Preserve the earlier observation in the audit trail rather than pretending that the confirmation was never seen.
For a payment service, repeated notifications should update the same expected payment, not create a fresh credit each time. If a credit must be reversed, that should be an explicit accounting transition tied to current evidence and the service's confirmation policy.
Reconcile before advancing the checkpoint
A small outline makes the order of operations clearer:
read wallet changes from the saved block checkpoint
collect affected txids plus payments still awaiting review
check their current chain, wallet and expected-output state
update each saved payment record idempotently
commit the reconciled records and the new checkpoint together
This is a design outline, not a complete payment processor. It omits database locking, multiple wallet rows per transaction, node failures, , policy thresholds and how to obtain a consistent view while new blocks arrive.
The important ordering is to apply the payment-state changes before considering the checkpoint safely processed. Advancing the checkpoint and crashing before updating credits can lose work. Processing a response again after a retry should not produce a second credit.
Do not silently interpret an RPC error or an unavailable old block as an empty change list. Keep the last successfully processed checkpoint and investigate the missing evidence. Services using pruned nodes need a deliberate plan for historical reconciliation.
There is another easy trap in listsinceblock: target_confirmations does not filter the returned transactions down to payments with that many confirmations. It changes the lastblock checkpoint. A larger value leaves more overlap for later polls; your application still needs its own confirmation threshold. At our height-107 snapshot, target 1 returned the block-107 cursor. Target 6 returned the block-102 cursor, yet still included P with just one confirmation. A six-confirmation acceptance rule would have to be applied separately.
Three read-only checks on your own node
litecoin-cli -rpcwallet=YOUR_WALLET gettransaction TXID
litecoin-cli -rpcwallet=YOUR_WALLET listsinceblock SAVED_BLOCK_HASH
litecoin-cli getblockheader BLOCK_HASH
Replace the uppercase placeholders with records from the correct network and wallet. These commands query state; they do not broadcast, cancel or refund a payment. gettransaction is wallet-specific, so a lookup failure is not proof that the transaction never existed.
Use the saved or currently returned block association to examine the relevant header, and verify mempool membership separately when the payment is unconfirmed. If you are checking through a service, ask which chain tip and data source its status reflects. An old status page can lag behind a node's present view.
If the recipient says a payment is missing, establish the current status before sending another one. The guide to avoiding duplicate Litecoin payments covers that next decision.
What this test establishes
One completed run of Litecoin Core 0.21.5.8 on Windows recorded eight named snapshots, 83 runtime checks, three signed candidates and 112 block records. Both nodes used fresh local data directories, loopback-only peer connections and artificial timestamps; MWEB remained inactive. Both processes stopped and the disposable data directories were removed after export. We used ordinary transparent transactions and disposable regtest wallets with valueless coins. The nodes' branches were deliberately separated and reconnected. This was not an observation of a naturally occurring mainnet reorganization.
The test demonstrates the recorded software behavior under those conditions. It does not estimate how often a reorganization will happen, price an attack, establish a universally safe confirmation count or test . We did not test a real , merchant platform or .
The project's functional tests provide separate examples of reorganizations and wallet history. Our downloadable package records our own run rather than presenting an upstream test result as ours.
Download the eight-state case table, structured results and block records and RPC observations. The reproduction runner creates a fresh disposable regtest setup. The method and limits describe the private branches, explicit P rebroadcast and versioned binary provenance.
A separate offline verifier checks the exported transactions, block relationships and recorded wallet states for consistency. It does not independently verify signatures, or that the recorded execution occurred. See the pinned source record and package checksums. Research, test scripting and drafting used AI assistance. The cover is a conceptual illustration.



