github.com/koko1123/flow-go-1@v0.29.6/ledger/complete/mtrie/flattener/encoding_v4_test.go (about) 1 package flattener_test 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 12 "github.com/koko1123/flow-go-1/ledger" 13 "github.com/koko1123/flow-go-1/ledger/common/hash" 14 "github.com/koko1123/flow-go-1/ledger/common/testutils" 15 "github.com/koko1123/flow-go-1/ledger/complete/mtrie/flattener" 16 "github.com/koko1123/flow-go-1/ledger/complete/mtrie/node" 17 "github.com/koko1123/flow-go-1/ledger/complete/mtrie/trie" 18 ) 19 20 func TestLeafNodeV4Decoding(t *testing.T) { 21 22 // Leaf node with nil payload 23 path1 := testutils.PathByUint8(0) 24 payload1 := (*ledger.Payload)(nil) 25 hashValue1 := hash.Hash([32]byte{1, 1, 1}) 26 leafNodeNilPayload := node.NewNode(255, nil, nil, ledger.Path(path1), payload1, hashValue1) 27 28 // Leaf node with empty payload (not nil) 29 // EmptyPayload() not used because decoded playload's value is empty slice (not nil) 30 path2 := testutils.PathByUint8(1) 31 payload2 := ledger.NewPayload(ledger.Key{}, []byte{}) 32 hashValue2 := hash.Hash([32]byte{2, 2, 2}) 33 leafNodeEmptyPayload := node.NewNode(255, nil, nil, ledger.Path(path2), payload2, hashValue2) 34 35 // Leaf node with payload 36 path3 := testutils.PathByUint8(2) 37 payload3 := testutils.LightPayload8('A', 'a') 38 hashValue3 := hash.Hash([32]byte{3, 3, 3}) 39 leafNodePayload := node.NewNode(255, nil, nil, ledger.Path(path3), payload3, hashValue3) 40 41 encodedLeafNodeNilPayload := []byte{ 42 0x00, // node type 43 0x00, 0xff, // height 44 0x00, 0x00, // max depth 45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // reg count 46 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hash data 50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // path data 54 0x00, 0x00, 0x00, 0x00, // payload data len 55 } 56 57 encodedLeafNodeEmptyPayload := []byte{ 58 0x00, // node type 59 0x00, 0xff, // height 60 0x00, 0x00, // max depth 61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // reg count 62 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hash data 66 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 69 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // path data 70 0x00, 0x00, 0x00, 0x0e, // payload data len 71 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // payload data 73 } 74 75 encodedLeafNodePayload := []byte{ 76 0x00, // node type 77 0x00, 0xff, // height 78 0x00, 0x00, // max depth 79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // reg count 80 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hash data 84 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // path data 88 0x00, 0x00, 0x00, 0x16, // payload data len 89 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 90 0x00, 0x03, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 91 0x00, 0x00, 0x00, 0x00, 0x01, 0x61, // payload data 92 } 93 94 testCases := []struct { 95 name string 96 node *node.Node 97 encodedNode []byte 98 }{ 99 {"nil payload", leafNodeNilPayload, encodedLeafNodeNilPayload}, 100 {"empty payload", leafNodeEmptyPayload, encodedLeafNodeEmptyPayload}, 101 {"payload", leafNodePayload, encodedLeafNodePayload}, 102 } 103 104 for _, tc := range testCases { 105 t.Run("decode "+tc.name, func(t *testing.T) { 106 scratchBuffers := [][]byte{ 107 nil, 108 make([]byte, 0), 109 make([]byte, 16), 110 make([]byte, 1024), 111 } 112 113 for _, scratch := range scratchBuffers { 114 reader := bytes.NewReader(tc.encodedNode) 115 newNode, regCount, regSize, err := flattener.ReadNodeFromCheckpointV4(reader, scratch, func(nodeIndex uint64) (*node.Node, uint64, uint64, error) { 116 return nil, 0, 0, fmt.Errorf("no call expected") 117 }) 118 require.NoError(t, err) 119 assert.Equal(t, tc.node, newNode) 120 assert.Equal(t, 0, reader.Len()) 121 require.Equal(t, uint64(1), regCount) 122 require.Equal(t, uint64(tc.node.Payload().Size()), regSize) 123 } 124 }) 125 } 126 } 127 128 func TestInterimNodeV4Decoding(t *testing.T) { 129 130 const lchildIndex = 1 131 const rchildIndex = 2 132 133 // Child node 134 path1 := testutils.PathByUint8(0) 135 payload1 := testutils.LightPayload8('A', 'a') 136 hashValue1 := hash.Hash([32]byte{1, 1, 1}) 137 leafNode1 := node.NewNode(255, nil, nil, ledger.Path(path1), payload1, hashValue1) 138 139 // Child node 140 path2 := testutils.PathByUint8(1) 141 payload2 := testutils.LightPayload8('B', 'b') 142 hashValue2 := hash.Hash([32]byte{2, 2, 2}) 143 leafNode2 := node.NewNode(255, nil, nil, ledger.Path(path2), payload2, hashValue2) 144 145 // Interim node 146 hashValue3 := hash.Hash([32]byte{3, 3, 3}) 147 interimNode := node.NewNode(256, leafNode1, leafNode2, ledger.DummyPath, nil, hashValue3) 148 149 encodedInterimNode := []byte{ 150 0x01, // node type 151 0x01, 0x00, // height 152 0x00, 0x01, // max depth 153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // reg count 154 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hash data 158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // LIndex 159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // RIndex 160 } 161 162 t.Run("decode", func(t *testing.T) { 163 scratchBuffers := [][]byte{ 164 nil, 165 make([]byte, 0), 166 make([]byte, 16), 167 make([]byte, 1024), 168 } 169 170 for _, scratch := range scratchBuffers { 171 reader := bytes.NewReader(encodedInterimNode) 172 newNode, regCount, regSize, err := flattener.ReadNodeFromCheckpointV4(reader, scratch, func(nodeIndex uint64) (*node.Node, uint64, uint64, error) { 173 switch nodeIndex { 174 case lchildIndex: 175 return leafNode1, 1, uint64(leafNode1.Payload().Size()), nil 176 case rchildIndex: 177 return leafNode2, 1, uint64(leafNode2.Payload().Size()), nil 178 default: 179 return nil, 0, 0, fmt.Errorf("unexpected child node index %d ", nodeIndex) 180 } 181 }) 182 require.NoError(t, err) 183 assert.Equal(t, interimNode, newNode) 184 assert.Equal(t, 0, reader.Len()) 185 require.Equal(t, uint64(2), regCount) 186 require.Equal(t, uint64(leafNode1.Payload().Size()+leafNode2.Payload().Size()), regSize) 187 } 188 }) 189 190 t.Run("decode child node not found error", func(t *testing.T) { 191 nodeNotFoundError := errors.New("failed to find node by index") 192 scratch := make([]byte, 1024) 193 194 reader := bytes.NewReader(encodedInterimNode) 195 newNode, regCount, regSize, err := flattener.ReadNodeFromCheckpointV4(reader, scratch, func(nodeIndex uint64) (*node.Node, uint64, uint64, error) { 196 return nil, 0, 0, nodeNotFoundError 197 }) 198 require.Nil(t, newNode) 199 require.ErrorIs(t, err, nodeNotFoundError) 200 require.Equal(t, uint64(0), regCount) 201 require.Equal(t, uint64(0), regSize) 202 }) 203 } 204 205 func TestTrieV4Decoding(t *testing.T) { 206 // Trie with nil root node 207 emptyTrieRootNodeIndex := uint64(20) 208 emptyTrie := trie.NewEmptyMTrie() 209 210 // Trie with not nil root node 211 hashValue := hash.Hash([32]byte{2, 2, 2}) 212 rootNode := node.NewNode(256, nil, nil, ledger.DummyPath, nil, hashValue) 213 notEmptyTrieRootNodeIndex := uint64(21) 214 notEmptyTrie, err := trie.NewMTrie(rootNode, 7, 5000) 215 require.NoError(t, err) 216 217 encodedEmptyTrie := []byte{ 218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, // RootIndex 219 0x56, 0x8f, 0x4e, 0xc7, 0x40, 0xfe, 0x3b, 0x5d, 220 0xe8, 0x80, 0x34, 0xcb, 0x7b, 0x1f, 0xbd, 0xdb, 221 0x41, 0x54, 0x8b, 0x06, 0x8f, 0x31, 0xae, 0xbc, 222 0x8a, 0xe9, 0x18, 0x9e, 0x42, 0x9c, 0x57, 0x49, // RootHash data 223 } 224 225 encodedTrie := []byte{ 226 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, // RootIndex 227 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hash data 231 } 232 233 testCases := []struct { 234 name string 235 tr *trie.MTrie 236 rootNodeIndex uint64 237 encodedTrie []byte 238 }{ 239 {"empty trie", emptyTrie, emptyTrieRootNodeIndex, encodedEmptyTrie}, 240 {"trie", notEmptyTrie, notEmptyTrieRootNodeIndex, encodedTrie}, 241 } 242 243 for _, tc := range testCases { 244 t.Run("decode "+tc.name, func(t *testing.T) { 245 scratchBuffers := [][]byte{ 246 nil, 247 make([]byte, 0), 248 make([]byte, 16), 249 make([]byte, 1024), 250 } 251 252 for _, scratch := range scratchBuffers { 253 reader := bytes.NewReader(tc.encodedTrie) 254 tr, err := flattener.ReadTrieFromCheckpointV4(reader, scratch, func(nodeIndex uint64) (*node.Node, uint64, uint64, error) { 255 switch nodeIndex { 256 case emptyTrieRootNodeIndex, notEmptyTrieRootNodeIndex: 257 return tc.tr.RootNode(), tc.tr.AllocatedRegCount(), tc.tr.AllocatedRegSize(), nil 258 default: 259 return nil, 0, 0, fmt.Errorf("unexpected root node index %d ", nodeIndex) 260 } 261 }) 262 263 require.NoError(t, err) 264 assert.Equal(t, tc.tr.RootNode(), tr.RootNode()) 265 assert.Equal(t, tc.tr.AllocatedRegCount(), tr.AllocatedRegCount()) 266 assert.Equal(t, tc.tr.AllocatedRegSize(), tr.AllocatedRegSize()) 267 assert.Equal(t, 0, reader.Len()) 268 } 269 }) 270 271 t.Run("decode "+tc.name+" node not found error", func(t *testing.T) { 272 nodeNotFoundError := errors.New("failed to find node by index") 273 scratch := make([]byte, 1024) 274 275 reader := bytes.NewReader(tc.encodedTrie) 276 tr, err := flattener.ReadTrieFromCheckpointV4(reader, scratch, func(nodeIndex uint64) (*node.Node, uint64, uint64, error) { 277 return nil, 0, 0, nodeNotFoundError 278 }) 279 require.Nil(t, tr) 280 require.ErrorIs(t, err, nodeNotFoundError) 281 }) 282 } 283 }