Skip to content

Commit

Permalink
Fix 1244 Mempool.ReverifyTransactions (neo-project#1248)
Browse files Browse the repository at this point in the history
* add internal to DB and WriteBatch

* reset db.cs writebatch.cs

* fix Nep5Token.Burn method

* format

* format

* reset and fix memorypool.ReverifyTransactions

* reset and fix ReverifyTransactions

* add ut

* remove commit

* fix BlockPersistAndReverificationWillAbandonTxAsBalanceTransfered.balance

* update comments
  • Loading branch information
Luchuan committed Jan 10, 2020
1 parent 15e995e commit 4e7f13d
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 1 deletion.
69 changes: 69 additions & 0 deletions neo.UnitTests/Ledger/UT_MemoryPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.Plugins;
using Neo.SmartContract;
using Neo.SmartContract.Native;
using System;
using System.Collections;
Expand Down Expand Up @@ -92,6 +93,31 @@ private Transaction CreateTransactionWithFee(long fee)
return mock.Object;
}

private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee)
{
Random random = new Random();
var randomBytes = new byte[16];
random.NextBytes(randomBytes);
Mock<Transaction> mock = new Mock<Transaction>();
UInt160 sender = UInt160.Zero;
mock.Setup(p => p.Reverify(It.IsAny<Snapshot>(), It.IsAny<BigInteger>())).Returns(((Snapshot snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee));
mock.Setup(p => p.Verify(It.IsAny<Snapshot>(), It.IsAny<BigInteger>())).Returns(true);
mock.Object.Script = randomBytes;
mock.Object.Sender = sender;
mock.Object.NetworkFee = fee;
mock.Object.Attributes = new TransactionAttribute[0];
mock.Object.Cosigners = new Cosigner[0];
mock.Object.Witnesses = new[]
{
new Witness
{
InvocationScript = new byte[0],
VerificationScript = new byte[0]
}
};
return mock.Object;
}

private Transaction CreateTransaction(long fee = -1)
{
if (fee != -1)
Expand All @@ -115,6 +141,17 @@ private void AddTransaction(Transaction txToAdd)
_unit.TryAdd(txToAdd.Hash, txToAdd);
}

private void AddTransactionsWithBalanceVerify(int count, long fee)
{
for (int i = 0; i < count; i++)
{
var txToAdd = CreateTransactionWithFeeAndBalanceVerify(fee);
_unit.TryAdd(txToAdd.Hash, txToAdd);
}

Console.WriteLine($"created {count} tx");
}

[TestMethod]
public void CapacityTest()
{
Expand Down Expand Up @@ -171,6 +208,38 @@ public void BlockPersistMovesTxToUnverifiedAndReverification()
_unit.UnverifiedSortedTxCount.Should().Be(0);
}

[TestMethod]
public void BlockPersistAndReverificationWillAbandonTxAsBalanceTransfered()
{
long txFee = 1;
AddTransactionsWithBalanceVerify(70, txFee);

_unit.SortedTxCount.Should().Be(70);

var block = new Block
{
Transactions = _unit.GetSortedVerifiedTransactions().Take(10).ToArray()
};

// Simulate the transfer process in tx by burning the balance
UInt160 sender = block.Transactions[0].Sender;
Snapshot snapshot = Blockchain.Singleton.GetSnapshot();
BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, sender);

ApplicationEngine applicationEngine = new ApplicationEngine(TriggerType.All, block, snapshot, (long)balance);
NativeContract.GAS.Burn(applicationEngine, sender, balance);
NativeContract.GAS.Mint(applicationEngine, sender, txFee * 30); // Set the balance to meet 30 txs only

// Persist block and reverify all the txs in mempool, but half of the txs will be discarded
_unit.UpdatePoolForBlockPersisted(block, snapshot);
_unit.SortedTxCount.Should().Be(30);
_unit.UnverifiedSortedTxCount.Should().Be(0);

// Revert the balance
NativeContract.GAS.Burn(applicationEngine, sender, txFee * 30);
NativeContract.GAS.Mint(applicationEngine, sender, balance);
}

private void VerifyTransactionsSortedDescending(IEnumerable<Transaction> transactions)
{
Transaction lastTransaction = null;
Expand Down
6 changes: 5 additions & 1 deletion neo/Ledger/MemoryPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,10 @@ private int ReverifyTransactions(SortedSet<PoolItem> verifiedSortedTxPool,
foreach (PoolItem item in unverifiedSortedTxPool.Reverse().Take(count))
{
if (item.Tx.Reverify(snapshot, SendersFeeMonitor.GetSenderFee(item.Tx.Sender)))
{
reverifiedItems.Add(item);
SendersFeeMonitor.AddSenderFee(item.Tx);
}
else // Transaction no longer valid -- it will be removed from unverifiedTxPool.
invalidItems.Add(item);

Expand All @@ -438,7 +441,6 @@ private int ReverifyTransactions(SortedSet<PoolItem> verifiedSortedTxPool,
{
if (_unsortedTransactions.TryAdd(item.Tx.Hash, item))
{
SendersFeeMonitor.AddSenderFee(item.Tx);
verifiedSortedTxPool.Add(item);

if (item.LastBroadcastTimestamp < rebroadcastCutOffTime)
Expand All @@ -447,6 +449,8 @@ private int ReverifyTransactions(SortedSet<PoolItem> verifiedSortedTxPool,
item.LastBroadcastTimestamp = DateTime.UtcNow;
}
}
else
SendersFeeMonitor.RemoveSenderFee(item.Tx);

_unverifiedTransactions.Remove(item.Tx.Hash);
unverifiedSortedTxPool.Remove(item);
Expand Down

0 comments on commit 4e7f13d

Please sign in to comment.