github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/merkler/path_test.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package merkler 7 8 import ( 9 "fmt" 10 "math" 11 "math/bits" 12 "testing" 13 14 "github.com/stretchr/testify/assert" 15 16 "github.com/stretchr/testify/require" 17 18 "github.com/insolar/vanilla/cryptkit" 19 "github.com/insolar/vanilla/longbits" 20 ) 21 22 type item = uint64 23 24 func buildTrace(t *testing.T, count uint, unbalancedStub cryptkit.Digest, skipEmpty bool) (result []item, sum uint64) { 25 result = make([]item, 0, int(count)<<1+bits.Len(count)) 26 27 md := NewStackedCalculator(xorPairDigester{}, unbalancedStub, func(item longbits.FoldableReader, _ bool) { 28 switch { 29 case item != nil: 30 u := item.FoldToUint64() 31 if count <= 64 { 32 require.NotEqual(t, uint64(0), u) 33 } 34 result = append(result, u) 35 case skipEmpty: 36 return 37 default: 38 result = append(result, 0) 39 } 40 }) 41 42 for i := uint(0); i < count; i++ { 43 bit := bits.RotateLeft64(1, int(i)) 44 md.AddNext(newBits64(bit)) 45 } 46 47 sum = md.FinishSequence().FoldToUint64() 48 49 var mask uint64 50 51 require.Equal(t, int(count), md.Count()) 52 count &= 0x7F 53 switch { 54 case count < 64: 55 mask = ^uint64(math.MaxUint64 << count) 56 case count > 64: 57 mask = math.MaxUint64 << (count - 64) 58 default: 59 mask = ^uint64(0) 60 } 61 if unbalancedStub.IsEmpty() { 62 require.Equal(t, mask, sum) 63 } 64 65 return 66 } 67 68 //nolint 69 func printTrace(trace []item, count uint) { 70 for i, item := range trace { 71 switch index := uint(i >> 1); { 72 case index >= count: 73 index = uint(i) - count 74 fmt.Printf("%3d# ", index) 75 case i&1 == 1: 76 fmt.Printf("%3d* ", index) 77 default: 78 fmt.Printf("%3d ", index) 79 } 80 if item == 0 { 81 fmt.Println() 82 continue 83 } 84 fmt.Printf("%064b\n", item) 85 } 86 } 87 88 func TestPathBuilder_WalkUnstubbed(t *testing.T) { 89 for count := uint(0); count < 64; count++ { 90 leafCount := 1 + count 91 t.Run(fmt.Sprint(leafCount), func(t *testing.T) { 92 testWalk(t, leafCount, cryptkit.Digest{}) 93 }) 94 } 95 } 96 97 func TestPathBuilder_WalkStubbed(t *testing.T) { 98 stubDigest := cryptkit.NewDigest(newBits64(uint64(1)<<63), "x") 99 100 for count := uint(0); count < 64; count++ { 101 leafCount := 1 + count 102 t.Run(fmt.Sprint(leafCount), func(t *testing.T) { 103 testWalk(t, leafCount, stubDigest) 104 }) 105 } 106 } 107 108 func testWalk(t *testing.T, leafCount uint, stubDigest cryptkit.Digest) { 109 110 var stub uint64 111 if !stubDigest.IsEmpty() { 112 stub = stubDigest.FoldToUint64() 113 } 114 115 trace, expected := buildTrace(t, leafCount, stubDigest, false) 116 // fmt.Println("\nTrace: ", leafCount, " ============================================================== ") 117 // printTrace(trace, leafCount) 118 119 pb := NewPathBuilder(leafCount, !stubDigest.IsEmpty()) 120 121 // fmt.Println() 122 // for i, level := range pb.levels { 123 // fmt.Printf("L%d %3d %3d\n", i+1, level.nodeValueL, level.nodeValueR) 124 // } 125 // 126 // fmt.Println() 127 128 for i := uint(0); i < pb.count; i++ { 129 // fmt.Println("\nIndex: ", i, "/", leafCount, " ======== ") 130 131 total := uint64(1) << i 132 // fmt.Printf(" %064b\n", total) 133 pb.WalkFor(i, func(index uint, isLeaf, _ bool) { 134 135 switch { 136 case isLeaf: 137 // fmt.Printf("%3d ", index) 138 index <<= 1 139 case pb.stubbed && index == 0: 140 // fmt.Printf("stub %064b\n", stub) 141 total ^= stub 142 return 143 case index < pb.count: 144 // fmt.Printf("%3d* ", index) 145 index = index<<1 + 1 146 default: 147 // fmt.Printf("%3d# ", index) 148 index = pb.count + index 149 } 150 if index >= uint(len(trace)) { 151 // fmt.Println("-") 152 return 153 } 154 155 u := trace[index] 156 switch { 157 case leafCount > 64: 158 // 159 case u == 0: 160 require.Fail(t, "empty entry") 161 default: 162 v := u &^ stub 163 assert.Zero(t, v&total) 164 } 165 total ^= u 166 // fmt.Printf("%064b\n", u) 167 }) 168 // fmt.Printf("ALL %064b\n", total) 169 assert.Equal(t, expected, total) 170 } 171 }