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

Fix mempool and chain locking #647

Merged
merged 18 commits into from
Feb 6, 2020
Merged

Conversation

roman-khimov
Copy link
Member

Problem

Our mempool sucks.

Solution

Make it great again! This allows us easily make 1000 Tx/s in 4-nodes privnet, fixes potential double spends and improves mempool testing coverage.

Makes no sense copying the Pool around.
Eliminate races between tx checks and adding them to the mempool, ensure the
chain doesn't change while we're working with the new tx. Ensure only one
block addition attempt could be in progress.
We can only add one block of the given height and we have two competing
goroutines to do that --- consensus and block queue. Whomever adds the block
first shouldn't trigger an error in another one.

Fix block relaying for blocks added via the block queue also, previously one
consensus-generated blocks were broadcasted.
Appending and not changing the real Items is utterly wrong.
Nobody outside should care about these details, mempool operates on
transactions and that's it.
After the f0bb886 with all methods of Pool
being pointer-based it makes no sense having this lock as a pointer.
They shouldn't depend on the chain state and for the same transaction they
should always produce the same result. Thus, it makes no sense recalculating
them over and over again.
It doesn't harm as we have transactions naturally ordered by fee anyway and it
makes managing them a little easier. This also makes slices store item itself
instead of pointers to it which reduces the pressure on the memory subsystem.
Chopping off the last element of the slice if way easier than doing it with
the first one.
Which is way faster than sort.Sort'ing things all the time.
We not only need to remove transactions stored in the block, but also
invalidate some potential double spends caused by these transactions. Usually
new block contains a substantial number of transactions from the pool, so it's
easier to make one pass over it only keeping valid items rather than remove
them one by one and make an additional pass to recheck inputs/witnesses.
Our mempool only contains valid verified transactions all the time, it never
has any unverified ones. Unverified pool made some sense for quick unverifying
after the new block acceptance (and gradual background reverification), but
reverification needs some non-trivial locking between blockchain and mempool
and internal mempool state locking (reverifying tx and moving it between
unverified and verified pools must be atomic). But our current reverification
is fast enough (and has all the appropriate locks), so bothering with
unverified pool makes little sense.
It's more efficient and keeps transactions sorted by priority.
@roman-khimov roman-khimov added the network P2P layer label Feb 6, 2020
@roman-khimov roman-khimov added this to the v0.72.0 milestone Feb 6, 2020
@roman-khimov roman-khimov requested a review from fyrchik February 6, 2020 14:43
@codecov
Copy link

codecov bot commented Feb 6, 2020

Codecov Report

Merging #647 into master will increase coverage by 0.44%.
The diff coverage is 65.35%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #647      +/-   ##
==========================================
+ Coverage    63.9%   64.34%   +0.44%     
==========================================
  Files         126      126              
  Lines       10574    10597      +23     
==========================================
+ Hits         6757     6819      +62     
+ Misses       3511     3475      -36     
+ Partials      306      303       -3
Impacted Files Coverage Δ
pkg/consensus/consensus.go 42.01% <0%> (-0.18%) ⬇️
pkg/network/server.go 17.57% <0%> (-0.17%) ⬇️
pkg/core/mempool/prometheus.go 100% <100%> (ø) ⬆️
pkg/network/blockqueue.go 79.16% <22.22%> (-4.93%) ⬇️
pkg/core/blockchain.go 31.17% <24.39%> (-0.49%) ⬇️
pkg/core/mempool/mem_pool.go 97.63% <98.86%> (+51.37%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 70c22eb...7445655. Read the comment docs.

Simplifies things a lot and removes useless code.
Fixes GolangCI:
  Error return value of
  (*github.com/CityOfZion/neo-go/pkg/core/mempool.Pool).Add is not checked
  (from errcheck)

and allows us to almost completely forget about mempool here.
@roman-khimov roman-khimov force-pushed the fix-mempool-and-chain-locking branch from 037dab4 to 7445655 Compare February 6, 2020 14:50
}
}
if num < len(mp.verifiedTxes)-1 {
mp.verifiedTxes = append(mp.verifiedTxes[:num], mp.verifiedTxes[num+1:]...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this line alone is enough. We should simplify it later.

@roman-khimov roman-khimov merged commit ab14a46 into master Feb 6, 2020
@roman-khimov roman-khimov deleted the fix-mempool-and-chain-locking branch February 6, 2020 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
network P2P layer
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants