diff --git a/pkg/core/mempool/mem_pool_test.go b/pkg/core/mempool/mem_pool_test.go index 6575ccf4e..4cd529a06 100644 --- a/pkg/core/mempool/mem_pool_test.go +++ b/pkg/core/mempool/mem_pool_test.go @@ -1,6 +1,7 @@ package mempool import ( + "sort" "testing" "github.com/CityOfZion/neo-go/pkg/core/transaction" @@ -35,7 +36,7 @@ func (fs *FeerStub) SystemFee(*transaction.Transaction) util.Fixed8 { func testMemPoolAddRemoveWithFeer(t *testing.T, fs Feer) { mp := NewMemPool(10) - tx := newMinerTX() + tx := newMinerTX(0) _, ok := mp.TryGetValue(tx.Hash()) require.Equal(t, false, ok) require.NoError(t, mp.Add(tx, fs)) @@ -61,19 +62,19 @@ func TestMemPoolAddRemove(t *testing.T) { func TestMemPoolVerify(t *testing.T) { mp := NewMemPool(10) - tx := newMinerTX() + tx := newMinerTX(1) inhash1 := random.Uint256() tx.Inputs = append(tx.Inputs, transaction.Input{PrevHash: inhash1, PrevIndex: 0}) require.Equal(t, true, mp.Verify(tx)) require.NoError(t, mp.Add(tx, &FeerStub{})) - tx2 := newMinerTX() + tx2 := newMinerTX(2) inhash2 := random.Uint256() tx2.Inputs = append(tx2.Inputs, transaction.Input{PrevHash: inhash2, PrevIndex: 0}) require.Equal(t, true, mp.Verify(tx2)) require.NoError(t, mp.Add(tx2, &FeerStub{})) - tx3 := newMinerTX() + tx3 := newMinerTX(3) // Different index number, but the same PrevHash as in tx1. tx3.Inputs = append(tx3.Inputs, transaction.Input{PrevHash: inhash1, PrevIndex: 1}) require.Equal(t, true, mp.Verify(tx3)) @@ -83,9 +84,134 @@ func TestMemPoolVerify(t *testing.T) { require.Error(t, mp.Add(tx3, &FeerStub{})) } -func newMinerTX() *transaction.Transaction { +func newMinerTX(i uint32) *transaction.Transaction { return &transaction.Transaction{ Type: transaction.MinerType, - Data: &transaction.MinerTX{}, + Data: &transaction.MinerTX{Nonce: i}, + } +} + +func TestOverCapacity(t *testing.T) { + var fs = &FeerStub{lowPriority: true} + const mempoolSize = 10 + mp := NewMemPool(mempoolSize) + + for i := 0; i < mempoolSize; i++ { + tx := newMinerTX(uint32(i)) + require.NoError(t, mp.Add(tx, fs)) + } + txcnt := uint32(mempoolSize) + require.Equal(t, mempoolSize, mp.Count()) + require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) + + // Claim TX has more priority than ordinary lowprio, so it should easily + // fit into the pool. + claim := &transaction.Transaction{ + Type: transaction.ClaimType, + Data: &transaction.ClaimTX{}, + } + require.NoError(t, mp.Add(claim, fs)) + require.Equal(t, mempoolSize, mp.Count()) + require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) + + // Fees are also prioritized. + fs.netFee = util.Fixed8FromFloat(0.0001) + for i := 0; i < mempoolSize-1; i++ { + tx := newMinerTX(txcnt) + txcnt++ + require.NoError(t, mp.Add(tx, fs)) + require.Equal(t, mempoolSize, mp.Count()) + require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) + } + // Less prioritized txes are not allowed anymore. + fs.netFee = util.Fixed8FromFloat(0.00001) + tx := newMinerTX(txcnt) + txcnt++ + require.Error(t, mp.Add(tx, fs)) + require.Equal(t, mempoolSize, mp.Count()) + require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) + + // But claim tx should still be there. + require.True(t, mp.ContainsKey(claim.Hash())) + + // Low net fee, but higher per-byte fee is still a better combination. + fs.perByteFee = util.Fixed8FromFloat(0.001) + tx = newMinerTX(txcnt) + txcnt++ + require.NoError(t, mp.Add(tx, fs)) + require.Equal(t, mempoolSize, mp.Count()) + require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) + + // High priority always wins over low priority. + fs.lowPriority = false + for i := 0; i < mempoolSize; i++ { + tx := newMinerTX(txcnt) + txcnt++ + require.NoError(t, mp.Add(tx, fs)) + require.Equal(t, mempoolSize, mp.Count()) + require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) + } + // Good luck with low priority now. + fs.lowPriority = true + tx = newMinerTX(txcnt) + require.Error(t, mp.Add(tx, fs)) + require.Equal(t, mempoolSize, mp.Count()) + require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes))) +} + +func TestGetVerified(t *testing.T) { + var fs = &FeerStub{lowPriority: true} + const mempoolSize = 10 + mp := NewMemPool(mempoolSize) + + txes := make([]*transaction.Transaction, 0, mempoolSize) + for i := 0; i < mempoolSize; i++ { + tx := newMinerTX(uint32(i)) + txes = append(txes, tx) + require.NoError(t, mp.Add(tx, fs)) + } + require.Equal(t, mempoolSize, mp.Count()) + verTxes := mp.GetVerifiedTransactions() + require.Equal(t, mempoolSize, len(verTxes)) + for _, tx := range verTxes { + require.Contains(t, txes, tx) + } + for _, tx := range txes { + mp.Remove(tx.Hash()) + } + verTxes = mp.GetVerifiedTransactions() + require.Equal(t, 0, len(verTxes)) +} + +func TestRemoveStale(t *testing.T) { + var fs = &FeerStub{lowPriority: true} + const mempoolSize = 10 + mp := NewMemPool(mempoolSize) + + txes1 := make([]*transaction.Transaction, 0, mempoolSize/2) + txes2 := make([]*transaction.Transaction, 0, mempoolSize/2) + for i := 0; i < mempoolSize; i++ { + tx := newMinerTX(uint32(i)) + if i%2 == 0 { + txes1 = append(txes1, tx) + } else { + txes2 = append(txes2, tx) + } + require.NoError(t, mp.Add(tx, fs)) + } + require.Equal(t, mempoolSize, mp.Count()) + mp.RemoveStale(func(t *transaction.Transaction) bool { + for _, tx := range txes2 { + if tx == t { + return true + } + } + return false + }) + require.Equal(t, mempoolSize/2, mp.Count()) + verTxes := mp.GetVerifiedTransactions() + for _, tx := range verTxes { + require.NotContains(t, txes1, tx) + require.Contains(t, txes2, tx) } }