Skip to content
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

Doublespend detection is broken #218

Open
Sjors opened this issue May 8, 2023 · 0 comments
Open

Doublespend detection is broken #218

Sjors opened this issue May 8, 2023 · 0 comments

Comments

@Sjors
Copy link
Collaborator

Sjors commented May 8, 2023

The site is finding pairs of transactions for stale blocks that it thinks are conflicting. However in reality for several of these the transaction doesn't actually exist in the shortest branch. E.g. for the stale block at height 788686 transaction b4b995e6a3a7daceab20519ddd34530a997379f29ee1319609a90ea716f7b536 does not exist in either block 000000000000000000032e2236a4c96c9dfc0f9f7993be6675fefb8fb6200b4b or 000000000000000000015221d97f2a108ae4bfea27639592f6cf17a2effc5fa6.

I found a bug that may or may not be at the root of this issue. In any case it makes the result unreliable.

We incorrectly assume a Transaction is associated with one block:

belongs_to :block

This means that the Block method block_and_descendant_transactions returns an incomplete set.

We use the result from that method in get_spent_coins_with_tx to contruct a list of outpoints that are being spent on each side. This list is incomplete.

We then pass that list into get_double_spent_inputs, where we loop through all outpoints spent in the shortest branch. We then find coins that are spent with a different tx in the longest chain.

def get_double_spent_inputs(spent_coins_with_tx)
return nil if spent_coins_with_tx.nil?
(shortest_spent_coins_with_tx, longest_spent_coins_with_tx) = spent_coins_with_tx
# Filter coins that are spent with a different tx in the longest chain
# unique is used because a transaction may doublespend multiple inputs
shortest_spent_coins_with_tx.filter do |txout, tx|
longest_spent_coins_with_tx.key?(txout) && tx.tx_id != longest_spent_coins_with_tx[txout].tx_id
end.collect { |txout, tx| [tx, longest_spent_coins_with_tx[txout]] }.uniq.transpose
end

This however doesn't explain why we end up with transactions that don't occur on the shortest chain at all. So there's probably another bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant