internal void Accept(ITreeVisitor visitor, ITrieNodeResolver nodeResolver, TrieVisitContext trieVisitContext) { try { ResolveNode(nodeResolver); } catch (TrieException) { visitor.VisitMissingNode(Keccak, trieVisitContext); return; } ResolveKey(nodeResolver, trieVisitContext.Level == 0); switch (NodeType) { case NodeType.Branch: { visitor.VisitBranch(this, trieVisitContext); trieVisitContext.Level++; for (int i = 0; i < 16; i++) { TrieNode child = GetChild(nodeResolver, i); if (child != null) { child.ResolveKey(nodeResolver, false); if (visitor.ShouldVisit(child.Keccak !)) { trieVisitContext.BranchChildIndex = i; child.Accept(visitor, nodeResolver, trieVisitContext); } if (child.IsPersisted) { UnresolveChild(i); } } } trieVisitContext.Level--; trieVisitContext.BranchChildIndex = null; break; } case NodeType.Extension: { visitor.VisitExtension(this, trieVisitContext); TrieNode child = GetChild(nodeResolver, 0); if (child == null) { throw new InvalidDataException($"Child of an extension {Key} should not be null."); } child.ResolveKey(nodeResolver, false); if (visitor.ShouldVisit(child.Keccak !)) { trieVisitContext.Level++; trieVisitContext.BranchChildIndex = null; child.Accept(visitor, nodeResolver, trieVisitContext); trieVisitContext.Level--; } break; } case NodeType.Leaf: { visitor.VisitLeaf(this, trieVisitContext, Value); if (!trieVisitContext.IsStorage && trieVisitContext.ExpectAccounts) // can combine these conditions { Account account = _accountDecoder.Decode(Value.AsRlpStream()); if (account.HasCode && visitor.ShouldVisit(account.CodeHash)) { trieVisitContext.Level++; trieVisitContext.BranchChildIndex = null; visitor.VisitCode(account.CodeHash, trieVisitContext); trieVisitContext.Level--; } if (account.HasStorage && visitor.ShouldVisit(account.StorageRoot)) { trieVisitContext.IsStorage = true; TrieNode storageRoot = new(NodeType.Unknown, account.StorageRoot); trieVisitContext.Level++; trieVisitContext.BranchChildIndex = null; storageRoot.Accept(visitor, nodeResolver, trieVisitContext); trieVisitContext.Level--; trieVisitContext.IsStorage = false; } } break; } default: throw new TrieException($"An attempt was made to visit a node {Keccak} of type {NodeType}"); } }