github.com/ethersphere/bee/v2@v2.2.0/pkg/manifest/mantaray/marshal_test.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package mantaray 6 7 import ( 8 "bytes" 9 "context" 10 11 "encoding/hex" 12 "errors" 13 "reflect" 14 "testing" 15 16 "golang.org/x/crypto/sha3" 17 ) 18 19 const testMarshalOutput01 = "52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64950ac787fbce1061870e8d34e0a638bc7e812c7ca4ebd31d626a572ba47b06f6952fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952fdfc072102654f163f5f0fa0621d729566c74d10037c4d7bbb0407d1e2c64950fcd3072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64950f89d6640e3044f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64850ff9f642182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64b50fc98072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64a50ff99622182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64d" 20 21 const testMarshalOutput02 = "52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64905954fb18659339d0b25e0fb9723d3cd5d528fb3c8d495fd157bd7b7a210496952fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952fdfc072102654f163f5f0fa0621d729566c74d10037c4d7bbb0407d1e2c64940fcd3072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952e3872548ec012a6e123b60f9177017fb12e57732621d2c1ada267adbe8cc4350f89d6640e3044f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64850ff9f642182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64b50fc98072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64a50ff99622182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64952fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c64d" 22 23 var obfuscationKey = []uint8{82, 253, 252, 7, 33, 130, 101, 79, 22, 63, 95, 15, 154, 98, 29, 114, 149, 102, 199, 77, 16, 3, 124, 77, 123, 187, 4, 7, 209, 226, 198, 73} 24 25 var testEntries = []NodeEntry{ 26 { 27 Path: []byte("/"), 28 Metadata: map[string]string{ 29 "index-document": "aaaaa", 30 }, 31 }, 32 { 33 Path: []byte("aaaaa"), 34 }, 35 { 36 Path: []byte("cc"), 37 }, 38 { 39 Path: []byte("d"), 40 }, 41 { 42 Path: []byte("ee"), 43 }, 44 } 45 46 type NodeEntry struct { 47 Path []byte 48 Entry []byte 49 Metadata map[string]string 50 } 51 52 // nolint:gochecknoinits 53 func init() { 54 SetObfuscationKeyFn(func(b []byte) (int, error) { 55 copy(b, obfuscationKey) 56 return 32, nil 57 }) 58 } 59 60 func TestVersion01(t *testing.T) { 61 t.Parallel() 62 63 hasher := sha3.NewLegacyKeccak256() 64 65 _, err := hasher.Write([]byte(version01String)) 66 if err != nil { 67 t.Fatal(err) 68 } 69 sum := hasher.Sum(nil) 70 71 sumHex := hex.EncodeToString(sum) 72 73 if version01HashString != sumHex { 74 t.Fatalf("expecting version hash '%s', got '%s'", version01String, sumHex) 75 } 76 } 77 78 func TestVersion02(t *testing.T) { 79 t.Parallel() 80 81 hasher := sha3.NewLegacyKeccak256() 82 83 _, err := hasher.Write([]byte(version02String)) 84 if err != nil { 85 t.Fatal(err) 86 } 87 sum := hasher.Sum(nil) 88 89 sumHex := hex.EncodeToString(sum) 90 91 if version02HashString != sumHex { 92 t.Fatalf("expecting version hash '%s', got '%s'", version02String, sumHex) 93 } 94 } 95 96 func TestUnmarshal01(t *testing.T) { 97 t.Parallel() 98 99 input, _ := hex.DecodeString(testMarshalOutput01) 100 n := &Node{} 101 err := n.UnmarshalBinary(input) 102 if err != nil { 103 t.Fatalf("expected no error marshaling, got %v", err) 104 } 105 106 expEncrypted := testMarshalOutput01[128:192] 107 // perform XOR decryption 108 expEncryptedBytes, _ := hex.DecodeString(expEncrypted) 109 expBytes := encryptDecrypt(expEncryptedBytes, n.obfuscationKey) 110 exp := hex.EncodeToString(expBytes) 111 112 if hex.EncodeToString(n.entry) != exp { 113 t.Fatalf("expected %x, got %x", exp, n.entry) 114 } 115 if len(testEntries) != len(n.forks) { 116 t.Fatalf("expected %d forks, got %d", len(testEntries), len(n.forks)) 117 } 118 for _, entry := range testEntries { 119 prefix := entry.Path 120 f := n.forks[prefix[0]] 121 if f == nil { 122 t.Fatalf("expected to have fork on byte %x", prefix[:1]) 123 } 124 if !bytes.Equal(f.prefix, prefix) { 125 t.Fatalf("expected prefix for byte %x to match %s, got %s", prefix[:1], prefix, f.prefix) 126 } 127 } 128 } 129 130 func TestUnmarshal02(t *testing.T) { 131 t.Parallel() 132 133 input, _ := hex.DecodeString(testMarshalOutput02) 134 n := &Node{} 135 err := n.UnmarshalBinary(input) 136 if err != nil { 137 t.Fatalf("expected no error marshaling, got %v", err) 138 } 139 140 expEncrypted := testMarshalOutput02[128:192] 141 // perform XOR decryption 142 expEncryptedBytes, _ := hex.DecodeString(expEncrypted) 143 expBytes := encryptDecrypt(expEncryptedBytes, n.obfuscationKey) 144 exp := hex.EncodeToString(expBytes) 145 146 if hex.EncodeToString(n.entry) != exp { 147 t.Fatalf("expected %x, got %x", exp, n.entry) 148 } 149 if len(testEntries) != len(n.forks) { 150 t.Fatalf("expected %d forks, got %d", len(testEntries), len(n.forks)) 151 } 152 for _, entry := range testEntries { 153 prefix := entry.Path 154 f := n.forks[prefix[0]] 155 if f == nil { 156 t.Fatalf("expected to have fork on byte %x", prefix[:1]) 157 } 158 if !bytes.Equal(f.prefix, prefix) { 159 t.Fatalf("expected prefix for byte %x to match %s, got %s", prefix[:1], prefix, f.prefix) 160 } 161 if len(entry.Metadata) > 0 { 162 if !reflect.DeepEqual(entry.Metadata, f.metadata) { 163 t.Fatalf("expected metadata for byte %x to match %s, got %s", prefix[:1], entry.Metadata, f.metadata) 164 } 165 } 166 } 167 } 168 169 // nolint:paralleltest 170 func TestMarshal(t *testing.T) { 171 ctx := context.Background() 172 n := New() 173 defer func(r func(*fork) []byte) { refBytes = r }(refBytes) 174 i := uint8(0) 175 refBytes = func(*fork) []byte { 176 b := make([]byte, 32) 177 b[31] = i 178 i++ 179 return b 180 } 181 for i := 0; i < len(testEntries); i++ { 182 c := testEntries[i].Path 183 e := testEntries[i].Entry 184 if len(e) == 0 { 185 e = append(make([]byte, 32-len(c)), c...) 186 } 187 m := testEntries[i].Metadata 188 err := n.Add(ctx, c, e, m, nil) 189 if err != nil { 190 t.Fatalf("expected no error, got %v", err) 191 } 192 } 193 b, err := n.MarshalBinary() 194 if err != nil { 195 t.Fatalf("expected no error marshaling, got %v", err) 196 } 197 exp, _ := hex.DecodeString(testMarshalOutput02) 198 if !bytes.Equal(b, exp) { 199 t.Fatalf("expected marshalled output to match %x, got %x", exp, b) 200 } 201 // n = &Node{} 202 // err = n.UnmarshalBinary(b) 203 // if err != nil { 204 // t.Fatalf("expected no error unmarshaling, got %v", err) 205 // } 206 207 // for j := 0; j < len(testCases); j++ { 208 // d := testCases[j] 209 // m, err := n.Lookup(d, nil) 210 // if err != nil { 211 // t.Fatalf("expected no error, got %v", err) 212 // } 213 // if !bytes.Equal(m, d) { 214 // t.Fatalf("expected value %x, got %x", d, m) 215 // } 216 // } 217 } 218 219 func Test_UnmarshalBinary(t *testing.T) { 220 t.Parallel() 221 222 decode := func(s string) []byte { 223 t.Helper() 224 data, err := hex.DecodeString(s) 225 if err != nil { 226 t.Fatalf("expected no error, got %v", err) 227 } 228 return data 229 } 230 231 tests := []struct { 232 name string // name for test case 233 data []byte // node binary data 234 wantErr error // tells if UnmarshalBinary should return error 235 }{ 236 { 237 name: "nil input bytes", 238 data: nil, 239 wantErr: ErrTooShort, 240 }, 241 { 242 name: "not enough bytes for header", 243 data: make([]byte, nodeHeaderSize-1), 244 wantErr: ErrTooShort, 245 }, 246 { 247 name: "invalid header - empty bytes", 248 data: make([]byte, nodeHeaderSize), 249 wantErr: ErrInvalidVersionHash, 250 }, 251 { // fork with metadata where metadata size value is less than metadata content (size 89, want 93) 252 name: "invalid manifest size 89", 253 data: decode("00000000000000000000000000000000000000000000000000000000000000005768b3b6a7db56d21d1abff40d41cebfc83448fed8d7e9b06ec0d3b073f28f200000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000016012f0000000000000000000000000000000000000000000000000000000000e87f95c3d081c4fede769b6c69e27b435e525cbd25c6715c607e7c531e32963900597b22776562736974652d696e6465782d646f63756d656e74223a2233356561656538316262363338303436393965633637316265323736326465626665346662643330636461646139303232393239646131613965366134366436227d0a"), 254 wantErr: ErrInvalidManifest, 255 }, 256 { // fork with valid metadata (size is 93, want 93) 257 name: "valid manifest", 258 data: decode("00000000000000000000000000000000000000000000000000000000000000005768b3b6a7db56d21d1abff40d41cebfc83448fed8d7e9b06ec0d3b073f28f200000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000016012f0000000000000000000000000000000000000000000000000000000000e87f95c3d081c4fede769b6c69e27b435e525cbd25c6715c607e7c531e329639005d7b22776562736974652d696e6465782d646f63756d656e74223a2233356561656538316262363338303436393965633637316265323736326465626665346662643330636461646139303232393239646131613965366134366436227d0a"), 259 wantErr: nil, 260 }, 261 { // fork with metadata where metadata size value exceeds actual metadata size (size is 95, want 93) 262 name: "invalid manifest size 95", 263 data: decode("00000000000000000000000000000000000000000000000000000000000000005768b3b6a7db56d21d1abff40d41cebfc83448fed8d7e9b06ec0d3b073f28f200000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000016012f0000000000000000000000000000000000000000000000000000000000e87f95c3d081c4fede769b6c69e27b435e525cbd25c6715c607e7c531e329639005f7b22776562736974652d696e6465782d646f63756d656e74223a2233356561656538316262363338303436393965633637316265323736326465626665346662643330636461646139303232393239646131613965366134366436227d0a"), 264 wantErr: ErrInvalidManifest, 265 }, 266 { // fork with metadata where metadata size value exceeds actual metadata size (size is 96, want 93) 267 name: "invalid manifest size 96", 268 data: decode("00000000000000000000000000000000000000000000000000000000000000005768b3b6a7db56d21d1abff40d41cebfc83448fed8d7e9b06ec0d3b073f28f200000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000016012f0000000000000000000000000000000000000000000000000000000000e87f95c3d081c4fede769b6c69e27b435e525cbd25c6715c607e7c531e32963900607b22776562736974652d696e6465782d646f63756d656e74223a2233356561656538316262363338303436393965633637316265323736326465626665346662643330636461646139303232393239646131613965366134366436227d0a"), 269 wantErr: ErrInvalidManifest, 270 }, 271 } 272 273 for _, tc := range tests { 274 tc := tc 275 t.Run(tc.name, func(t *testing.T) { 276 t.Parallel() 277 278 n := New() 279 haveErr := n.UnmarshalBinary(tc.data) 280 281 if tc.wantErr != nil && !errors.Is(haveErr, tc.wantErr) { 282 t.Fatalf("expected error marshaling, want %v got %v", tc.wantErr, haveErr) 283 } else if tc.wantErr == nil && haveErr != nil { 284 t.Fatalf("unexpected error marshaling, got %v", haveErr) 285 } 286 }) 287 } 288 }