github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/mpt/node_test.go (about)

     1  package mpt
     2  
     3  import (
     4  	"encoding/json"
     5  	"testing"
     6  
     7  	"github.com/nspcc-dev/neo-go/internal/random"
     8  	"github.com/nspcc-dev/neo-go/internal/testserdes"
     9  	"github.com/nspcc-dev/neo-go/pkg/io"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func getTestFuncEncode(ok bool, expected, actual Node) func(t *testing.T) {
    15  	return func(t *testing.T) {
    16  		t.Run("IO", func(t *testing.T) {
    17  			bs, err := testserdes.EncodeBinary(expected)
    18  			require.NoError(t, err)
    19  			if hn, ok := actual.(*HashNode); ok {
    20  				hn.hashValid = true // this field is set during NodeObject decoding
    21  			}
    22  			err = testserdes.DecodeBinary(bs, actual)
    23  			if !ok {
    24  				require.Error(t, err)
    25  				return
    26  			}
    27  			require.NoError(t, err)
    28  			require.Equal(t, expected.Type(), actual.Type())
    29  			require.Equal(t, expected.Hash(), actual.Hash())
    30  			require.Equal(t, 1+expected.Size(), len(expected.Bytes()))
    31  		})
    32  		t.Run("JSON", func(t *testing.T) {
    33  			bs, err := json.Marshal(expected)
    34  			require.NoError(t, err)
    35  			err = json.Unmarshal(bs, actual)
    36  			if !ok {
    37  				require.Error(t, err)
    38  				return
    39  			}
    40  			require.NoError(t, err)
    41  			require.Equal(t, expected.Type(), actual.Type())
    42  			require.Equal(t, expected.Hash(), actual.Hash())
    43  		})
    44  	}
    45  }
    46  
    47  func TestNode_Serializable(t *testing.T) {
    48  	t.Run("Leaf", func(t *testing.T) {
    49  		t.Run("Good", func(t *testing.T) {
    50  			l := NewLeafNode(random.Bytes(123))
    51  			t.Run("Raw", getTestFuncEncode(true, l, new(LeafNode)))
    52  			t.Run("WithType", getTestFuncEncode(true, &NodeObject{l}, new(NodeObject)))
    53  		})
    54  		t.Run("BigValue", getTestFuncEncode(false,
    55  			NewLeafNode(random.Bytes(MaxValueLength+1)), new(LeafNode)))
    56  	})
    57  
    58  	t.Run("Extension", func(t *testing.T) {
    59  		t.Run("Good", func(t *testing.T) {
    60  			e := NewExtensionNode(random.Bytes(42), NewLeafNode(random.Bytes(10)))
    61  			t.Run("Raw", getTestFuncEncode(true, e, new(ExtensionNode)))
    62  			t.Run("WithType", getTestFuncEncode(true, &NodeObject{e}, new(NodeObject)))
    63  		})
    64  		t.Run("BigKey", getTestFuncEncode(false,
    65  			NewExtensionNode(random.Bytes(maxPathLength+1), NewLeafNode(random.Bytes(10))), new(ExtensionNode)))
    66  	})
    67  
    68  	t.Run("Branch", func(t *testing.T) {
    69  		b := NewBranchNode()
    70  		b.Children[0] = NewLeafNode(random.Bytes(10))
    71  		b.Children[lastChild] = NewHashNode(random.Uint256())
    72  		t.Run("Raw", getTestFuncEncode(true, b, new(BranchNode)))
    73  		t.Run("WithType", getTestFuncEncode(true, &NodeObject{b}, new(NodeObject)))
    74  	})
    75  
    76  	t.Run("Hash", func(t *testing.T) {
    77  		t.Run("Good", func(t *testing.T) {
    78  			h := NewHashNode(random.Uint256())
    79  			t.Run("Raw", getTestFuncEncode(true, h, new(HashNode)))
    80  			t.Run("WithType", getTestFuncEncode(true, &NodeObject{h}, new(NodeObject)))
    81  		})
    82  		t.Run("InvalidSize", func(t *testing.T) {
    83  			buf := io.NewBufBinWriter()
    84  			buf.BinWriter.WriteBytes(make([]byte, 13))
    85  			require.Error(t, testserdes.DecodeBinary(buf.Bytes(), &HashNode{BaseNode: BaseNode{hashValid: true}}))
    86  		})
    87  	})
    88  
    89  	t.Run("Invalid", func(t *testing.T) {
    90  		require.Error(t, testserdes.DecodeBinary([]byte{0xFF}, new(NodeObject)))
    91  	})
    92  }
    93  
    94  // https://github.com/neo-project/neo/blob/neox-2.x/neo.UnitTests/UT_MPTTrie.cs#L198
    95  func TestJSONSharp(t *testing.T) {
    96  	tr := NewTrie(nil, ModeAll, newTestStore())
    97  	require.NoError(t, tr.Put([]byte{0xac, 0x11}, []byte{0xac, 0x11}))
    98  	require.NoError(t, tr.Put([]byte{0xac, 0x22}, []byte{0xac, 0x22}))
    99  	require.NoError(t, tr.Put([]byte{0xac}, []byte{0xac}))
   100  	require.NoError(t, tr.Delete([]byte{0xac, 0x11}))
   101  	require.NoError(t, tr.Delete([]byte{0xac, 0x22}))
   102  
   103  	js, err := tr.root.MarshalJSON()
   104  	require.NoError(t, err)
   105  	require.JSONEq(t, `{"key":"0a0c", "next":{"value":"ac"}}`, string(js))
   106  }
   107  
   108  func TestInvalidJSON(t *testing.T) {
   109  	t.Run("InvalidChildrenCount", func(t *testing.T) {
   110  		var cs [childrenCount + 1]Node
   111  		for i := range cs {
   112  			cs[i] = EmptyNode{}
   113  		}
   114  		data, err := json.Marshal(cs)
   115  		require.NoError(t, err)
   116  
   117  		var n NodeObject
   118  		require.Error(t, json.Unmarshal(data, &n))
   119  	})
   120  
   121  	testCases := []struct {
   122  		name string
   123  		data []byte
   124  	}{
   125  		{"WrongFieldCount", []byte(`{"key":"0102", "next": {}, "field": {}}`)},
   126  		{"InvalidField1", []byte(`{"next":{}}`)},
   127  		{"InvalidField2", []byte(`{"key":"0102", "hash":{}}`)},
   128  		{"InvalidKey", []byte(`{"key":"xy", "next":{}}`)},
   129  		{"InvalidNext", []byte(`{"key":"01", "next":[]}`)},
   130  		{"InvalidHash", []byte(`{"hash":"01"}`)},
   131  		{"InvalidValue", []byte(`{"value":1}`)},
   132  		{"InvalidBranch", []byte(`[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]`)},
   133  	}
   134  	for _, tc := range testCases {
   135  		var n NodeObject
   136  		assert.Errorf(t, json.Unmarshal(tc.data, &n), "no error in "+tc.name)
   137  	}
   138  }
   139  
   140  // C# interoperability test
   141  // https://github.com/neo-project/neo/blob/neox-2.x/neo.UnitTests/UT_MPTTrie.cs#L135
   142  func TestRootHash(t *testing.T) {
   143  	b := NewBranchNode()
   144  	r := NewExtensionNode([]byte{0x0A, 0x0C}, b)
   145  
   146  	v1 := NewLeafNode([]byte{0xAB, 0xCD})
   147  	l1 := NewExtensionNode([]byte{0x01}, v1)
   148  	b.Children[0] = l1
   149  
   150  	v2 := NewLeafNode([]byte{0x22, 0x22})
   151  	l2 := NewExtensionNode([]byte{0x09}, v2)
   152  	b.Children[9] = l2
   153  
   154  	r1 := NewExtensionNode([]byte{0x0A, 0x0C, 0x00, 0x01}, v1)
   155  	require.Equal(t, "cedd9897dd1559fbd5dfe5cfb223464da6de438271028afb8d647e950cbd18e0", r1.Hash().StringLE())
   156  	require.Equal(t, "1037e779c8a0313bd0d99c4151fa70a277c43c53a549b6444079f2e67e8ffb7b", r.Hash().StringLE())
   157  }