@@ -620,3 +620,162 @@ func TestBinaryTrieWitness(t *testing.T) {
620620 t .Fatal ("unexpected witness value for path2" )
621621 }
622622}
623+
624+ // testAccount is a helper that creates a BinaryTrie with a tracer and
625+ // inserts a single account, returning the trie.
626+ func testAccount (t * testing.T , addr common.Address , nonce uint64 , balance uint64 ) * BinaryTrie {
627+ t .Helper ()
628+ tr := & BinaryTrie {
629+ root : NewBinaryNode (),
630+ tracer : trie .NewPrevalueTracer (),
631+ }
632+ acc := & types.StateAccount {
633+ Nonce : nonce ,
634+ Balance : uint256 .NewInt (balance ),
635+ CodeHash : types .EmptyCodeHash [:],
636+ }
637+ if err := tr .UpdateAccount (addr , acc , 0 ); err != nil {
638+ t .Fatalf ("UpdateAccount error: %v" , err )
639+ }
640+ return tr
641+ }
642+
643+ // TestGetAccountNonMembershipStemRoot verifies that querying a non-existent
644+ // address returns nil when the trie root is a StemNode (single-account trie).
645+ // This is a regression test: previously the StemNode branch in GetAccount
646+ // returned the root's values without verifying the stem.
647+ func TestGetAccountNonMembershipStemRoot (t * testing.T ) {
648+ addr := common .HexToAddress ("0x1111111111111111111111111111111111111111" )
649+ tr := testAccount (t , addr , 42 , 100 )
650+
651+ // Verify root is a StemNode (single stem inserted).
652+ if _ , ok := tr .root .(* StemNode ); ! ok {
653+ t .Fatalf ("expected StemNode root, got %T" , tr .root )
654+ }
655+
656+ // Query a completely different address — must return nil.
657+ other := common .HexToAddress ("0x2222222222222222222222222222222222222222" )
658+ got , err := tr .GetAccount (other )
659+ if err != nil {
660+ t .Fatalf ("GetAccount error: %v" , err )
661+ }
662+ if got != nil {
663+ t .Fatalf ("expected nil for non-existent account, got nonce=%d balance=%s" , got .Nonce , got .Balance )
664+ }
665+
666+ // Original account must still be retrievable.
667+ got , err = tr .GetAccount (addr )
668+ if err != nil {
669+ t .Fatalf ("GetAccount(original) error: %v" , err )
670+ }
671+ if got == nil {
672+ t .Fatal ("expected original account, got nil" )
673+ }
674+ if got .Nonce != 42 {
675+ t .Fatalf ("expected nonce=42, got %d" , got .Nonce )
676+ }
677+ }
678+
679+ // TestGetAccountNonMembershipInternalRoot verifies that querying a non-existent
680+ // address returns nil when the trie root is an InternalNode (multi-account trie).
681+ func TestGetAccountNonMembershipInternalRoot (t * testing.T ) {
682+ tr := & BinaryTrie {
683+ root : NewBinaryNode (),
684+ tracer : trie .NewPrevalueTracer (),
685+ }
686+
687+ // Insert two accounts whose binary tree keys have different first bits
688+ // so the root splits into an InternalNode.
689+ addr1 := common .HexToAddress ("0x1111111111111111111111111111111111111111" )
690+ addr2 := common .HexToAddress ("0x9999999999999999999999999999999999999999" )
691+ for _ , addr := range []common.Address {addr1 , addr2 } {
692+ acc := & types.StateAccount {
693+ Nonce : 1 ,
694+ Balance : uint256 .NewInt (1 ),
695+ CodeHash : types .EmptyCodeHash [:],
696+ }
697+ if err := tr .UpdateAccount (addr , acc , 0 ); err != nil {
698+ t .Fatalf ("UpdateAccount error: %v" , err )
699+ }
700+ }
701+
702+ // Verify root is an InternalNode.
703+ if _ , ok := tr .root .(* InternalNode ); ! ok {
704+ t .Fatalf ("expected InternalNode root, got %T" , tr .root )
705+ }
706+
707+ // Query a non-existent address — must return nil.
708+ other := common .HexToAddress ("0x5555555555555555555555555555555555555555" )
709+ got , err := tr .GetAccount (other )
710+ if err != nil {
711+ t .Fatalf ("GetAccount error: %v" , err )
712+ }
713+ if got != nil {
714+ t .Fatalf ("expected nil for non-existent account, got nonce=%d" , got .Nonce )
715+ }
716+ }
717+
718+ // TestGetStorageNonMembershipStemRoot verifies that querying storage for a
719+ // non-existent address returns nil when the root is a StemNode. This is a
720+ // regression test: previously StemNode.Get panicked unconditionally.
721+ func TestGetStorageNonMembershipStemRoot (t * testing.T ) {
722+ addr := common .HexToAddress ("0x1111111111111111111111111111111111111111" )
723+ tr := testAccount (t , addr , 1 , 100 )
724+
725+ // Verify root is a StemNode.
726+ if _ , ok := tr .root .(* StemNode ); ! ok {
727+ t .Fatalf ("expected StemNode root, got %T" , tr .root )
728+ }
729+
730+ // Query storage for a different address — must return nil, not panic.
731+ other := common .HexToAddress ("0x2222222222222222222222222222222222222222" )
732+ slot := common .HexToHash ("0x01" )
733+ got , err := tr .GetStorage (other , slot [:])
734+ if err != nil {
735+ t .Fatalf ("GetStorage error: %v" , err )
736+ }
737+ if len (got ) > 0 && ! bytes .Equal (got , zero [:]) {
738+ t .Fatalf ("expected nil/zero for non-existent storage, got %x" , got )
739+ }
740+ }
741+
742+ // TestGetStorageNonMembershipInternalRoot verifies that querying storage for a
743+ // non-existent address returns nil when the root is an InternalNode.
744+ func TestGetStorageNonMembershipInternalRoot (t * testing.T ) {
745+ tr := & BinaryTrie {
746+ root : NewBinaryNode (),
747+ tracer : trie .NewPrevalueTracer (),
748+ }
749+
750+ addr := common .HexToAddress ("0x1234567890abcdef1234567890abcdef12345678" )
751+ acc := & types.StateAccount {
752+ Nonce : 1 ,
753+ Balance : uint256 .NewInt (1000 ),
754+ CodeHash : types .EmptyCodeHash [:],
755+ }
756+ if err := tr .UpdateAccount (addr , acc , 0 ); err != nil {
757+ t .Fatalf ("UpdateAccount error: %v" , err )
758+ }
759+
760+ // Add a storage slot so the root becomes an InternalNode (storage
761+ // slots use a different stem than account data).
762+ slot := common .HexToHash ("0xFF" )
763+ val := common .TrimLeftZeroes (common .HexToHash ("0xdeadbeef" ).Bytes ())
764+ if err := tr .UpdateStorage (addr , slot [:], val ); err != nil {
765+ t .Fatalf ("UpdateStorage error: %v" , err )
766+ }
767+
768+ if _ , ok := tr .root .(* InternalNode ); ! ok {
769+ t .Fatalf ("expected InternalNode root, got %T" , tr .root )
770+ }
771+
772+ // Query storage for a non-existent address — must return nil.
773+ other := common .HexToAddress ("0x9999999999999999999999999999999999999999" )
774+ got , err := tr .GetStorage (other , slot [:])
775+ if err != nil {
776+ t .Fatalf ("GetStorage error: %v" , err )
777+ }
778+ if len (got ) > 0 && ! bytes .Equal (got , zero [:]) {
779+ t .Fatalf ("expected nil/zero for non-existent storage, got %x" , got )
780+ }
781+ }
0 commit comments