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  }