github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/p2p/enr/enr.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 // Package enr implements Ethereum Node Records as defined in EIP-778. A node record holds 19 // arbitrary information about a node on the peer-to-peer network. Node information is 20 // stored in key/value pairs. To store and retrieve key/values in a record, use the Entry 21 // interface. 22 // 23 // Signature Handling 24 // 25 // Records must be signed before transmitting them to another node. 26 // 27 // Decoding a record doesn't check its signature. Code working with records from an 28 // untrusted source must always verify two things: that the record uses an identity scheme 29 // deemed secure, and that the signature is valid according to the declared scheme. 30 // 31 // When creating a record, set the entries you want and use a signing function provided by 32 // the identity scheme to add the signature. Modifying a record invalidates the signature. 33 // 34 // Package enr supports the "secp256k1-keccak" identity scheme. 35 package enr 36 37 import ( 38 "bytes" 39 "errors" 40 "fmt" 41 "io" 42 "sort" 43 44 "github.com/AigarNetwork/aigar/rlp" 45 ) 46 47 const SizeLimit = 300 // maximum encoded size of a node record in bytes 48 49 var ( 50 ErrInvalidSig = errors.New("invalid signature on node record") 51 errNotSorted = errors.New("record key/value pairs are not sorted by key") 52 errDuplicateKey = errors.New("record contains duplicate key") 53 errIncompletePair = errors.New("record contains incomplete k/v pair") 54 errTooBig = fmt.Errorf("record bigger than %d bytes", SizeLimit) 55 errEncodeUnsigned = errors.New("can't encode unsigned record") 56 errNotFound = errors.New("no such key in record") 57 ) 58 59 // An IdentityScheme is capable of verifying record signatures and 60 // deriving node addresses. 61 type IdentityScheme interface { 62 Verify(r *Record, sig []byte) error 63 NodeAddr(r *Record) []byte 64 } 65 66 // SchemeMap is a registry of named identity schemes. 67 type SchemeMap map[string]IdentityScheme 68 69 func (m SchemeMap) Verify(r *Record, sig []byte) error { 70 s := m[r.IdentityScheme()] 71 if s == nil { 72 return ErrInvalidSig 73 } 74 return s.Verify(r, sig) 75 } 76 77 func (m SchemeMap) NodeAddr(r *Record) []byte { 78 s := m[r.IdentityScheme()] 79 if s == nil { 80 return nil 81 } 82 return s.NodeAddr(r) 83 } 84 85 // Record represents a node record. The zero value is an empty record. 86 type Record struct { 87 seq uint64 // sequence number 88 signature []byte // the signature 89 raw []byte // RLP encoded record 90 pairs []pair // sorted list of all key/value pairs 91 } 92 93 // pair is a key/value pair in a record. 94 type pair struct { 95 k string 96 v rlp.RawValue 97 } 98 99 // Seq returns the sequence number. 100 func (r *Record) Seq() uint64 { 101 return r.seq 102 } 103 104 // SetSeq updates the record sequence number. This invalidates any signature on the record. 105 // Calling SetSeq is usually not required because setting any key in a signed record 106 // increments the sequence number. 107 func (r *Record) SetSeq(s uint64) { 108 r.signature = nil 109 r.raw = nil 110 r.seq = s 111 } 112 113 // Load retrieves the value of a key/value pair. The given Entry must be a pointer and will 114 // be set to the value of the entry in the record. 115 // 116 // Errors returned by Load are wrapped in KeyError. You can distinguish decoding errors 117 // from missing keys using the IsNotFound function. 118 func (r *Record) Load(e Entry) error { 119 i := sort.Search(len(r.pairs), func(i int) bool { return r.pairs[i].k >= e.ENRKey() }) 120 if i < len(r.pairs) && r.pairs[i].k == e.ENRKey() { 121 if err := rlp.DecodeBytes(r.pairs[i].v, e); err != nil { 122 return &KeyError{Key: e.ENRKey(), Err: err} 123 } 124 return nil 125 } 126 return &KeyError{Key: e.ENRKey(), Err: errNotFound} 127 } 128 129 // Set adds or updates the given entry in the record. It panics if the value can't be 130 // encoded. If the record is signed, Set increments the sequence number and invalidates 131 // the sequence number. 132 func (r *Record) Set(e Entry) { 133 blob, err := rlp.EncodeToBytes(e) 134 if err != nil { 135 panic(fmt.Errorf("enr: can't encode %s: %v", e.ENRKey(), err)) 136 } 137 r.invalidate() 138 139 pairs := make([]pair, len(r.pairs)) 140 copy(pairs, r.pairs) 141 i := sort.Search(len(pairs), func(i int) bool { return pairs[i].k >= e.ENRKey() }) 142 switch { 143 case i < len(pairs) && pairs[i].k == e.ENRKey(): 144 // element is present at r.pairs[i] 145 pairs[i].v = blob 146 case i < len(r.pairs): 147 // insert pair before i-th elem 148 el := pair{e.ENRKey(), blob} 149 pairs = append(pairs, pair{}) 150 copy(pairs[i+1:], pairs[i:]) 151 pairs[i] = el 152 default: 153 // element should be placed at the end of r.pairs 154 pairs = append(pairs, pair{e.ENRKey(), blob}) 155 } 156 r.pairs = pairs 157 } 158 159 func (r *Record) invalidate() { 160 if r.signature != nil { 161 r.seq++ 162 } 163 r.signature = nil 164 r.raw = nil 165 } 166 167 // Signature returns the signature of the record. 168 func (r *Record) Signature() []byte { 169 if r.signature == nil { 170 return nil 171 } 172 cpy := make([]byte, len(r.signature)) 173 copy(cpy, r.signature) 174 return cpy 175 } 176 177 // EncodeRLP implements rlp.Encoder. Encoding fails if 178 // the record is unsigned. 179 func (r Record) EncodeRLP(w io.Writer) error { 180 if r.signature == nil { 181 return errEncodeUnsigned 182 } 183 _, err := w.Write(r.raw) 184 return err 185 } 186 187 // DecodeRLP implements rlp.Decoder. Decoding doesn't verify the signature. 188 func (r *Record) DecodeRLP(s *rlp.Stream) error { 189 dec, raw, err := decodeRecord(s) 190 if err != nil { 191 return err 192 } 193 *r = dec 194 r.raw = raw 195 return nil 196 } 197 198 func decodeRecord(s *rlp.Stream) (dec Record, raw []byte, err error) { 199 raw, err = s.Raw() 200 if err != nil { 201 return dec, raw, err 202 } 203 if len(raw) > SizeLimit { 204 return dec, raw, errTooBig 205 } 206 207 // Decode the RLP container. 208 s = rlp.NewStream(bytes.NewReader(raw), 0) 209 if _, err := s.List(); err != nil { 210 return dec, raw, err 211 } 212 if err = s.Decode(&dec.signature); err != nil { 213 return dec, raw, err 214 } 215 if err = s.Decode(&dec.seq); err != nil { 216 return dec, raw, err 217 } 218 // The rest of the record contains sorted k/v pairs. 219 var prevkey string 220 for i := 0; ; i++ { 221 var kv pair 222 if err := s.Decode(&kv.k); err != nil { 223 if err == rlp.EOL { 224 break 225 } 226 return dec, raw, err 227 } 228 if err := s.Decode(&kv.v); err != nil { 229 if err == rlp.EOL { 230 return dec, raw, errIncompletePair 231 } 232 return dec, raw, err 233 } 234 if i > 0 { 235 if kv.k == prevkey { 236 return dec, raw, errDuplicateKey 237 } 238 if kv.k < prevkey { 239 return dec, raw, errNotSorted 240 } 241 } 242 dec.pairs = append(dec.pairs, kv) 243 prevkey = kv.k 244 } 245 return dec, raw, s.ListEnd() 246 } 247 248 // IdentityScheme returns the name of the identity scheme in the record. 249 func (r *Record) IdentityScheme() string { 250 var id ID 251 r.Load(&id) 252 return string(id) 253 } 254 255 // VerifySignature checks whether the record is signed using the given identity scheme. 256 func (r *Record) VerifySignature(s IdentityScheme) error { 257 return s.Verify(r, r.signature) 258 } 259 260 // SetSig sets the record signature. It returns an error if the encoded record is larger 261 // than the size limit or if the signature is invalid according to the passed scheme. 262 // 263 // You can also use SetSig to remove the signature explicitly by passing a nil scheme 264 // and signature. 265 // 266 // SetSig panics when either the scheme or the signature (but not both) are nil. 267 func (r *Record) SetSig(s IdentityScheme, sig []byte) error { 268 switch { 269 // Prevent storing invalid data. 270 case s == nil && sig != nil: 271 panic("enr: invalid call to SetSig with non-nil signature but nil scheme") 272 case s != nil && sig == nil: 273 panic("enr: invalid call to SetSig with nil signature but non-nil scheme") 274 // Verify if we have a scheme. 275 case s != nil: 276 if err := s.Verify(r, sig); err != nil { 277 return err 278 } 279 raw, err := r.encode(sig) 280 if err != nil { 281 return err 282 } 283 r.signature, r.raw = sig, raw 284 // Reset otherwise. 285 default: 286 r.signature, r.raw = nil, nil 287 } 288 return nil 289 } 290 291 // AppendElements appends the sequence number and entries to the given slice. 292 func (r *Record) AppendElements(list []interface{}) []interface{} { 293 list = append(list, r.seq) 294 for _, p := range r.pairs { 295 list = append(list, p.k, p.v) 296 } 297 return list 298 } 299 300 func (r *Record) encode(sig []byte) (raw []byte, err error) { 301 list := make([]interface{}, 1, 2*len(r.pairs)+1) 302 list[0] = sig 303 list = r.AppendElements(list) 304 if raw, err = rlp.EncodeToBytes(list); err != nil { 305 return nil, err 306 } 307 if len(raw) > SizeLimit { 308 return nil, errTooBig 309 } 310 return raw, nil 311 }