github.com/amazechain/amc@v0.1.3/internal/p2p/enr/enr.go (about)

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