github.com/core-coin/go-core/v2@v2.1.9/p2p/enr/enr_test.go (about) 1 // Copyright 2017 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-core library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package enr 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "math/rand" 24 "testing" 25 "time" 26 27 "github.com/stretchr/testify/assert" 28 "github.com/stretchr/testify/require" 29 30 "github.com/core-coin/go-core/v2/rlp" 31 ) 32 33 var rnd = rand.New(rand.NewSource(time.Now().UnixNano())) 34 35 func randomString(strlen int) string { 36 b := make([]byte, strlen) 37 rnd.Read(b) 38 return string(b) 39 } 40 41 // TestGetSetID tests encoding/decoding and setting/getting of the ID key. 42 func TestGetSetID(t *testing.T) { 43 id := ID("someid") 44 var r Record 45 r.Set(id) 46 47 var id2 ID 48 require.NoError(t, r.Load(&id2)) 49 assert.Equal(t, id, id2) 50 } 51 52 // TestGetSetIP4 tests encoding/decoding and setting/getting of the IP key. 53 func TestGetSetIPv4(t *testing.T) { 54 ip := IPv4{192, 168, 0, 3} 55 var r Record 56 r.Set(ip) 57 58 var ip2 IPv4 59 require.NoError(t, r.Load(&ip2)) 60 assert.Equal(t, ip, ip2) 61 } 62 63 // TestGetSetIP6 tests encoding/decoding and setting/getting of the IP6 key. 64 func TestGetSetIPv6(t *testing.T) { 65 ip := IPv6{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68} 66 var r Record 67 r.Set(ip) 68 69 var ip2 IPv6 70 require.NoError(t, r.Load(&ip2)) 71 assert.Equal(t, ip, ip2) 72 } 73 74 // TestGetSetUDP tests encoding/decoding and setting/getting of the UDP key. 75 func TestGetSetUDP(t *testing.T) { 76 port := UDP(30309) 77 var r Record 78 r.Set(port) 79 80 var port2 UDP 81 require.NoError(t, r.Load(&port2)) 82 assert.Equal(t, port, port2) 83 } 84 85 func TestLoadErrors(t *testing.T) { 86 var r Record 87 ip4 := IPv4{127, 0, 0, 1} 88 r.Set(ip4) 89 90 // Check error for missing keys. 91 var udp UDP 92 err := r.Load(&udp) 93 if !IsNotFound(err) { 94 t.Error("IsNotFound should return true for missing key") 95 } 96 assert.Equal(t, &KeyError{Key: udp.ENRKey(), Err: errNotFound}, err) 97 98 // Check error for invalid keys. 99 var list []uint 100 err = r.Load(WithEntry(ip4.ENRKey(), &list)) 101 kerr, ok := err.(*KeyError) 102 if !ok { 103 t.Fatalf("expected KeyError, got %T", err) 104 } 105 assert.Equal(t, kerr.Key, ip4.ENRKey()) 106 assert.Error(t, kerr.Err) 107 if IsNotFound(err) { 108 t.Error("IsNotFound should return false for decoding errors") 109 } 110 } 111 112 // TestSortedGetAndSet tests that Set produced a sorted pairs slice. 113 func TestSortedGetAndSet(t *testing.T) { 114 type pair struct { 115 k string 116 v uint32 117 } 118 119 for _, tt := range []struct { 120 input []pair 121 want []pair 122 }{ 123 { 124 input: []pair{{"a", 1}, {"c", 2}, {"b", 3}}, 125 want: []pair{{"a", 1}, {"b", 3}, {"c", 2}}, 126 }, 127 { 128 input: []pair{{"a", 1}, {"c", 2}, {"b", 3}, {"d", 4}, {"a", 5}, {"bb", 6}}, 129 want: []pair{{"a", 5}, {"b", 3}, {"bb", 6}, {"c", 2}, {"d", 4}}, 130 }, 131 { 132 input: []pair{{"c", 2}, {"b", 3}, {"d", 4}, {"a", 5}, {"bb", 6}}, 133 want: []pair{{"a", 5}, {"b", 3}, {"bb", 6}, {"c", 2}, {"d", 4}}, 134 }, 135 } { 136 var r Record 137 for _, i := range tt.input { 138 r.Set(WithEntry(i.k, &i.v)) 139 } 140 for i, w := range tt.want { 141 // set got's key from r.pair[i], so that we preserve order of pairs 142 got := pair{k: r.pairs[i].k} 143 assert.NoError(t, r.Load(WithEntry(w.k, &got.v))) 144 assert.Equal(t, w, got) 145 } 146 } 147 } 148 149 // TestDirty tests record signature removal on setting of new key/value pair in record. 150 func TestDirty(t *testing.T) { 151 var r Record 152 153 if _, err := rlp.EncodeToBytes(r); err != errEncodeUnsigned { 154 t.Errorf("expected errEncodeUnsigned, got %#v", err) 155 } 156 157 require.NoError(t, signTest([]byte{5}, &r)) 158 if len(r.signature) == 0 { 159 t.Error("record is not signed") 160 } 161 _, err := rlp.EncodeToBytes(r) 162 assert.NoError(t, err) 163 164 r.SetSeq(3) 165 if len(r.signature) != 0 { 166 t.Error("signature still set after modification") 167 } 168 if _, err := rlp.EncodeToBytes(r); err != errEncodeUnsigned { 169 t.Errorf("expected errEncodeUnsigned, got %#v", err) 170 } 171 } 172 173 func TestSeq(t *testing.T) { 174 var r Record 175 176 assert.Equal(t, uint64(0), r.Seq()) 177 r.Set(UDP(1)) 178 assert.Equal(t, uint64(0), r.Seq()) 179 signTest([]byte{5}, &r) 180 assert.Equal(t, uint64(0), r.Seq()) 181 r.Set(UDP(2)) 182 assert.Equal(t, uint64(1), r.Seq()) 183 } 184 185 // TestGetSetOverwrite tests value overwrite when setting a new value with an existing key in record. 186 func TestGetSetOverwrite(t *testing.T) { 187 var r Record 188 189 ip := IPv4{192, 168, 0, 3} 190 r.Set(ip) 191 192 ip2 := IPv4{192, 168, 0, 4} 193 r.Set(ip2) 194 195 var ip3 IPv4 196 require.NoError(t, r.Load(&ip3)) 197 assert.Equal(t, ip2, ip3) 198 } 199 200 // TestSignEncodeAndDecode tests signing, RLP encoding and RLP decoding of a record. 201 func TestSignEncodeAndDecode(t *testing.T) { 202 var r Record 203 r.Set(UDP(30300)) 204 r.Set(IPv4{127, 0, 0, 1}) 205 require.NoError(t, signTest([]byte{5}, &r)) 206 207 blob, err := rlp.EncodeToBytes(r) 208 require.NoError(t, err) 209 210 var r2 Record 211 require.NoError(t, rlp.DecodeBytes(blob, &r2)) 212 assert.Equal(t, r, r2) 213 214 blob2, err := rlp.EncodeToBytes(r2) 215 require.NoError(t, err) 216 assert.Equal(t, blob, blob2) 217 } 218 219 // TestRecordTooBig tests that records bigger than SizeLimit bytes cannot be signed. 220 func TestRecordTooBig(t *testing.T) { 221 var r Record 222 key := randomString(10) 223 224 // set a big value for random key, expect error 225 r.Set(WithEntry(key, randomString(SizeLimit))) 226 if err := signTest([]byte{5}, &r); err != errTooBig { 227 t.Fatalf("expected to get errTooBig, got %#v", err) 228 } 229 230 // set an acceptable value for random key, expect no error 231 r.Set(WithEntry(key, randomString(100))) 232 require.NoError(t, signTest([]byte{5}, &r)) 233 } 234 235 // TestSignEncodeAndDecodeRandom tests encoding/decoding of records containing random key/value pairs. 236 func TestSignEncodeAndDecodeRandom(t *testing.T) { 237 var r Record 238 239 // random key/value pairs for testing 240 pairs := map[string]uint32{} 241 for i := 0; i < 10; i++ { 242 key := randomString(7) 243 value := rnd.Uint32() 244 pairs[key] = value 245 r.Set(WithEntry(key, &value)) 246 } 247 248 require.NoError(t, signTest([]byte{5}, &r)) 249 _, err := rlp.EncodeToBytes(r) 250 require.NoError(t, err) 251 252 for k, v := range pairs { 253 desc := fmt.Sprintf("key %q", k) 254 var got uint32 255 buf := WithEntry(k, &got) 256 require.NoError(t, r.Load(buf), desc) 257 require.Equal(t, v, got, desc) 258 } 259 } 260 261 type testSig struct{} 262 263 type testID []byte 264 265 func (id testID) ENRKey() string { return "testid" } 266 267 func signTest(id []byte, r *Record) error { 268 r.Set(ID("test")) 269 r.Set(testID(id)) 270 return r.SetSig(testSig{}, makeTestSig(id, r.Seq())) 271 } 272 273 func makeTestSig(id []byte, seq uint64) []byte { 274 sig := make([]byte, 8, len(id)+8) 275 binary.BigEndian.PutUint64(sig[:8], seq) 276 sig = append(sig, id...) 277 return sig 278 } 279 280 func (testSig) Verify(r *Record, sig []byte) error { 281 var id []byte 282 if err := r.Load((*testID)(&id)); err != nil { 283 return err 284 } 285 if !bytes.Equal(sig, makeTestSig(id, r.Seq())) { 286 return ErrInvalidSig 287 } 288 return nil 289 } 290 291 func (testSig) NodeAddr(r *Record) []byte { 292 var id []byte 293 if err := r.Load((*testID)(&id)); err != nil { 294 return nil 295 } 296 return id 297 }