planetarium / libplanet

Blockchain in C#/.NET for on-chain, decentralized gaming
https://docs.libplanet.io/
GNU Lesser General Public License v2.1
506 stars 142 forks source link

Append Failed. exception: System.ArgumentNullException: Value cannot be null #454

Closed earlbread closed 5 years ago

earlbread commented 5 years ago
8/22/2019 6:13:53 PM +09:00: Branchpoint is "04c93b80089cfb5c28036ac513c6200337c3ed1f8319d90f6327fb6fc62a0000".                                                                                                                                                      [680/82069]
8/22/2019 6:13:53 PM +09:00: Forking needed. Trying to fork...
8/22/2019 6:13:53 PM +09:00: Trying to distribute own delta (+0, -0)...
8/22/2019 6:13:54 PM +09:00: A raw message [frame count: 7] has received.
8/22/2019 6:13:54 PM +09:00: A message has parsed: "Libplanet.Net.Messages.BlockHashes"
8/22/2019 6:13:54 PM +09:00: Trying to GetBlocksAsync() (using 1 hashes)
8/22/2019 6:13:54 PM +09:00: Required block count: 1. System.Threading.CancellationToken
8/22/2019 6:13:54 PM +09:00: Starts to receive blocks from "0xd3C39761CE5977324009414643394c4b7381a7eA.Unspecified/localhost:59876.".
8/22/2019 6:13:54 PM +09:00: Received 1 blocks from "0xd3C39761CE5977324009414643394c4b7381a7eA.Unspecified/localhost:59876.".
8/22/2019 6:13:54 PM +09:00: GetBlocksAsync() complete.
8/22/2019 6:13:54 PM +09:00: Trying to fill up previous blocks...
8/22/2019 6:13:54 PM +09:00: Append Failed. exception: System.ArgumentNullException: Value cannot be null.
Parameter name: source
  at System.Linq.Enumerable.Select[TSource,TResult] (System.Collections.Generic.IEnumerable`1[T] source, System.Func`2[T,TResult] selector) [0x0000d] in <3e4da02cf86b4fc686ed0ac61bffc210>:0
  at Libplanet.Blockchain.BlockChain`1[T].Fork (Libplanet.HashDigest`1[T] point) [0x00127] in <acd9bdd9fbbd4121870ea1ccd40faf01>:0
  at Libplanet.Net.Swarm`1+<SyncPreviousBlocksAsync>d__97[T].MoveNext () [0x001c3] in <acd9bdd9fbbd4121870ea1ccd40faf01>:0
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at Libplanet.Net.Swarm`1+<AppendBlocksAsync>d__98[T].MoveNext () [0x000dc] in <acd9bdd9fbbd4121870ea1ccd40faf01>:0
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at Libplanet.Net.Swarm`1+<ProcessBlockHashes>d__96[T].MoveNext () [0x00227] in <acd9bdd9fbbd4121870ea1ccd40faf01>:0
System.ArgumentNullException: Value cannot be null.
Parameter name: source
  at System.Linq.Enumerable.Select[TSource,TResult] (System.Collections.Generic.IEnumerable`1[T] source, System.Func`2[T,TResult] selector) [0x0000d] in <3e4da02cf86b4fc686ed0ac61bffc210>:0
  at Libplanet.Blockchain.BlockChain`1[T].Fork (Libplanet.HashDigest`1[T] point) [0x00127] in <acd9bdd9fbbd4121870ea1ccd40faf01>:0
  at Libplanet.Net.Swarm`1+<SyncPreviousBlocksAsync>d__97[T].MoveNext () [0x001c3] in <acd9bdd9fbbd4121870ea1ccd40faf01>:0
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at Libplanet.Net.Swarm`1+<AppendBlocksAsync>d__98[T].MoveNext () [0x000dc] in <acd9bdd9fbbd4121870ea1ccd40faf01>:0
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <1f0c1ef1ad524c38bbc5536809c46b48>:0
  at Libplanet.Net.Swarm`1+<ProcessBlockHashes>d__96[T].MoveNext () [0x00227] in <acd9bdd9fbbd4121870ea1ccd40faf01>:0
8/22/2019 6:13:54 PM +09:00: Trying to find branchpoint...
8/22/2019 6:13:54 PM +09:00: Something went wrong during message parsing: System.ArgumentNullException: Value cannot be null.
dahlia commented 5 years ago

I guess this happens at the following code:

https://github.com/planetarium/libplanet/blob/a158cfa6b4b8fede4ea4b14bc757f4439e944119/Libplanet/Blockchain/BlockChain.cs#L838-L841

… because IStore.GetBlockStates() method became able to return null to represent an absence of states (i.e., incomplete states) since the patch #285. So if my hypotheses is valid we can reproduce this by trying to fork a chain filled by downloading pre-calculated states from a trusted peer.

dahlia commented 5 years ago

Easily reproduced:

[Fact]
public void ForkChainWithIncompleteBlockStates()
{
    (_, _, BlockChain<DumbAction> chain) = MakeIncompleteBlockStates();
    BlockChain<DumbAction> forked = chain.Fork(chain[5].Hash);
    Assert.Equal(chain.Take(6), forked);
}