@@ -41,6 +41,7 @@ public class TrieTest {
4141 private static String doge = "doge" ;
4242 private static String test = "test" ;
4343 private static String dude = "dude" ;
44+ private static final long SHUFFLE_SEED = 0xC0FFEEL ;
4445
4546 @ Test
4647 public void test () {
@@ -64,8 +65,6 @@ public void test() {
6465 boolean result = trie
6566 .verifyProof (trieCopy .getRootHash (), new byte []{1 , 1 }, (LinkedHashMap <byte [], Node >) map );
6667 Assert .assertTrue (result );
67- System .out .println (trieCopy .prove (RLP .encodeInt (5 )));
68- System .out .println (trieCopy .prove (RLP .encodeInt (6 )));
6968 assertTrue (RLP .encodeInt (5 ), trieCopy );
7069 assertTrue (RLP .encodeInt (5 ), RLP .encodeInt (6 ), trieCopy );
7170 assertTrue (RLP .encodeInt (6 ), trieCopy );
@@ -122,16 +121,16 @@ public void test2() {
122121
123122 /*
124123 * Verifies that TrieImpl root hash is insertion-order-independent even when
125- * a key is inserted twice with the same value (idempotent put).
124+ * the same key is put more than once (idempotent put).
126125 *
127- * Covers both known-failing sequences (regression) and a random shuffle.
128- * Previously flaky due to two bugs in TrieImpl.insert():
129- * 1. commonPrefix.isEmpty() was checked before commonPrefix.equals(k), causing
130- * KVNode("",v ) to be incorrectly replaced with BranchNode{terminal:v} on
131- * duplicate put of a fully-split key — corrupting the root hash.
132- * 2. kvNodeSetValueOrNode() unconditionally marked the node dirty even when
133- * the value was unchanged, causing unnecessary hash recomputation.
134- * Both are now fixed .
126+ * Covers both known-failing sequences (regression) and a seeded random
127+ * shuffle. Previously flaky due to a correctness bug in TrieImpl.insert():
128+ * commonPrefix.isEmpty() was checked before commonPrefix.equals(k), causing
129+ * KVNode("", v_old ) to be incorrectly replaced with BranchNode{terminal:v_new}
130+ * on a duplicate put of a fully-split key — this is the actual root- hash
131+ * corruption. A separate, non-correctness optimization in
132+ * kvNodeSetValueOrNode() additionally short-circuits same- value writes to
133+ * avoid unnecessary dirty marking / hash recomputation .
135134 */
136135 @ Test
137136 public void testOrder () {
@@ -145,7 +144,12 @@ public void testOrder() {
145144 trie .put (RLP .encodeInt (10 ), String .valueOf (10 ).getBytes ());
146145 value .add (10 );
147146 byte [] rootHash1 = trie .getRootHash ();
148- Collections .shuffle (value , new Random (0xC0FFEEL ));
147+ TrieImpl baseline = new TrieImpl ();
148+ for (int i = 1 ; i < n ; i ++) {
149+ baseline .put (RLP .encodeInt (i ), String .valueOf (i ).getBytes ());
150+ }
151+ Assert .assertArrayEquals (baseline .getRootHash (), rootHash1 );
152+ Collections .shuffle (value , new Random (SHUFFLE_SEED ));
149153 assertTrieRootHash (rootHash1 , value );
150154 String [] sequences = {
151155 "95,10,66,10,67,2,98,31,85,89,81,96,19,68,44,49,43,40,62,87,4,38,17,18,8,"
@@ -206,7 +210,7 @@ private static List<Integer> parseSeq(String csv) {
206210 return result ;
207211 }
208212
209- private void assertTrieRootHash (byte [] rootHash1 , List <Integer > value ) {
213+ private static void assertTrieRootHash (byte [] rootHash1 , List <Integer > value ) {
210214 TrieImpl trie2 = new TrieImpl ();
211215 for (int i : value ) {
212216 trie2 .put (RLP .encodeInt (i ), String .valueOf (i ).getBytes ());
@@ -249,7 +253,7 @@ public void testOrderNoDuplicate() {
249253 trie .put (RLP .encodeInt (i ), String .valueOf (i ).getBytes ());
250254 }
251255 byte [] rootHash1 = trie .getRootHash ();
252- Collections .shuffle (value , new java . util . Random (42 ));
256+ Collections .shuffle (value , new Random (42 ));
253257 TrieImpl trie2 = new TrieImpl ();
254258 for (int i : value ) {
255259 trie2 .put (RLP .encodeInt (i ), String .valueOf (i ).getBytes ());
0 commit comments