github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/ledger/complete/wal/checkpointer_serialization_test.go (about)

     1  package wal
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/assert"
     7  	"github.com/stretchr/testify/require"
     8  
     9  	"github.com/onflow/flow-go/ledger"
    10  	"github.com/onflow/flow-go/ledger/common/hash"
    11  	"github.com/onflow/flow-go/ledger/common/testutils"
    12  	"github.com/onflow/flow-go/ledger/complete/mtrie/node"
    13  	"github.com/onflow/flow-go/ledger/complete/mtrie/trie"
    14  )
    15  
    16  func TestGetNodesAtLevel(t *testing.T) {
    17  
    18  	t.Run("nil node", func(t *testing.T) {
    19  		n := (*node.Node)(nil)
    20  		for level := uint(0); level < 6; level++ {
    21  			nodes := getNodesAtLevel(n, level)
    22  			assert.Equal(t, 1<<level, len(nodes))
    23  			for _, nAtLevel := range nodes {
    24  				require.Nil(t, nAtLevel)
    25  			}
    26  		}
    27  	})
    28  
    29  	t.Run("leaf node", func(t *testing.T) {
    30  		path := testutils.PathByUint8(1)
    31  		payload := testutils.LightPayload8('A', 'a')
    32  		hashValue := hash.Hash([32]byte{1, 1, 1})
    33  		leafNode := node.NewNode(255, nil, nil, path, payload, hashValue)
    34  
    35  		nodes := getNodesAtLevel(leafNode, 0)
    36  		require.Equal(t, []*node.Node{leafNode}, nodes)
    37  
    38  		for level := uint(1); level < 6; level++ {
    39  			nodes := getNodesAtLevel(leafNode, level)
    40  			require.Equal(t, 1<<level, len(nodes))
    41  			for _, nAtLevel := range nodes {
    42  				require.Nil(t, nAtLevel)
    43  			}
    44  		}
    45  	})
    46  
    47  	t.Run("interim node with left child", func(t *testing.T) {
    48  		emptyTrie := trie.NewEmptyMTrie()
    49  
    50  		// key: 0000...
    51  		p1 := testutils.PathByUint8(0)
    52  		v1 := testutils.LightPayload8('A', 'a')
    53  
    54  		// key: 0100....
    55  		p2 := testutils.PathByUint8(64)
    56  		v2 := testutils.LightPayload8('B', 'b')
    57  
    58  		paths := []ledger.Path{p1, p2}
    59  		payloads := []ledger.Payload{*v1, *v2}
    60  
    61  		updatedTrie, _, err := trie.NewTrieWithUpdatedRegisters(emptyTrie, paths, payloads, true)
    62  		require.NoError(t, err)
    63  
    64  		//              n4
    65  		//             /
    66  		//            /
    67  		//          n3
    68  		//        /     \
    69  		//      /         \
    70  		//   n1 (p1/v1)     n2 (p2/v2)
    71  
    72  		rootNode := updatedTrie.RootNode()
    73  
    74  		nodes := getNodesAtLevel(rootNode, 0)
    75  		require.Equal(t, []*node.Node{updatedTrie.RootNode()}, nodes)
    76  
    77  		nodes = getNodesAtLevel(rootNode, 1)
    78  		require.Equal(t, []*node.Node{rootNode.LeftChild(), nil}, nodes)
    79  
    80  		nodes = getNodesAtLevel(rootNode, 2)
    81  		require.Equal(t, []*node.Node{rootNode.LeftChild().LeftChild(), rootNode.LeftChild().RightChild(), nil, nil}, nodes)
    82  
    83  		for level := uint(3); level < 6; level++ {
    84  			nodes := getNodesAtLevel(rootNode, level)
    85  			require.Equal(t, 1<<level, len(nodes))
    86  			for _, nAtLevel := range nodes {
    87  				require.Nil(t, nAtLevel)
    88  			}
    89  		}
    90  	})
    91  
    92  	t.Run("interim node with right child", func(t *testing.T) {
    93  		emptyTrie := trie.NewEmptyMTrie()
    94  
    95  		// key: 1000...
    96  		p3 := testutils.PathByUint8(128)
    97  		v3 := testutils.LightPayload8('C', 'c')
    98  
    99  		// key: 1100....
   100  		p4 := testutils.PathByUint8(192)
   101  		v4 := testutils.LightPayload8('D', 'd')
   102  
   103  		paths := []ledger.Path{p3, p4}
   104  		payloads := []ledger.Payload{*v3, *v4}
   105  
   106  		updatedTrie, _, err := trie.NewTrieWithUpdatedRegisters(emptyTrie, paths, payloads, true)
   107  		require.NoError(t, err)
   108  
   109  		//              n8
   110  		//                 \
   111  		//                   \
   112  		//                   n7
   113  		//                  /   \
   114  		//                /       \
   115  		//              n5         n6
   116  		//            (p3/v3)    (p4/v4)
   117  
   118  		rootNode := updatedTrie.RootNode()
   119  
   120  		nodes := getNodesAtLevel(rootNode, 0)
   121  		require.Equal(t, []*node.Node{rootNode}, nodes)
   122  
   123  		nodes = getNodesAtLevel(rootNode, 1)
   124  		require.Equal(t, []*node.Node{nil, rootNode.RightChild()}, nodes)
   125  
   126  		nodes = getNodesAtLevel(rootNode, 2)
   127  		require.Equal(t, []*node.Node{nil, nil, rootNode.RightChild().LeftChild(), rootNode.RightChild().RightChild()}, nodes)
   128  
   129  		for level := uint(3); level < 6; level++ {
   130  			nodes := getNodesAtLevel(rootNode, level)
   131  			require.Equal(t, 1<<level, len(nodes))
   132  			for _, nAtLevel := range nodes {
   133  				require.Nil(t, nAtLevel)
   134  			}
   135  		}
   136  	})
   137  
   138  	t.Run("interim node with 2 children", func(t *testing.T) {
   139  		emptyTrie := trie.NewEmptyMTrie()
   140  
   141  		// key: 0000...
   142  		p1 := testutils.PathByUint8(0)
   143  		v1 := testutils.LightPayload8('A', 'a')
   144  
   145  		// key: 0100....
   146  		p2 := testutils.PathByUint8(64)
   147  		v2 := testutils.LightPayload8('B', 'b')
   148  
   149  		// key: 1000...
   150  		p3 := testutils.PathByUint8(128)
   151  		v3 := testutils.LightPayload8('C', 'c')
   152  
   153  		// key: 1100....
   154  		p4 := testutils.PathByUint8(192)
   155  		v4 := testutils.LightPayload8('D', 'd')
   156  
   157  		paths := []ledger.Path{p1, p2, p3, p4}
   158  		payloads := []ledger.Payload{*v1, *v2, *v3, *v4}
   159  
   160  		updatedTrie, _, err := trie.NewTrieWithUpdatedRegisters(emptyTrie, paths, payloads, true)
   161  		require.NoError(t, err)
   162  
   163  		//                n4
   164  		//             /      \
   165  		//            /        \
   166  		//          n3           n5
   167  		//        /   \          /  \
   168  		//      /      \        /     \
   169  		//   n1        n2      n6      n7
   170  		//  (p1)      (p2)    (p3)    (p4)
   171  
   172  		rootNode := updatedTrie.RootNode()
   173  
   174  		nodes := getNodesAtLevel(rootNode, 0)
   175  		require.Equal(t, []*node.Node{rootNode}, nodes)
   176  
   177  		nodes = getNodesAtLevel(rootNode, 1)
   178  		require.Equal(t, []*node.Node{rootNode.LeftChild(), rootNode.RightChild()}, nodes)
   179  
   180  		nodes = getNodesAtLevel(rootNode, 2)
   181  		require.Equal(t, []*node.Node{rootNode.LeftChild().LeftChild(), rootNode.LeftChild().RightChild(), rootNode.RightChild().LeftChild(), rootNode.RightChild().RightChild()}, nodes)
   182  
   183  		for level := uint(3); level < 6; level++ {
   184  			nodes := getNodesAtLevel(rootNode, level)
   185  			require.Equal(t, 1<<level, len(nodes))
   186  			for _, nAtLevel := range nodes {
   187  				require.Nil(t, nAtLevel)
   188  			}
   189  		}
   190  	})
   191  
   192  	t.Run("sparse trie with 8 levels", func(t *testing.T) {
   193  
   194  		emptyTrie := trie.NewEmptyMTrie()
   195  
   196  		// key: 0000 0000
   197  		p1 := testutils.PathByUint8(0)
   198  		v1 := testutils.LightPayload8('A', 'a')
   199  
   200  		// key: 0000 0001
   201  		p2 := testutils.PathByUint8(1)
   202  		v2 := testutils.LightPayload8('B', 'b')
   203  
   204  		// key: 1111 1110
   205  		p3 := testutils.PathByUint8(254)
   206  		v3 := testutils.LightPayload8('C', 'c')
   207  
   208  		// key: 1111 1111
   209  		p4 := testutils.PathByUint8(255)
   210  		v4 := testutils.LightPayload8('D', 'd')
   211  
   212  		paths := []ledger.Path{p1, p2, p3, p4}
   213  		payloads := []ledger.Payload{*v1, *v2, *v3, *v4}
   214  
   215  		updatedTrie, _, err := trie.NewTrieWithUpdatedRegisters(emptyTrie, paths, payloads, true)
   216  		require.NoError(t, err)
   217  
   218  		//                             n0
   219  		//                           /    \
   220  		//                         n1a    n1b
   221  		//                         /        \
   222  		//                       n2a        n2b
   223  		//                       /            \
   224  		//                      n3a           n3b
   225  		//                      /               \
   226  		//                     n4a              n4b
   227  		//                     /                  \
   228  		//                    n5a                 n5b
   229  		//                    /                     \
   230  		//                   n6a                    n6b
   231  		//                   /                        \
   232  		//                  n7a                       n7b
   233  		//                 /   \                      /  \
   234  		//               n8a   n8b                  n8d   n8d
   235  		//              (p1)   (p2)                (p3)   (p4)
   236  
   237  		n0 := updatedTrie.RootNode()
   238  
   239  		n1a := n0.LeftChild()
   240  		require.NotNil(t, n1a)
   241  		n1b := n0.RightChild()
   242  		require.NotNil(t, n1b)
   243  
   244  		n2a := n1a.LeftChild()
   245  		require.NotNil(t, n2a)
   246  		n2b := n1b.RightChild()
   247  		require.NotNil(t, n2b)
   248  
   249  		n3a := n2a.LeftChild()
   250  		require.NotNil(t, n3a)
   251  		n3b := n2b.RightChild()
   252  		require.NotNil(t, n3b)
   253  
   254  		n4a := n3a.LeftChild()
   255  		require.NotNil(t, n4a)
   256  		n4b := n3b.RightChild()
   257  		require.NotNil(t, n4b)
   258  
   259  		n5a := n4a.LeftChild()
   260  		require.NotNil(t, n5a)
   261  		n5b := n4b.RightChild()
   262  		require.NotNil(t, n5b)
   263  
   264  		n6a := n5a.LeftChild()
   265  		require.NotNil(t, n6a)
   266  		n6b := n5b.RightChild()
   267  		require.NotNil(t, n6b)
   268  
   269  		n7a := n6a.LeftChild()
   270  		require.NotNil(t, n7a)
   271  		n7b := n6b.RightChild()
   272  		require.NotNil(t, n7b)
   273  
   274  		n8a := n7a.LeftChild()
   275  		require.NotNil(t, n8a)
   276  		n8b := n7a.RightChild()
   277  		require.NotNil(t, n8b)
   278  		n8c := n7b.LeftChild()
   279  		require.NotNil(t, n8c)
   280  		n8d := n7b.RightChild()
   281  		require.NotNil(t, n8d)
   282  
   283  		testcases := []struct {
   284  			level         uint
   285  			expectedNodes []*node.Node
   286  		}{
   287  			{0, []*node.Node{n0}},
   288  			{1, []*node.Node{n1a, n1b}},
   289  			{2, []*node.Node{0: n2a, 3: n2b}},
   290  			{3, []*node.Node{0: n3a, 7: n3b}},
   291  			{4, []*node.Node{0: n4a, 15: n4b}},
   292  			{5, []*node.Node{0: n5a, 31: n5b}},
   293  			{6, []*node.Node{0: n6a, 63: n6b}},
   294  			{7, []*node.Node{0: n7a, 127: n7b}},
   295  			{8, []*node.Node{0: n8a, 1: n8b, 254: n8c, 255: n8d}},
   296  		}
   297  
   298  		rootNode := updatedTrie.RootNode()
   299  		for _, tc := range testcases {
   300  			nodes := getNodesAtLevel(rootNode, tc.level)
   301  			require.Equal(t, len(tc.expectedNodes), len(nodes))
   302  			require.Equal(t, tc.expectedNodes, nodes)
   303  		}
   304  	})
   305  }