diff --git a/.azure-pipelines/mono.yml b/.azure-pipelines/mono.yml index 74f913e353f..5b6cc622770 100644 --- a/.azure-pipelines/mono.yml +++ b/.azure-pipelines/mono.yml @@ -28,7 +28,7 @@ steps: displayName: xunit.console.exe *.Tests.dll inputs: script: | - mono xunit.runner.console.*/tools/net472/xunit.console.exe \ + mono xunit.runner.console.*/tools/net461/xunit.console.exe \ *.Tests/bin/${{ parameters.configuration }}/net*/*.Tests.dll env: TURN_SERVER_URL: ${{ parameters.turnServerUrl }} diff --git a/.azure-pipelines/windows-net461.yml b/.azure-pipelines/windows-net461.yml index cfd13d81abe..9b2d4afa703 100644 --- a/.azure-pipelines/windows-net461.yml +++ b/.azure-pipelines/windows-net461.yml @@ -33,15 +33,9 @@ steps: targetType: inline script: | ${{ parameters.testPrefix }} \ - xunit.runner.console.*/tools/net472/xunit.console.exe \ + xunit.runner.console.*/tools/net461/xunit.console.exe \ *.Tests/bin/$(configuration)/net*/*.Tests.dll \ ${{ parameters.testArguments }} - # FIXME: For unknown reason, on Windows tests depending on TURN_SERVER_URL - # seems to never end or to take too long time. We should diagnose - # this and make Windows builds to run these tests too. - # FIXME: For unknown reason, on Windows + Mono SwarmTests seem never end. - # We should diagnose this and make Windows builds to run these - # tests too. env: TURN_SERVER_URL: ${{ parameters.turnServerUrl }} timeoutInMinutes: 10 diff --git a/CHANGES.md b/CHANGES.md index 6b5ce98eefa..89d97cce9a7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -112,7 +112,9 @@ To be released. - `BlockChain.Append()` method became to throw `InvalidTxNonceException` when the `Transaction.Nonce` does not correspond to its `Signer`'s current nonce. [[#246]] - + - `Swarm` became to enforce `ForceDotNet.Force()` in [AsyncIO] while it's running on + Mono runtime. [[#247]] + ### Bug fixes - Fixed a bug that TURN relay had been disconnected when being connected for @@ -140,7 +142,10 @@ To be released. unnecessary race conditions. [[#217]] - Fixed a bug that `Swarm` could not properly communicate with `Peer` behind NAT. [[#240]] + - Fixed a bug that `BlockChain.FindNextHashes()` throws + `ArgumentOutOfRangeException` when chain is empty. +[AsyncIO]: https://github.com/somdoron/AsyncIO [Ethereum Homestead algorithm]: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.md [#31]: https://github.com/planetarium/libplanet/issues/31 [#133]: https://github.com/planetarium/libplanet/issues/133 @@ -171,6 +176,8 @@ To be released. [#240]: https://github.com/planetarium/libplanet/pull/240 [#241]: https://github.com/planetarium/libplanet/pull/241 [#243]: https://github.com/planetarium/libplanet/pull/243 +[#246]: https://github.com/planetarium/libplanet/pull/246 +[#247]: https://github.com/planetarium/libplanet/pull/247 [#251]: https://github.com/planetarium/libplanet/pull/251 diff --git a/Libplanet.Tests/Blockchain/BlockChainTest.cs b/Libplanet.Tests/Blockchain/BlockChainTest.cs index 536a6d5f992..5149ac9faf1 100644 --- a/Libplanet.Tests/Blockchain/BlockChainTest.cs +++ b/Libplanet.Tests/Blockchain/BlockChainTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Security.Cryptography; using Libplanet.Action; using Libplanet.Blockchain; using Libplanet.Blockchain.Policies; @@ -300,8 +301,11 @@ public void AppendValidatesBlock() } [Fact] - public void CanFindNextHashes() + public void FindNextHashes() { + Assert.Empty(_blockChain.FindNextHashes( + new BlockLocator(new HashDigest[] { }) + )); _blockChain.Append(_fx.Block1); var block0 = _fx.Block1; var block1 = _blockChain.MineBlock(_fx.Address1); diff --git a/Libplanet.Tests/Net/SwarmTest.cs b/Libplanet.Tests/Net/SwarmTest.cs index 53382ec02c3..7297ea00283 100644 --- a/Libplanet.Tests/Net/SwarmTest.cs +++ b/Libplanet.Tests/Net/SwarmTest.cs @@ -83,6 +83,11 @@ public void Dispose() { s.StopAsync().Wait(DisposeTimeout); } + + if (!(Type.GetType("Mono.Runtime") is null)) + { + NetMQConfig.Cleanup(false); + } } [Fact(Timeout = Timeout)] @@ -269,51 +274,6 @@ public async Task CanExchangePeer() } } - [Fact(Timeout = Timeout)] - public async Task WorksAsCollection() - { - Swarm a = _swarms[0]; - Swarm b = _swarms[1]; - Swarm c = _swarms[2]; - - // Obtaining swarm's endpoint... - await Task.WhenAll( - StartAsync(a, _blockchains[0]), - StartAsync(b, _blockchains[1]), - StartAsync(c, _blockchains[2])); - - Assert.Empty(a); - Assert.Empty(b); - Assert.Empty(c); - - a.Add(b.AsPeer); - a.Add(c.AsPeer); - Assert.Contains(b.AsPeer, a); - Assert.Contains(c.AsPeer, a); - - Peer[] peers = null; - Assert.Throws(() => - { - a.CopyTo(peers, 0); - }); - - peers = new Peer[3]; - Assert.Throws(() => - { - a.CopyTo(peers, -1); - }); - Assert.Throws(() => - { - a.CopyTo(peers, 2); - }); - - a.CopyTo(peers, 1); - - Assert.Equal( - new HashSet { null, b.AsPeer, c.AsPeer }, - peers.ToHashSet()); - } - [Fact(Timeout = Timeout)] public async Task DetectAppProtocolVersion() { @@ -348,8 +308,8 @@ public async Task DetectAppProtocolVersion() foreach (var peer in peers) { - a.Add(peer); - b.Add(peer); + await a.AddPeersAsync(new[] { peer }); + await b.AddPeersAsync(new[] { peer }); } Assert.Equal(new[] { c.AsPeer }, a.ToArray()); @@ -391,7 +351,7 @@ void GameHandler(object sender, DifferentProtocolVersionEventArgs e) await StartAsync(a, chain); await StartAsync(b, chain); - a.Add(b.AsPeer); + await a.AddPeersAsync(new[] { b.AsPeer }); Assert.True(isCalled); } @@ -768,7 +728,7 @@ public async Task InitialBlockDownload() try { await StartAsync(minerSwarm, minerChain); - receiverSwarm.Add(minerSwarm.AsPeer); + await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer }); await StartAsync(receiverSwarm, receiverChain); @@ -810,7 +770,7 @@ public async Task Preload() try { await StartAsync(minerSwarm, minerChain); - receiverSwarm.Add(minerSwarm.AsPeer); + await receiverSwarm.AddPeersAsync(new[] { minerSwarm.AsPeer }); await receiverSwarm.PreloadAsync(receiverChain, progress); diff --git a/Libplanet/Blockchain/BlockChain.cs b/Libplanet/Blockchain/BlockChain.cs index 8a0cba9c295..53109fb6c21 100644 --- a/Libplanet/Blockchain/BlockChain.cs +++ b/Libplanet/Blockchain/BlockChain.cs @@ -445,6 +445,11 @@ internal IEnumerable> FindNextHashes( HashDigest? tip = Store.IndexBlockHash( Id.ToString(), -1); + if (tip is null) + { + yield break; + } + HashDigest? currentHash = FindBranchPoint(locator); while (currentHash != null && count > 0) diff --git a/Libplanet/Net/Swarm.cs b/Libplanet/Net/Swarm.cs index 1ee159e34e3..3bb554480c6 100644 --- a/Libplanet/Net/Swarm.cs +++ b/Libplanet/Net/Swarm.cs @@ -12,6 +12,7 @@ using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; +using AsyncIO; using Libplanet.Action; using Libplanet.Blockchain; using Libplanet.Blocks; @@ -65,6 +66,14 @@ public class Swarm : ICollection private CancellationTokenSource _workerCancellationTokenSource; private IPAddress _publicIPAddress; + static Swarm() + { + if (!(Type.GetType("Mono.Runtime") is null)) + { + ForceDotNet.Force(); + } + } + public Swarm( PrivateKey privateKey, int appProtocolVersion, @@ -243,7 +252,7 @@ public async Task> AddPeersAsync( DateTimeOffset? timestamp = null, CancellationToken cancellationToken = default(CancellationToken)) { - if (timestamp == null) + if (timestamp is null) { timestamp = DateTimeOffset.UtcNow; } @@ -306,6 +315,10 @@ public async Task> AddPeersAsync( ); } } + else + { + _peers[peer] = timestamp.Value; + } } return addedPeers; @@ -1083,9 +1096,19 @@ private async Task> SyncPreviousBlocksAsync( _logger.Debug("Trying to find branchpoint..."); BlockLocator locator = blockChain.GetBlockLocator(); _logger.Debug($"Locator's count: {locator.Count()}"); - IEnumerable> hashes = + IEnumerable> hashes = ( await GetBlockHashesAsync( - peer, locator, stop, cancellationToken); + peer, locator, stop, cancellationToken) + ).ToArray(); + + if (!hashes.Any()) + { + _logger.Debug( + $"Peer[{peer}] didn't return any hashes. " + + $"ignored."); + return blockChain; + } + HashDigest branchPoint = hashes.First(); _logger.Debug( diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 30ae3c56e62..2bfe22655e2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -98,12 +98,7 @@ jobs: configuration: $(configuration) turnServerUrl: $(turnServerUrl) testPrefix: '"$PROGRAMFILES/Mono/bin/mono.exe"' - testArguments: | - -appdomains denied \ - -noclass Libplanet.Tests.Net.SwarmTest - # FIXME: For unknown reason, on Windows + Mono SwarmTests seem never end. - # We should diagnose this and make Windows builds to run these - # tests too. + testArguments: -appdomains denied timeoutInMinutes: 30 - job: Linux_NETCore