Skip to content

Commit

Permalink
Fixes planetarium#721, Unstage Transaction with same signer's lower n…
Browse files Browse the repository at this point in the history
…once during Append phase
  • Loading branch information
minhoryang committed Dec 14, 2019
1 parent 8bed290 commit 835df4b
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ To be released.
[[#706]]
- Increased `Swarm<T>`'s network timeout value, in order to be stable
a high latency internet connection. [[#709]]
- `BlockChain<T>.Append()` became to unstage the staged `Transaction`s which
nonce was already stored in chain by same signer. [[#721], [#728]]

### Bug fixes

Expand Down Expand Up @@ -111,8 +113,10 @@ To be released.
[#709]: https://github.com/planetarium/libplanet/pull/709
[#718]: https://github.com/planetarium/libplanet/pull/718
[#719]: https://github.com/planetarium/libplanet/pull/719
[#721]: https://github.com/planetarium/libplanet/issues/721
[#725]: https://github.com/planetarium/libplanet/pull/725
[#727]: https://github.com/planetarium/libplanet/pull/727
[#728]: https://github.com/planetarium/libplanet/pull/728


Version 0.7.0
Expand Down
62 changes: 60 additions & 2 deletions Libplanet.Tests/Blockchain/BlockChainTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,64 @@ await Assert.ThrowsAsync<UnexpectedlyTerminatedActionException>(async () =>
Assert.Equal(1, blockChain.Count);
}

[Fact]
public void UnstageAfterAppendComplete()
{
DumbAction.RenderRecords.Value = ImmutableList<RenderRecord>.Empty;
MinerReward.RenderRecords.Value = ImmutableList<RenderRecord>.Empty;

PrivateKey privateKey = new PrivateKey();
(Address[] addresses, Transaction<DumbAction>[] txs) =
MakeFixturesForAppendTests(privateKey);
var genesis = _blockChain.Genesis;

try
{
Block<DumbAction> block1 = TestUtils.MineNext(
genesis,
miner: addresses[4],
difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain),
blockInterval: TimeSpan.FromSeconds(10));
_blockChain.Append(block1);
Assert.Empty(_blockChain.GetStagedTransactionIds());
_blockChain.StageTransactions(txs.ToImmutableHashSet());
Assert.Equal(2, _blockChain.GetStagedTransactionIds().Count);

Block<DumbAction> block2 = TestUtils.MineNext(
block1,
ImmutableHashSet<Transaction<DumbAction>>.Empty.Add(txs[0]),
difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain),
blockInterval: TimeSpan.FromSeconds(10)
);
_blockChain.Append(block2);
Assert.Equal(1, _blockChain.GetStagedTransactionIds().Count);
_blockChain.StageTransactions(txs.ToImmutableHashSet());
Assert.Equal(1, _blockChain.GetStagedTransactionIds().Count);

var actions = new[] { new DumbAction(addresses[0], "foobar") };
Transaction<DumbAction>[] txs2 =
{
_fx.MakeTransaction(actions, privateKey: privateKey, nonce: 0),
};
_blockChain.StageTransactions(txs2.ToImmutableHashSet());
Assert.Equal(2, _blockChain.GetStagedTransactionIds().Count);

Block<DumbAction> block3 = TestUtils.MineNext(
block2,
ImmutableHashSet<Transaction<DumbAction>>.Empty.Add(txs[1]),
difficulty: _blockChain.Policy.GetNextBlockDifficulty(_blockChain),
blockInterval: TimeSpan.FromSeconds(10)
);
_blockChain.Append(block3);
Assert.Empty(_blockChain.GetStagedTransactionIds());
}
finally
{
DumbAction.RenderRecords.Value = ImmutableList<RenderRecord>.Empty;
MinerReward.RenderRecords.Value = ImmutableList<RenderRecord>.Empty;
}
}

[Fact]
public async Task RenderAfterAppendComplete()
{
Expand Down Expand Up @@ -1750,7 +1808,7 @@ void BuildIndex(Guid id, Block<DumbAction> block)
}

private (Address[], Transaction<DumbAction>[])
MakeFixturesForAppendTests()
MakeFixturesForAppendTests(PrivateKey privateKey = null)
{
Address[] addresses =
{
Expand All @@ -1761,7 +1819,7 @@ void BuildIndex(Guid id, Block<DumbAction> block)
_fx.Address5,
};

PrivateKey privateKey = new PrivateKey(new byte[]
privateKey = privateKey ?? new PrivateKey(new byte[]
{
0xa8, 0x21, 0xc7, 0xc2, 0x08, 0xa9, 0x1e, 0x53, 0xbb, 0xb2,
0x71, 0x15, 0xf4, 0x23, 0x5d, 0x82, 0x33, 0x44, 0xd1, 0x16,
Expand Down
20 changes: 17 additions & 3 deletions Libplanet/Blockchain/BlockChain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -767,12 +767,26 @@ bool renderActions
Hash = block.Hash,
};
TipChanged?.Invoke(this, tipChangedEventArgs);
ISet<TxId> txIds = block.Transactions
.Select(t => t.Id)
.ToImmutableHashSet();

_logger.Debug("Unstaging transactions...");

ImmutableDictionary<Address, long> maxNonces = block.Transactions
.GroupBy(
t => t.Signer,
t => t.Nonce,
(signer, nonces) => new
{
signer = signer,
maxNonce = nonces.Max(),
}
)
.ToImmutableDictionary(t => t.signer, t => t.maxNonce);
ISet<TxId> txIds = Store.IterateStagedTransactionIds()
.Select(Store.GetTransaction<T>)
.Where(tx => maxNonces.TryGetValue(tx.Signer, out long nonce) &&
tx.Nonce <= nonce)
.Select(tx => tx.Id)
.ToImmutableHashSet();
Store.UnstageTransactionIds(txIds);
_logger.Debug("Block {blockIndex}: {block} is appended.", block?.Index, block);
}
Expand Down

0 comments on commit 835df4b

Please sign in to comment.