mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 17:33:47 +00:00
p2p/enr: changed api; removed wrapList hack;
This commit is contained in:
parent
d94202c943
commit
992c80eb3d
7 changed files with 341 additions and 313 deletions
25
p2p/enr/discv5.go
Normal file
25
p2p/enr/discv5.go
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package enr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DiscV5 uint32
|
||||||
|
|
||||||
|
func (DiscV5) ENRKey() string {
|
||||||
|
return "discv5"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v DiscV5) EncodeRLP(w io.Writer) error {
|
||||||
|
port := uint32(v)
|
||||||
|
return rlp.Encode(w, port)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *DiscV5) DecodeRLP(s *rlp.Stream) error {
|
||||||
|
if err := s.Decode((*uint32)(v)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
356
p2p/enr/enr.go
356
p2p/enr/enr.go
|
|
@ -20,9 +20,8 @@ package enr
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"io"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
@ -31,203 +30,93 @@ import (
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ()
|
||||||
|
|
||||||
// The maximum encoded size of a node record is 300 bytes. Implementations should reject records larger than this size.
|
// The maximum encoded size of a node record is 300 bytes. Implementations should reject records larger than this size.
|
||||||
const (
|
const (
|
||||||
RECORD_MAX_SIZE = 300
|
RECORD_MAX_SIZE = 300
|
||||||
ID_SECP256k1_KECCAK = "secp256k1-keccak" // "secp256k1-keccak" identity scheme identifier
|
ID_SECP256k1_KECCAK = "secp256k1-keccak" // "secp256k1-keccak" identity scheme identifier
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pseudo-const identifiers for pre-defined keys
|
// Key is implemented by known node record key types.
|
||||||
var (
|
//
|
||||||
ID = []byte(`id`) // name of identity scheme, e.g. "secp256k1-keccak"
|
// To define a new key that is to be included in a node record,
|
||||||
SECP256K1 = []byte(`secp256k1`) // compressed secp256k1 public key
|
// create a Go type that satisfies this interface. The type should
|
||||||
IP4 = []byte(`ip4`) // IPv4 address, 4 bytes
|
// also implement rlp.Decoder if additional checks are needed on the value.
|
||||||
IP6 = []byte(`ip6`) // IPv6 address, 16 bytes
|
type Key interface {
|
||||||
DISCV5 = []byte(`discv5`) // UDP port for discovery v5
|
ENRKey() string
|
||||||
)
|
}
|
||||||
|
|
||||||
type record struct {
|
type pair struct {
|
||||||
k []byte
|
k []byte
|
||||||
v []byte
|
v []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type ENR struct {
|
type Record struct {
|
||||||
seq uint32 // sequence number
|
seq uint32 // sequence number
|
||||||
signature []byte // record's signature
|
signature []byte // record's signature
|
||||||
raw []byte // RLP encoded record
|
raw []byte // RLP encoded record
|
||||||
records []record // list of all key/value pairs, sorted prior to RLP encoding
|
pairs []pair // list of all key/value pairs, sorted prior to RLP encoding
|
||||||
dirty bool // keeps track if record was modified after it was signed and encoded
|
signed bool // keeps track if record was modified after it was signed and encoded
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewENR() *ENR {
|
func (r Record) Seq() uint32 {
|
||||||
return &ENR{
|
return r.seq
|
||||||
dirty: true,
|
}
|
||||||
|
|
||||||
|
func (r *Record) SetSeq(s uint32) {
|
||||||
|
r.signed = false
|
||||||
|
r.seq = s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Record) Load(k Key) (bool, error) {
|
||||||
|
for _, p := range r.pairs {
|
||||||
|
if string(p.k) == k.ENRKey() {
|
||||||
|
err := rlp.DecodeBytes(p.v, k)
|
||||||
|
return true, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ENR) GetID() (string, error) {
|
return false, errors.New("record does not exist")
|
||||||
for _, r := range e.records {
|
|
||||||
if bytes.Compare(ID, r.k) == 0 {
|
|
||||||
return string(r.v), nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", errors.New("id record does not exist")
|
func (r *Record) Set(k Key) error {
|
||||||
}
|
r.signed = false
|
||||||
|
blob, err := rlp.EncodeToBytes(k)
|
||||||
func (e *ENR) SetID(id string) {
|
|
||||||
e.dirty = true
|
|
||||||
e.records = append(e.records, record{ID, []byte(id)})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) GetSecp256k1() ([]byte, error) {
|
|
||||||
for _, r := range e.records {
|
|
||||||
if bytes.Compare(SECP256K1, r.k) == 0 {
|
|
||||||
return r.v, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("secp256k1 record does not exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) SetSecp256k1(pk []byte) {
|
|
||||||
e.dirty = true
|
|
||||||
e.records = append(e.records, record{SECP256K1, pk})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) GetIPv4() (net.IP, error) {
|
|
||||||
for _, r := range e.records {
|
|
||||||
if bytes.Compare(IP4, r.k) == 0 {
|
|
||||||
if len(r.v) != net.IPv4len {
|
|
||||||
return nil, errors.New("wrong ipv4 record length")
|
|
||||||
}
|
|
||||||
return net.IP(r.v), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("ip4 record does not exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) SetIPv4(ip net.IP) error {
|
|
||||||
e.dirty = true
|
|
||||||
ipv4 := ip.To4()
|
|
||||||
if ipv4 == nil {
|
|
||||||
return errors.New("param is not a valid ipv4 address")
|
|
||||||
}
|
|
||||||
e.records = append(e.records, record{IP4, ipv4})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) GetIPv6() (net.IP, error) {
|
|
||||||
for _, r := range e.records {
|
|
||||||
if bytes.Compare(IP6, r.k) == 0 {
|
|
||||||
if len(r.v) != net.IPv6len {
|
|
||||||
return nil, errors.New("wrong ipv6 record length")
|
|
||||||
}
|
|
||||||
return net.IP(r.v), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("ip6 record does not exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) SetIPv6(ip net.IP) error {
|
|
||||||
if len(ip) != net.IPv6len {
|
|
||||||
return errors.New("param length is not equal to 16 bytes")
|
|
||||||
}
|
|
||||||
e.dirty = true
|
|
||||||
e.records = append(e.records, record{IP6, ip})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) GetDiscv5() (uint32, error) {
|
|
||||||
for _, r := range e.records {
|
|
||||||
if bytes.Compare(DISCV5, r.k) == 0 {
|
|
||||||
buf := bytes.NewBuffer(r.v)
|
|
||||||
var port uint32
|
|
||||||
err := binary.Read(buf, binary.BigEndian, &port)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
|
}
|
||||||
|
r.pairs = append(r.pairs, pair{[]byte(k.ENRKey()), blob})
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return port, nil
|
func (r Record) EncodeRLP(w io.Writer) error {
|
||||||
}
|
if !r.signed {
|
||||||
|
return errors.New("record is not signed")
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, errors.New("secp256k1 record does not exist")
|
_, err := w.Write(r.raw)
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ENR) SetDiscv5(port uint32) error {
|
func (r *Record) DecodeRLP(s *rlp.Stream) error {
|
||||||
e.dirty = true
|
var err error
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
err := binary.Write(buf, binary.BigEndian, port)
|
r.signature, err = s.Bytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
e.records = append(e.records, record{DISCV5, buf.Bytes()})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) GetRaw(k []byte) ([]byte, error) {
|
|
||||||
for _, r := range e.records {
|
|
||||||
if bytes.Compare(r.k, k) == 0 {
|
|
||||||
return r.v, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("record does not exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) SetRaw(k []byte, v []byte) {
|
|
||||||
e.dirty = true
|
|
||||||
e.records = append(e.records, record{k, v})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) Encode() ([]byte, error) {
|
|
||||||
if e.dirty {
|
|
||||||
return nil, errors.New("record is not signed")
|
|
||||||
}
|
|
||||||
return e.raw, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) NodeAddress() ([]byte, error) {
|
|
||||||
pk, err := e.GetSecp256k1()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
digest := crypto.Keccak256Hash(pk)
|
|
||||||
|
|
||||||
return digest.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) Decode(data []byte) error {
|
|
||||||
if len(data) > RECORD_MAX_SIZE {
|
|
||||||
return errors.New("record is too big")
|
|
||||||
}
|
|
||||||
|
|
||||||
s := rlp.NewStream(bytes.NewReader(data), RECORD_MAX_SIZE)
|
|
||||||
|
|
||||||
signature, err := s.Bytes()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// consume the list prefix
|
|
||||||
_, err = s.List()
|
_, err = s.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
seq, err := s.Uint()
|
if err := s.Decode(&r.seq); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var records []record
|
|
||||||
|
|
||||||
// read key/value pairs until we reach rlp.EOL
|
// read key/value pairs until we reach rlp.EOL
|
||||||
for _, _, err = s.Kind(); err == nil; _, _, err = s.Kind() {
|
for _, _, err = s.Kind(); err == nil; _, _, err = s.Kind() {
|
||||||
key, err2 := s.Bytes()
|
key, err2 := s.Bytes()
|
||||||
|
|
@ -240,115 +129,120 @@ func (e *ENR) Decode(data []byte) error {
|
||||||
return err2
|
return err2
|
||||||
}
|
}
|
||||||
|
|
||||||
records = append(records, record{k: key, v: value})
|
r.pairs = append(r.pairs, pair{k: key, v: value})
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != rlp.EOL {
|
if err != rlp.EOL {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
e.signature = signature
|
err = r.verifySignature()
|
||||||
e.raw = data
|
|
||||||
e.seq = uint32(seq)
|
|
||||||
e.records = records
|
|
||||||
|
|
||||||
err = e.verifySignature()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
e.dirty = false
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ENR) Sign(privkey *ecdsa.PrivateKey) error {
|
|
||||||
e.seq = e.seq + 1
|
|
||||||
|
|
||||||
e.SetID(ID_SECP256k1_KECCAK)
|
|
||||||
|
|
||||||
pk := (*btcec.PublicKey)(&privkey.PublicKey).SerializeCompressed()
|
|
||||||
e.SetSecp256k1(pk)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
e.signature, e.raw, err = e.SignAndEncode(privkey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark record ready for encoding
|
// mark record ready for encoding
|
||||||
e.dirty = false
|
r.signed = true
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ENR) SignAndEncode(privkey *ecdsa.PrivateKey) ([]byte, []byte, error) {
|
func (r Record) Equal(o Record) (bool, error) {
|
||||||
content, err := e.SerialisedContent()
|
rr, err := r.serialisedContent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
digest := crypto.Keccak256Hash(content)
|
oo, err := o.serialisedContent()
|
||||||
|
|
||||||
signature, err := crypto.Sign(digest.Bytes(), privkey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
blob, err := rlp.EncodeToBytes(signature)
|
if bytes.Compare(rr, oo) != 0 {
|
||||||
if err != nil {
|
return false, nil
|
||||||
return nil, nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
raw := append(blob, content...)
|
if err := r.verifySignature(); err != nil {
|
||||||
|
return false, err
|
||||||
return signature, raw, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ENR) SerialisedContent() ([]byte, error) {
|
if err := o.verifySignature(); err != nil {
|
||||||
var buffer bytes.Buffer
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
blob, err := rlp.EncodeToBytes(e.seq)
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Record) NodeAddr() ([]byte, error) {
|
||||||
|
var secp256k1 Secp256k1
|
||||||
|
|
||||||
|
_, err := r.Load(&secp256k1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = buffer.Write(blob)
|
digest := crypto.Keccak256Hash(secp256k1)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return digest.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(e.records, func(i, j int) bool {
|
func (r *Record) Sign(privkey *ecdsa.PrivateKey) error {
|
||||||
return bytes.Compare(e.records[i].k, e.records[j].k) < 0
|
r.seq = r.seq + 1
|
||||||
|
|
||||||
|
id := ID(ID_SECP256k1_KECCAK)
|
||||||
|
|
||||||
|
r.Set(id)
|
||||||
|
|
||||||
|
pk := (*btcec.PublicKey)(&privkey.PublicKey).SerializeCompressed()
|
||||||
|
secp256k1 := Secp256k1(pk)
|
||||||
|
r.Set(secp256k1)
|
||||||
|
|
||||||
|
return r.signAndEncode(privkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Record) serialisedContent() ([]byte, error) {
|
||||||
|
sort.Slice(r.pairs, func(i, j int) bool {
|
||||||
|
return string(r.pairs[i].k) < string(r.pairs[j].k)
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, r := range e.records {
|
list := []interface{}{r.seq}
|
||||||
kk, err := rlp.EncodeToBytes(r.k)
|
|
||||||
|
for _, p := range r.pairs {
|
||||||
|
list = append(list, p.k, p.v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rlp.EncodeToBytes(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Record) signAndEncode(privkey *ecdsa.PrivateKey) error {
|
||||||
|
sigcontent, err := r.serialisedContent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = buffer.Write(kk)
|
digest := crypto.Keccak256Hash(sigcontent)
|
||||||
|
|
||||||
|
r.signature, err = crypto.Sign(digest.Bytes(), privkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
vv, err := rlp.EncodeToBytes(r.v)
|
blob, err := rlp.EncodeToBytes(r.signature)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = buffer.Write(vv)
|
r.raw = append(blob, sigcontent...)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
// mark record ready for encoding
|
||||||
}
|
r.signed = true
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrapList(buffer.Bytes()), nil
|
func (r *Record) verifySignature() error {
|
||||||
}
|
var id ID
|
||||||
|
_, err := r.Load(&id)
|
||||||
func (e *ENR) verifySignature() error {
|
|
||||||
id, err := e.GetID()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -359,7 +253,8 @@ func (e *ENR) verifySignature() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get publickey from record
|
// get publickey from record
|
||||||
blob, err := e.GetSecp256k1()
|
var blob Secp256k1
|
||||||
|
_, err = r.Load(&blob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -371,13 +266,14 @@ func (e *ENR) verifySignature() error {
|
||||||
pubkey1 := pk.SerializeUncompressed()
|
pubkey1 := pk.SerializeUncompressed()
|
||||||
|
|
||||||
// get publickey from message and signature
|
// get publickey from message and signature
|
||||||
content, err := e.SerialisedContent()
|
sigcontent, err := r.serialisedContent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
digest := crypto.Keccak256Hash(content)
|
digest := crypto.Keccak256Hash(sigcontent)
|
||||||
pubkey2, err := crypto.Ecrecover(digest.Bytes(), e.signature)
|
|
||||||
|
pubkey2, err := crypto.Ecrecover(digest.Bytes(), r.signature)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -388,9 +284,3 @@ func (e *ENR) verifySignature() error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrapList(c []byte) []byte {
|
|
||||||
head := make([]byte, 9)
|
|
||||||
res := rlp.LengthPrefix(head, uint64(len(c)))
|
|
||||||
return append(res, c...)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,11 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -32,113 +32,119 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetSetID(t *testing.T) {
|
func TestGetSetID(t *testing.T) {
|
||||||
id := "someid"
|
id := ID("someid")
|
||||||
e := NewENR()
|
var r Record
|
||||||
e.SetID(id)
|
r.Set(id)
|
||||||
|
|
||||||
got, err := e.GetID()
|
var id2 ID
|
||||||
|
|
||||||
|
_, err := r.Load(&id2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %#v", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if got != id {
|
if id != id2 {
|
||||||
t.Fatalf("got %#v, expected %#v", got, id)
|
t.Fatalf("got %#v, expected %#v", id2, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSetIP4(t *testing.T) {
|
func TestGetSetIP4(t *testing.T) {
|
||||||
ip := net.IP{192, 168, 0, 3}
|
ip := IP4(net.IP{192, 168, 0, 3})
|
||||||
e := NewENR()
|
var r Record
|
||||||
e.SetIPv4(ip)
|
r.Set(ip)
|
||||||
|
|
||||||
got, err := e.GetIPv4()
|
var ip2 IP4
|
||||||
|
|
||||||
|
_, err := r.Load(&ip2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %#v", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !got.Equal(ip) {
|
if bytes.Compare(ip, ip2) != 0 {
|
||||||
t.Fatalf("got %#v, expected %#v", got, ip)
|
t.Fatalf("got %#v, expected %#v", ip2, ip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSetIP6(t *testing.T) {
|
func TestGetSetIP6(t *testing.T) {
|
||||||
ip := net.IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}
|
ip := IP6(net.IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68})
|
||||||
e := NewENR()
|
var r Record
|
||||||
e.SetIPv6(ip)
|
r.Set(ip)
|
||||||
|
|
||||||
got, err := e.GetIPv6()
|
var ip2 IP6
|
||||||
|
|
||||||
|
_, err := r.Load(&ip2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %#v", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !got.Equal(ip) {
|
if bytes.Compare(ip, ip2) != 0 {
|
||||||
t.Fatalf("got %#v, expected %#v", got, ip)
|
t.Fatalf("got %#v, expected %#v", ip2, ip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSetDiscv5(t *testing.T) {
|
func TestGetSetDiscv5(t *testing.T) {
|
||||||
port := uint32(30309)
|
port := DiscV5(30309)
|
||||||
e := NewENR()
|
var r Record
|
||||||
|
r.Set(port)
|
||||||
|
|
||||||
err := e.SetDiscv5(port)
|
var port2 DiscV5
|
||||||
|
|
||||||
|
_, err := r.Load(&port2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %#v", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
got, err := e.GetDiscv5()
|
if port != port2 {
|
||||||
if err != nil {
|
t.Fatalf("got %#v, expected %#v", port2, port)
|
||||||
t.Fatalf("error: %#v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got != port {
|
|
||||||
t.Fatalf("got %#v, expected %#v", got, port)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetSetSecp256k1(t *testing.T) {
|
func TestGetSetSecp256k1(t *testing.T) {
|
||||||
privkey, err := crypto.HexToECDSA(privkeyHex)
|
privkey, err := crypto.HexToECDSA(privkeyHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %#v", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
e := NewENR()
|
var r Record
|
||||||
|
|
||||||
err = e.Sign(privkey)
|
err = r.Sign(privkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %#v", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
got, err := e.GetSecp256k1()
|
var pk Secp256k1
|
||||||
|
|
||||||
|
_, err = r.Load(&pk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %#v", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := (*btcec.PublicKey)(&privkey.PublicKey).SerializeCompressed()
|
expected := (*btcec.PublicKey)(&privkey.PublicKey).SerializeCompressed()
|
||||||
if bytes.Compare(got, expected) != 0 {
|
if bytes.Compare(pk, expected) != 0 {
|
||||||
t.Fatalf("got %#v, expected %#v", got, expected)
|
t.Fatalf("got %#v, expected %#v", pk, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDirty(t *testing.T) {
|
func TestDirty(t *testing.T) {
|
||||||
privkey, err := crypto.HexToECDSA(privkeyHex)
|
privkey, err := crypto.HexToECDSA(privkeyHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %#v", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
e := NewENR()
|
var r Record
|
||||||
|
|
||||||
err = e.Sign(privkey)
|
err = r.Sign(privkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error: %#v", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := e.Encode(); err != nil {
|
if _, err := rlp.EncodeToBytes(r); err != nil {
|
||||||
t.Fatalf("error: %#v", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
e.SetRaw([]byte(`some key`), []byte(`some value`))
|
r.SetSeq(3)
|
||||||
|
|
||||||
if _, err := e.Encode(); err == nil {
|
if _, err := rlp.EncodeToBytes(r); err == nil {
|
||||||
t.Fatal("expected err, got nil")
|
t.Fatal("expected err, got nil")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -149,47 +155,37 @@ func TestSignEncodeAndDecode(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
e := NewENR()
|
var r Record
|
||||||
e.SetDiscv5(30303)
|
port := DiscV5(30303)
|
||||||
e.SetIPv4(net.ParseIP("127.0.0.1"))
|
r.Set(port)
|
||||||
|
|
||||||
err = e.Sign(privkey)
|
ipv4 := IP4(net.ParseIP("127.0.0.1"))
|
||||||
|
r.Set(ipv4)
|
||||||
|
|
||||||
|
err = r.Sign(privkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
record, err := e.Encode()
|
blob, err := rlp.EncodeToBytes(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
e2 := NewENR()
|
var r2 Record
|
||||||
|
err = rlp.DecodeBytes(blob, &r2)
|
||||||
err = e2.Decode(record)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(e, e2) {
|
if ok, err := r.Equal(r2); err != nil || !ok {
|
||||||
t.Errorf("got\n%#v, expected\n%#v", e2, e)
|
t.Errorf("records not equal ; got\n%#v, expected\n%#v", r2, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedRecord := "b8415571f9a36b1e26c366745894656dd1565033cdeda18d330c9a9bac67dfc3e786556b0490e509372fa9db5abf418accd895467e8ff047bbdc147789bef71a2cc401f8560186646973637635840000765f82696490736563703235366b312d6b656363616b83697034847f00000189736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138"
|
_, err = rlp.EncodeToBytes(r2)
|
||||||
|
|
||||||
got := hex.EncodeToString(record)
|
|
||||||
if got != expectedRecord {
|
|
||||||
t.Errorf("got\n%#v, expected\n%#v", got, expectedRecord)
|
|
||||||
}
|
|
||||||
|
|
||||||
blob, err := e2.Encode()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
got = hex.EncodeToString(blob)
|
|
||||||
if got != expectedRecord {
|
|
||||||
t.Errorf("got\n%#v, expected\n%#v", got, expectedRecord)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeAddress(t *testing.T) {
|
func TestNodeAddress(t *testing.T) {
|
||||||
|
|
@ -198,14 +194,14 @@ func TestNodeAddress(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
e := NewENR()
|
var r Record
|
||||||
|
|
||||||
err = e.Sign(privkey)
|
err = r.Sign(privkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, err := e.NodeAddress()
|
addr, err := r.NodeAddr()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
p2p/enr/id.go
Normal file
25
p2p/enr/id.go
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package enr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ID string
|
||||||
|
|
||||||
|
func (ID) ENRKey() string {
|
||||||
|
return "id"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v ID) EncodeRLP(w io.Writer) error {
|
||||||
|
id := string(v)
|
||||||
|
return rlp.Encode(w, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ID) DecodeRLP(s *rlp.Stream) error {
|
||||||
|
if err := s.Decode((*string)(v)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
35
p2p/enr/ip4.go
Normal file
35
p2p/enr/ip4.go
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
package enr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IP4 represents an 4-byte IPv4 address in a node record.
|
||||||
|
type IP4 net.IP
|
||||||
|
|
||||||
|
// ENRKey returns the node record key for an IPv4 address.
|
||||||
|
func (IP4) ENRKey() string {
|
||||||
|
return "ip4"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v IP4) EncodeRLP(w io.Writer) error {
|
||||||
|
ip4 := net.IP(v).To4()
|
||||||
|
if ip4 == nil {
|
||||||
|
return fmt.Errorf("invalid IPv4 address: %v", v)
|
||||||
|
}
|
||||||
|
return rlp.Encode(w, ip4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *IP4) DecodeRLP(s *rlp.Stream) error {
|
||||||
|
if err := s.Decode((*net.IP)(v)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(*v) != 4 {
|
||||||
|
return fmt.Errorf("invalid IPv4 address, want 4 bytes: %v", *v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
32
p2p/enr/ip6.go
Normal file
32
p2p/enr/ip6.go
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
package enr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IP6 represents an 16-byte IPv6 address in a node record.
|
||||||
|
type IP6 net.IP
|
||||||
|
|
||||||
|
// ENRKey returns the node record key for an IPv6 address.
|
||||||
|
func (IP6) ENRKey() string {
|
||||||
|
return "ip6"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v IP6) EncodeRLP(w io.Writer) error {
|
||||||
|
ip6 := net.IP(v)
|
||||||
|
return rlp.Encode(w, ip6)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *IP6) DecodeRLP(s *rlp.Stream) error {
|
||||||
|
if err := s.Decode((*net.IP)(v)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(*v) != 16 {
|
||||||
|
return fmt.Errorf("invalid IPv6 address, want 16 bytes: %v", *v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
25
p2p/enr/secp256k1.go
Normal file
25
p2p/enr/secp256k1.go
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package enr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Secp256k1 []byte
|
||||||
|
|
||||||
|
func (Secp256k1) ENRKey() string {
|
||||||
|
return "secp256k1"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Secp256k1) EncodeRLP(w io.Writer) error {
|
||||||
|
blob := []byte(v)
|
||||||
|
return rlp.Encode(w, blob)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Secp256k1) DecodeRLP(s *rlp.Stream) error {
|
||||||
|
if err := s.Decode((*[]byte)(v)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue