From e1032752c716314be1a47ab1981931ea7529c7c6 Mon Sep 17 00:00:00 2001 From: Luis Pinto Date: Wed, 2 Oct 2024 14:32:37 +0100 Subject: [PATCH] Refactor NullNode and remove NullLeafNode class (#73) * Refactor NullNode and remove NullLeafNode class Signed-off-by: Luis Pinto Remove NullLeafNode and use NullNode instead Signed-off-by: Luis Pinto * fixup! Refactor NullNode and remove NullLeafNode class rename nullLeafNode to newNullLeafNode in NullNode Signed-off-by: Luis Pinto --------- Signed-off-by: Luis Pinto --- .../trie/verkle/VerkleTrieBatchHasher.java | 4 +- .../verkle/factory/StoredNodeFactory.java | 8 +- .../ethereum/trie/verkle/node/BranchNode.java | 8 +- .../trie/verkle/node/InternalNode.java | 6 +- .../ethereum/trie/verkle/node/LeafNode.java | 4 +- .../besu/ethereum/trie/verkle/node/Node.java | 9 ++ .../trie/verkle/node/NullLeafNode.java | 131 ------------------ .../ethereum/trie/verkle/node/NullNode.java | 61 ++++++-- .../ethereum/trie/verkle/node/StemNode.java | 10 +- .../ethereum/trie/verkle/node/StoredNode.java | 6 +- .../trie/verkle/visitor/CommitVisitor.java | 13 -- .../trie/verkle/visitor/FlattenVisitor.java | 13 +- .../trie/verkle/visitor/GetVisitor.java | 17 +-- .../trie/verkle/visitor/HashVisitor.java | 7 - .../trie/verkle/visitor/NodeVisitor.java | 11 -- .../trie/verkle/visitor/PathNodeVisitor.java | 12 -- .../trie/verkle/visitor/PutVisitor.java | 41 ++---- .../trie/verkle/visitor/RemoveVisitor.java | 25 +--- .../ethereum/trie/verkle/NodeDirtyTest.java | 3 +- 19 files changed, 112 insertions(+), 277 deletions(-) delete mode 100644 src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/NullLeafNode.java diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/VerkleTrieBatchHasher.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/VerkleTrieBatchHasher.java index abe3628..e27cfbc 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/VerkleTrieBatchHasher.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/VerkleTrieBatchHasher.java @@ -24,7 +24,6 @@ import org.hyperledger.besu.ethereum.trie.verkle.node.InternalNode; import org.hyperledger.besu.ethereum.trie.verkle.node.LeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.Node; -import org.hyperledger.besu.ethereum.trie.verkle.node.NullLeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.NullNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StemNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StoredNode; @@ -65,8 +64,7 @@ public class VerkleTrieBatchHasher { public void addNodeToBatch(final Optional maybeLocation, final Node node) { maybeLocation.ifPresent( location -> { - if ((node instanceof NullNode || node instanceof NullLeafNode) - && !location.isEmpty()) { + if (node instanceof NullNode && !location.isEmpty()) { updatedNodes.remove(location); } else { updatedNodes.put(location, node); diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/factory/StoredNodeFactory.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/factory/StoredNodeFactory.java index 5455053..41cb1d0 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/factory/StoredNodeFactory.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/factory/StoredNodeFactory.java @@ -21,7 +21,6 @@ import org.hyperledger.besu.ethereum.trie.verkle.node.InternalNode; import org.hyperledger.besu.ethereum.trie.verkle.node.LeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.Node; -import org.hyperledger.besu.ethereum.trie.verkle.node.NullLeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.NullNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StemNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StoredInternalNode; @@ -52,9 +51,6 @@ enum NodeType { * @param The type of values stored in Verkle Trie nodes. */ public class StoredNodeFactory implements NodeFactory { - - private final NullLeafNode nullLeafNode = new NullLeafNode(); - private final NodeLoader nodeLoader; private final Function valueDeserializer; private final Boolean areCommitmentsCompressed; @@ -182,7 +178,7 @@ private InternalNode createInternalNode( List> children = new ArrayList<>(nChild); for (int i = 0; i < nChild; i++) { if (scalars.get(i).compareTo(Bytes32.ZERO) == 0) { - children.add(new NullNode()); + children.add(NullNode.nullNode()); } else { if (indices.containsKey((byte) i)) { children.add( @@ -227,7 +223,7 @@ StemNode decodeStemNode(Bytes stem, Bytes encodedValues, Bytes32 hash) { List> children = new ArrayList<>(nChild); for (int i = 0; i < nChild; i++) { if (values.get(i) == Bytes.EMPTY) { - children.add(nullLeafNode); + children.add(NullNode.newNullLeafNode()); } else { children.add( createLeafNode( diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/BranchNode.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/BranchNode.java index d49d85e..f2e2598 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/BranchNode.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/BranchNode.java @@ -89,7 +89,7 @@ public BranchNode(final Bytes location) { new ArrayList<>() { { for (int i = 0; i < maxChild(); i++) { - add(new NullNode<>()); + add(NullNode.nullNode()); } } }); @@ -236,7 +236,7 @@ public String print() { public String toDot(Boolean showNullNodes) { StringBuilder result = new StringBuilder() - .append(getClass().getSimpleName()) + .append(getName()) .append(getLocation().orElse(Bytes.EMPTY)) .append(" [label=\"B: ") .append(getLocation().orElse(Bytes.EMPTY)) @@ -247,10 +247,10 @@ public String toDot(Boolean showNullNodes) { for (Node child : getChildren()) { String edgeString = - getClass().getSimpleName() + getName() + getLocation().orElse(Bytes.EMPTY) + " -> " - + child.getClass().getSimpleName() + + child.getName() + child.getLocation().orElse(Bytes.EMPTY) + "\n"; diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/InternalNode.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/InternalNode.java index 80f7607..45e288f 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/InternalNode.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/InternalNode.java @@ -196,7 +196,7 @@ public String print() { public String toDot(Boolean showNullNodes) { StringBuilder result = new StringBuilder() - .append(getClass().getSimpleName()) + .append(getName()) .append(getLocation().orElse(Bytes.EMPTY)) .append(" [label=\"I: ") .append(getLocation().orElse(Bytes.EMPTY)) @@ -206,10 +206,10 @@ public String toDot(Boolean showNullNodes) { for (Node child : getChildren()) { String edgeString = - getClass().getSimpleName() + getName() + getLocation().orElse(Bytes.EMPTY) + " -> " - + child.getClass().getSimpleName() + + child.getName() + child.getLocation().orElse(Bytes.EMPTY) + "\n"; diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/LeafNode.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/LeafNode.java index 2990900..927e5cb 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/LeafNode.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/LeafNode.java @@ -176,14 +176,14 @@ public String print() { public String toDot(Boolean showNullNodes) { Bytes locationBytes = getLocation().orElse(Bytes.EMPTY); - return getClass().getSimpleName() + return getName() + locationBytes + " [label=\"L: " + locationBytes + "\nSuffix: " + Bytes.of(locationBytes.get(locationBytes.size() - 1)) + "\"]\n" - + getClass().getSimpleName() + + getName() + locationBytes + " -> " + "Value" diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/Node.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/Node.java index 087a37d..6109965 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/Node.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/Node.java @@ -210,6 +210,15 @@ public boolean isPersisted() { */ public abstract String toDot(Boolean showNullNodes); + /** + * Gets the name for the DOT representation for the Node. + * + * @return name for the DOT representation for the Node. + */ + public String getName() { + return getClass().getSimpleName(); + } + /** * Generates DOT representation for the Node. * diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/NullLeafNode.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/NullLeafNode.java deleted file mode 100644 index 6fd3397..0000000 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/NullLeafNode.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright Hyperledger Besu Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * - */ -package org.hyperledger.besu.ethereum.trie.verkle.node; - -import org.hyperledger.besu.ethereum.trie.verkle.visitor.NodeVisitor; -import org.hyperledger.besu.ethereum.trie.verkle.visitor.PathNodeVisitor; - -import java.util.Optional; - -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; - -/** - * A special node representing a null or empty node in the Verkle Trie. - * - *

The `NullNode` class serves as a placeholder for non-existent nodes in the Verkle Trie - * structure. It implements the Node interface and represents a node that contains no information or - * value. - */ -public class NullLeafNode extends Node { - - public NullLeafNode() { - super(false, true); - } - - public NullLeafNode(Optional previousValue) { - super(false, true); - this.previous = previousValue; - } - - /** - * Accepts a visitor for path-based operations on the node. - * - * @param visitor The path node visitor. - * @param path The path associated with a node. - * @return The result of the visitor's operation. - */ - @Override - public Node accept(final PathNodeVisitor visitor, final Bytes path) { - return visitor.visit(this, path); - } - - /** - * Accepts a visitor for generic node operations. - * - * @param visitor The node visitor. - * @return The result of the visitor's operation. - */ - @Override - public Node accept(final NodeVisitor visitor) { - return visitor.visit(this); - } - - /** - * Replace node's Location - * - * @param newLocation The new location for the Node - * @return The updated Node - */ - @Override - public NullLeafNode replaceLocation(Bytes newLocation) { - return this; - } - - /** - * Get the hash associated with the `NullNode`. - * - * @return An optional containing the empty hash. - */ - @Override - public Optional getHash() { - return Optional.of(EMPTY_HASH); - } - - /** - * Get the hash associated with the `NullNode`. - * - * @return An optional containing the empty hash. - */ - @Override - public Optional getCommitment() { - return Optional.of(EMPTY_COMMITMENT); - } - - @Override - public void markDirty() { - dirty = true; - } - - /** - * Get a string representation of the `NullNode`. - * - * @return A string representation indicating that it is a "NULL" node. - */ - @Override - public String print() { - return "[NULL-LEAF]"; - } - - /** - * Generates DOT representation for the NullLeafNode. - * - * @return DOT representation of the NullLeafNode. - */ - @Override - public String toDot(Boolean showRepeatingEdges) { - if (!showRepeatingEdges) { - return ""; - } - String result = - getClass().getSimpleName() - + getLocation().orElse(Bytes.EMPTY) - + " [label=\"NL: " - + getLocation().orElse(Bytes.EMPTY) - + "\"]\n"; - return result; - } -} diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/NullNode.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/NullNode.java index ae4c443..dad93fd 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/NullNode.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/NullNode.java @@ -32,10 +32,17 @@ */ public class NullNode extends Node { - public NullNode() { + private boolean isLeaf; + + private NullNode() { super(false, true); } + private NullNode(Optional previousValue) { + super(false, true); + this.previous = previousValue; + } + /** * Accepts a visitor for path-based operations on the node. * @@ -95,6 +102,10 @@ public void markDirty() { dirty = true; } + public boolean isLeaf() { + return isLeaf; + } + /** * Get a string representation of the `NullNode`. * @@ -102,7 +113,7 @@ public void markDirty() { */ @Override public String print() { - return "[NULL]"; + return isLeaf() ? "[NULL-LEAF]" : "[NULL]"; } /** @@ -115,12 +126,44 @@ public String toDot(Boolean showRepeatingEdges) { if (!showRepeatingEdges) { return ""; } - String result = - getClass().getSimpleName() - + getLocation().orElse(Bytes.EMPTY) - + " [label=\"NL: " - + getLocation().orElse(Bytes.EMPTY) - + "\"]\n"; - return result; + return getName() + + getLocation().orElse(Bytes.EMPTY) + + " [label=\"NL: " + + getLocation().orElse(Bytes.EMPTY) + + "\"]\n"; + } + + @Override + public String getName() { + return isLeaf() ? "NullLeafNode" : "NullNode"; + } + + @SuppressWarnings("rawtypes") + private static NullNode nullLeafNode; + + @SuppressWarnings("rawtypes") + private static NullNode nullNode; + + @SuppressWarnings("unchecked") + public static NullNode nullNode() { + if (nullNode == null) { + nullNode = new NullNode<>(); + } + return nullNode; + } + + @SuppressWarnings("unchecked") + public static NullNode newNullLeafNode() { + if (nullLeafNode == null) { + nullLeafNode = new NullNode<>(); + nullLeafNode.isLeaf = true; + } + return nullLeafNode; + } + + public static NullNode newNullLeafNode(Optional previousValue) { + NullNode nullLeafNode = new NullNode<>(previousValue); + nullLeafNode.isLeaf = true; + return nullLeafNode; } } diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/StemNode.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/StemNode.java index 0c03aa8..f8c2d3a 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/StemNode.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/StemNode.java @@ -116,7 +116,7 @@ public StemNode( public StemNode(final Bytes location, final Bytes stem) { super(location); for (int i = 0; i < maxChild(); i++) { - NullLeafNode nullLeafNode = new NullLeafNode(); + NullNode nullLeafNode = NullNode.newNullLeafNode(); replaceChild((byte) i, nullLeafNode); } this.stem = extractStem(stem); @@ -294,7 +294,7 @@ public String print() { builder.append(String.format("Stem: %s", stem)); for (int i = 0; i < maxChild(); i++) { final Node child = child((byte) i); - if (!(child instanceof NullNode) && !(child instanceof NullLeafNode)) { + if (!(child instanceof NullNode)) { final String label = String.format("[%02x] ", i); final String childRep = child.print().replaceAll("\n ", "\n "); builder.append("\n ").append(label).append(childRep); @@ -311,7 +311,7 @@ private Bytes extractStem(final Bytes stemValue) { public String toDot(Boolean showNullNodes) { StringBuilder result = new StringBuilder() - .append(getClass().getSimpleName()) + .append(getName()) .append(getLocation().orElse(Bytes.EMPTY)) .append(" [label=\"S: ") .append(getLocation().orElse(Bytes.EMPTY)) @@ -325,10 +325,10 @@ public String toDot(Boolean showNullNodes) { for (Node child : getChildren()) { String edgeString = - getClass().getSimpleName() + getName() + getLocation().orElse(Bytes.EMPTY) + " -> " - + child.getClass().getSimpleName() + + child.getName() + child.getLocation().orElse(Bytes.EMPTY) + "\n"; diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/StoredNode.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/StoredNode.java index ff09e59..a01b791 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/StoredNode.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/node/StoredNode.java @@ -187,7 +187,7 @@ public String print() { @Override public String toDot(Boolean showNullNodes) { String result = - getClass().getSimpleName() + getName() + getLocation().orElse(Bytes.EMPTY) + " [label=\"SD: " + getLocation().orElse(Bytes.EMPTY) @@ -206,9 +206,9 @@ Node load() { if (loadedNode.isPresent()) { return loadedNode.get(); } else if (location.size() == 32) { - return new NullLeafNode<>(); + return NullNode.newNullLeafNode(); } else { - return new NullNode<>(); + return NullNode.nullNode(); } } } diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/CommitVisitor.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/CommitVisitor.java index 545a237..1dad6c6 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/CommitVisitor.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/CommitVisitor.java @@ -19,7 +19,6 @@ import org.hyperledger.besu.ethereum.trie.verkle.node.InternalNode; import org.hyperledger.besu.ethereum.trie.verkle.node.LeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.Node; -import org.hyperledger.besu.ethereum.trie.verkle.node.NullLeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.NullNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StemNode; @@ -125,16 +124,4 @@ public Node visit(final LeafNode leafNode, final Bytes location) { public Node visit(final NullNode nullNode, final Bytes location) { return nullNode; } - - /** - * Visits a NullLeafNode, indicating no changes to commit. - * - * @param nullLeafNode The NullLeafNode being visited. - * @param location The location in the Trie tree. - * @return The NullLeafNode indicating no changes. - */ - @Override - public Node visit(final NullLeafNode nullLeafNode, final Bytes location) { - return nullLeafNode; - } } diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/FlattenVisitor.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/FlattenVisitor.java index bedbaea..88e4b2f 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/FlattenVisitor.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/FlattenVisitor.java @@ -18,7 +18,6 @@ import org.hyperledger.besu.ethereum.trie.verkle.VerkleTrieBatchHasher; import org.hyperledger.besu.ethereum.trie.verkle.node.InternalNode; import org.hyperledger.besu.ethereum.trie.verkle.node.Node; -import org.hyperledger.besu.ethereum.trie.verkle.node.NullLeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.NullNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StemNode; @@ -45,7 +44,7 @@ public FlattenVisitor(final Optional batchProcessor) { @Override public Node visit(InternalNode internalNode) { - return new NullNode<>(); + return NullNode.nullNode(); } @Override @@ -54,20 +53,22 @@ public Node visit(StemNode stemNode) { final Bytes newLocation = location.slice(0, location.size() - 1); // Should not flatten root node if (newLocation.isEmpty()) { - return new NullNode<>(); + return NullNode.nullNode(); } final StemNode updateStemNode = stemNode.replaceLocation(newLocation); updateStemNode.markDirty(); batchProcessor.ifPresent( processor -> { - final NullNode nullNode = new NullNode<>(); + final NullNode nullNode = NullNode.nullNode(); nullNode.markDirty(); processor.addNodeToBatch(stemNode.getLocation(), nullNode); processor.addNodeToBatch(updateStemNode.getLocation(), updateStemNode); for (int i = 0; i < StemNode.maxChild(); i++) { Byte index = Bytes.of(i).get(0); - if (!(stemNode.child(index) instanceof NullLeafNode)) { - final NullLeafNode childNullNode = new NullLeafNode<>(); + boolean isNullLeafNode = + stemNode.child(index) instanceof NullNode nullLeafNode && nullLeafNode.isLeaf(); + if (!isNullLeafNode) { + final NullNode childNullNode = NullNode.newNullLeafNode(); childNullNode.markDirty(); processor.addNodeToBatch(stemNode.child(index).getLocation(), childNullNode); processor.addNodeToBatch( diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/GetVisitor.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/GetVisitor.java index 03d9b4a..e2e8595 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/GetVisitor.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/GetVisitor.java @@ -17,7 +17,6 @@ import org.hyperledger.besu.ethereum.trie.verkle.node.InternalNode; import org.hyperledger.besu.ethereum.trie.verkle.node.Node; -import org.hyperledger.besu.ethereum.trie.verkle.node.NullLeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.NullNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StemNode; @@ -30,8 +29,6 @@ */ public class GetVisitor implements PathNodeVisitor { - private final Node NULL_LEAF_NODE = new NullLeafNode<>(); - /** * Visits a internalNode to determine the node matching a given path. * @@ -57,7 +54,7 @@ public Node visit(final StemNode stemNode, final Bytes path) { final Bytes extension = stemNode.getPathExtension().get(); final int prefix = path.commonPrefixLength(extension); if (prefix < extension.size()) { - return NULL_LEAF_NODE; + return NullNode.newNullLeafNode(); } final byte childIndex = path.get(prefix); // extract suffix return stemNode.child(childIndex).accept(this, path.slice(prefix + 1)); @@ -74,16 +71,4 @@ public Node visit(final StemNode stemNode, final Bytes path) { public Node visit(NullNode nullNode, Bytes path) { return nullNode; } - - /** - * Visits a NullLeafNode to determine the matching node based on a given path. - * - * @param nullLeafNode The NullLeafNode being visited. - * @param path The path to search in the tree. - * @return NullLeafNode represents a missing leaf node on the path. - */ - @Override - public Node visit(NullLeafNode nullLeafNode, Bytes path) { - return nullLeafNode; - } } diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/HashVisitor.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/HashVisitor.java index 5a8b4f0..d706ced 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/HashVisitor.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/HashVisitor.java @@ -24,7 +24,6 @@ import org.hyperledger.besu.ethereum.trie.verkle.node.InternalNode; import org.hyperledger.besu.ethereum.trie.verkle.node.LeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.Node; -import org.hyperledger.besu.ethereum.trie.verkle.node.NullLeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.NullNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StemNode; @@ -136,10 +135,4 @@ public Node visit(final NullNode nullNode, final Bytes path) { nullNode.markClean(); return nullNode; } - - @Override - public Node visit(final NullLeafNode nullLeafNode, final Bytes path) { - nullLeafNode.markClean(); - return nullLeafNode; - } } diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/NodeVisitor.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/NodeVisitor.java index b6915a9..72e3bc8 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/NodeVisitor.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/NodeVisitor.java @@ -18,7 +18,6 @@ import org.hyperledger.besu.ethereum.trie.verkle.node.InternalNode; import org.hyperledger.besu.ethereum.trie.verkle.node.LeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.Node; -import org.hyperledger.besu.ethereum.trie.verkle.node.NullLeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.NullNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StemNode; @@ -68,14 +67,4 @@ default Node visit(LeafNode leafNode) { default Node visit(NullNode nullNode) { return nullNode; } - - /** - * Visits a null leaf node. - * - * @param nullLeafNode The null node to visit. - * @return The result of visiting the null node. - */ - default Node visit(NullLeafNode nullLeafNode) { - return nullLeafNode; - } } diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/PathNodeVisitor.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/PathNodeVisitor.java index 30b4fe6..ba5018b 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/PathNodeVisitor.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/PathNodeVisitor.java @@ -18,7 +18,6 @@ import org.hyperledger.besu.ethereum.trie.verkle.node.InternalNode; import org.hyperledger.besu.ethereum.trie.verkle.node.LeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.Node; -import org.hyperledger.besu.ethereum.trie.verkle.node.NullLeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.NullNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StemNode; @@ -75,15 +74,4 @@ default Node visit(LeafNode leafNode, Bytes path) { default Node visit(NullNode nullNode, Bytes path) { return nullNode; } - - /** - * Visits a null leaf node with a specified path. - * - * @param nullLeafNode The null leaf node to visit. - * @param path The path associated with the visit. - * @return The result of visiting the null node. - */ - default Node visit(NullLeafNode nullLeafNode, Bytes path) { - return nullLeafNode; - } } diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/PutVisitor.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/PutVisitor.java index 4eb4a28..2748392 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/PutVisitor.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/PutVisitor.java @@ -19,7 +19,6 @@ import org.hyperledger.besu.ethereum.trie.verkle.node.InternalNode; import org.hyperledger.besu.ethereum.trie.verkle.node.LeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.Node; -import org.hyperledger.besu.ethereum.trie.verkle.node.NullLeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.NullNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StemNode; @@ -68,7 +67,7 @@ public Node visit(final InternalNode internalNode, final Bytes path) { visited = Bytes.concatenate(visited, Bytes.of(index)); final Node child = internalNode.child(index); final Node updatedChild = child.accept(this, path.slice(1)); - if (child instanceof NullNode || child instanceof NullLeafNode) { + if (child instanceof NullNode) { batchProcessor.ifPresent( processor -> processor.addNodeToBatch(updatedChild.getLocation(), updatedChild)); } @@ -100,7 +99,7 @@ public Node visit(final StemNode stemNode, final Bytes path) { visited = Bytes.concatenate(visited, Bytes.of(index)); final Node child = stemNode.child(index); final Node updatedChild = stemNode.child(index).accept(this, path.slice(1)); - if (child instanceof NullNode || child instanceof NullLeafNode) { + if (child instanceof NullNode) { // This call may lead to the removal of the node from the batch if a null node // is inserted. batchProcessor.ifPresent( @@ -166,33 +165,23 @@ public Node visit(final LeafNode leafNode, final Bytes path) { @Override public Node visit(final NullNode nullNode, final Bytes path) { assert path.size() < 33; + Node newNode = createNode(nullNode, path); + batchProcessor.ifPresent(processor -> processor.addNodeToBatch(newNode.getLocation(), newNode)); + newNode.markDirty(); + return newNode; + } + + private Node createNode(final NullNode nullNode, final Bytes path) { + if (nullNode.isLeaf()) { + oldValue = Optional.empty(); + visited = Bytes.concatenate(visited, path.slice(path.size())); + return new LeafNode<>(visited, value); + } // Replace NullNode with a StemNode and visit it final Bytes leafKey = Bytes.concatenate(visited, path); final StemNode stemNode = new StemNode(visited, leafKey); stemNode.getChildren().forEach(Node::markDirty); - final Node updatedNode = stemNode.accept(this, path); - batchProcessor.ifPresent( - processor -> processor.addNodeToBatch(updatedNode.getLocation(), updatedNode)); - updatedNode.markDirty(); - return updatedNode; - } - - /** - * Visits a null leaf node to insert a value associated with the provided path. - * - * @param nullLeafNode The null leaf node to visit. - * @param path The path associated with the value to insert or update. - * @return A new leaf node containing the inserted or updated value. - */ - @Override - public Node visit(final NullLeafNode nullLeafNode, final Bytes path) { - assert path.size() < 33; - oldValue = Optional.empty(); - visited = Bytes.concatenate(visited, path.slice(path.size())); - LeafNode newNode = new LeafNode<>(visited, value); - batchProcessor.ifPresent(processor -> processor.addNodeToBatch(newNode.getLocation(), newNode)); - newNode.markDirty(); - return newNode; + return stemNode.accept(this, path); } /** diff --git a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/RemoveVisitor.java b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/RemoveVisitor.java index 927e5ee..f6d2f70 100644 --- a/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/RemoveVisitor.java +++ b/src/main/java/org/hyperledger/besu/ethereum/trie/verkle/visitor/RemoveVisitor.java @@ -19,7 +19,6 @@ import org.hyperledger.besu.ethereum.trie.verkle.node.InternalNode; import org.hyperledger.besu.ethereum.trie.verkle.node.LeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.Node; -import org.hyperledger.besu.ethereum.trie.verkle.node.NullLeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.NullNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StemNode; @@ -60,7 +59,7 @@ public Node visit(InternalNode internalNode, Bytes path) { final byte index = path.get(0); final Node child = internalNode.child(index); final Node updatedChild = child.accept(this, path.slice(1)); - if (child instanceof NullNode || child instanceof NullLeafNode) { + if (child instanceof NullNode) { batchProcessor.ifPresent( processor -> processor.addNodeToBatch(updatedChild.getLocation(), updatedChild)); } @@ -101,13 +100,14 @@ public Node visit(StemNode stemNode, Bytes path) { final Node updatedChild = child.accept(this, path); stemNode.replaceChild(childIndex, updatedChild); if (allLeavesAreNull(stemNode)) { - final NullNode nullNode = new NullNode<>(); + final NullNode nullNode = NullNode.nullNode(); nullNode.markDirty(); batchProcessor.ifPresent( processor -> processor.addNodeToBatch(stemNode.getLocation(), nullNode)); return nullNode; } - if (!(child instanceof NullLeafNode)) { // Removed a genuine leaf-node + boolean isNullLeafNode = child instanceof NullNode nullLeafNode && nullLeafNode.isLeaf(); + if (!isNullLeafNode) { // Removed a genuine leaf-node batchProcessor.ifPresent( processor -> processor.addNodeToBatch(stemNode.getLocation(), stemNode)); stemNode.markDirty(); @@ -125,7 +125,7 @@ public Node visit(StemNode stemNode, Bytes path) { */ @Override public Node visit(LeafNode leafNode, Bytes path) { - final NullLeafNode nullLeafNode = new NullLeafNode<>(leafNode.getPrevious()); + final NullNode nullLeafNode = NullNode.newNullLeafNode(leafNode.getPrevious()); nullLeafNode.markDirty(); batchProcessor.ifPresent( processor -> processor.addNodeToBatch(leafNode.getLocation(), nullLeafNode)); @@ -144,18 +144,6 @@ public Node visit(NullNode nullNode, Bytes path) { return nullNode; } - /** - * Visits a null leaf node and returns a null node, indicating that no removal is required. - * - * @param nullLeafNode The null node to visit. - * @param path The path associated with the removal (no operation). - * @return A null node, indicating no removal is needed. - */ - @Override - public Node visit(NullLeafNode nullLeafNode, Bytes path) { - return nullLeafNode; - } - /** * Finds the index of the only non-null child in the list of children nodes. * @@ -183,7 +171,8 @@ boolean allLeavesAreNull(final StemNode stemNode) { Node child = children.get(i).accept(getter, Bytes.EMPTY); // forces to load node if StoredNode; stemNode.replaceChild((byte) i, child); - if (!(child instanceof NullLeafNode)) { + boolean isNullLeafNode = child instanceof NullNode nullLeafNode && nullLeafNode.isLeaf(); + if (!isNullLeafNode) { return false; } } diff --git a/src/test/java/org/hyperledger/besu/ethereum/trie/verkle/NodeDirtyTest.java b/src/test/java/org/hyperledger/besu/ethereum/trie/verkle/NodeDirtyTest.java index e5871f7..e205e4b 100644 --- a/src/test/java/org/hyperledger/besu/ethereum/trie/verkle/NodeDirtyTest.java +++ b/src/test/java/org/hyperledger/besu/ethereum/trie/verkle/NodeDirtyTest.java @@ -22,7 +22,6 @@ import org.hyperledger.besu.ethereum.trie.verkle.factory.StoredNodeFactory; import org.hyperledger.besu.ethereum.trie.verkle.node.InternalNode; import org.hyperledger.besu.ethereum.trie.verkle.node.Node; -import org.hyperledger.besu.ethereum.trie.verkle.node.NullLeafNode; import org.hyperledger.besu.ethereum.trie.verkle.node.NullNode; import org.hyperledger.besu.ethereum.trie.verkle.node.StemNode; @@ -303,7 +302,7 @@ public void testSixValues() { */ private List> collectNodes( Node node, String path, List> nodes) { - if (node instanceof NullNode || node instanceof NullLeafNode) { + if (node instanceof NullNode) { return nodes; }