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  }