mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 09:23:48 +00:00
p2p/enr: improved documentation.
This commit is contained in:
parent
c219a2ab8b
commit
3b304ff8bf
3 changed files with 36 additions and 0 deletions
|
|
@ -58,6 +58,7 @@ type pair struct {
|
||||||
v rlp.RawValue
|
v rlp.RawValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record represents Ethereum Node Record
|
||||||
type Record struct {
|
type Record struct {
|
||||||
seq uint32 // sequence number
|
seq uint32 // sequence number
|
||||||
signature []byte // record's signature
|
signature []byte // record's signature
|
||||||
|
|
@ -65,15 +66,20 @@ type Record struct {
|
||||||
pairs []pair // sorted list of all key/value pairs
|
pairs []pair // sorted list of all key/value pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Seq return record's sequence number
|
||||||
func (r Record) Seq() uint32 {
|
func (r Record) Seq() uint32 {
|
||||||
return r.seq
|
return r.seq
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetSeq update record's sequence number. Nodes should increase the number whenever the record changes.
|
||||||
func (r *Record) SetSeq(s uint32) {
|
func (r *Record) SetSeq(s uint32) {
|
||||||
r.signature = nil
|
r.signature = nil
|
||||||
r.seq = s
|
r.seq = s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load is loading a key/value pair based on provided key from the record.
|
||||||
|
// It returns false if such key cannot be found.
|
||||||
|
// It returns an error if there is a problem with RLP decoding of the pair.
|
||||||
func (r *Record) Load(k Key) (bool, error) {
|
func (r *Record) Load(k Key) (bool, error) {
|
||||||
i := sort.Search(len(r.pairs), func(i int) bool { return r.pairs[i].k >= k.ENRKey() })
|
i := sort.Search(len(r.pairs), func(i int) bool { return r.pairs[i].k >= k.ENRKey() })
|
||||||
|
|
||||||
|
|
@ -109,6 +115,8 @@ func (r *Record) Set(k Key) {
|
||||||
r.pairs = append(r.pairs, pair{k.ENRKey(), blob})
|
r.pairs = append(r.pairs, pair{k.ENRKey(), blob})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodeRLP implements rlp.Encoder.
|
||||||
|
// Sign must be called prior to calling rlp.Encode
|
||||||
func (r Record) EncodeRLP(w io.Writer) error {
|
func (r Record) EncodeRLP(w io.Writer) error {
|
||||||
if r.signature == nil {
|
if r.signature == nil {
|
||||||
return errors.New("record is not signed")
|
return errors.New("record is not signed")
|
||||||
|
|
@ -117,6 +125,7 @@ func (r Record) EncodeRLP(w io.Writer) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecodeRLP implements rlp.Decoder.
|
||||||
func (r *Record) DecodeRLP(s *rlp.Stream) error {
|
func (r *Record) DecodeRLP(s *rlp.Stream) error {
|
||||||
raw, err := s.Raw()
|
raw, err := s.Raw()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -174,6 +183,7 @@ func (r *Record) DecodeRLP(s *rlp.Stream) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodeAddr returns node's address - keccak256 hash of the public key.
|
||||||
func (r *Record) NodeAddr() ([]byte, error) {
|
func (r *Record) NodeAddr() ([]byte, error) {
|
||||||
var secp256k1 Secp256k1
|
var secp256k1 Secp256k1
|
||||||
|
|
||||||
|
|
@ -189,6 +199,9 @@ func (r *Record) NodeAddr() ([]byte, error) {
|
||||||
return digest.Bytes(), nil
|
return digest.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sign signs the record with the provided private key.
|
||||||
|
// It updates record's identity scheme and public key.
|
||||||
|
// It returns an error if signed record is bigger than 300 bytes.
|
||||||
func (r *Record) Sign(privkey *ecdsa.PrivateKey) error {
|
func (r *Record) Sign(privkey *ecdsa.PrivateKey) error {
|
||||||
pk := (*btcec.PublicKey)(&privkey.PublicKey)
|
pk := (*btcec.PublicKey)(&privkey.PublicKey)
|
||||||
r.seq = r.seq + 1
|
r.seq = r.seq + 1
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ const (
|
||||||
privkeyHex = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
privkeyHex = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TestGetSetID tests encoding/decoding and setting/getting of the enr.ID type
|
||||||
func TestGetSetID(t *testing.T) {
|
func TestGetSetID(t *testing.T) {
|
||||||
id := ID("someid")
|
id := ID("someid")
|
||||||
var r Record
|
var r Record
|
||||||
|
|
@ -51,6 +52,7 @@ func TestGetSetID(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestGetSetIP4 tests encoding/decoding and setting/getting of the enr.IP4 type
|
||||||
func TestGetSetIP4(t *testing.T) {
|
func TestGetSetIP4(t *testing.T) {
|
||||||
ip := IP4(net.IP{192, 168, 0, 3})
|
ip := IP4(net.IP{192, 168, 0, 3})
|
||||||
var r Record
|
var r Record
|
||||||
|
|
@ -68,6 +70,7 @@ func TestGetSetIP4(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestGetSetIP6 tests encoding/decoding and setting/getting of the enr.IP6 type
|
||||||
func TestGetSetIP6(t *testing.T) {
|
func TestGetSetIP6(t *testing.T) {
|
||||||
ip := IP6(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})
|
||||||
var r Record
|
var r Record
|
||||||
|
|
@ -85,6 +88,7 @@ func TestGetSetIP6(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestGetSetDiscPort tests encoding/decoding and setting/getting of the enr.DiscPort type
|
||||||
func TestGetSetDiscPort(t *testing.T) {
|
func TestGetSetDiscPort(t *testing.T) {
|
||||||
port := DiscPort(30309)
|
port := DiscPort(30309)
|
||||||
var r Record
|
var r Record
|
||||||
|
|
@ -102,6 +106,7 @@ func TestGetSetDiscPort(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestGetSetSecp256k1 tests encoding/decoding and setting/getting of the enr.Secp256k1 type
|
||||||
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 {
|
||||||
|
|
@ -129,6 +134,7 @@ func TestGetSetSecp256k1(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestDirty tests record signature removal on setting of new key/value pair in record.
|
||||||
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 {
|
||||||
|
|
@ -153,6 +159,7 @@ func TestDirty(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestGetSetOverwrite tests value overwrite when setting a new value with an existing key in record.
|
||||||
func TestGetSetOverwrite(t *testing.T) {
|
func TestGetSetOverwrite(t *testing.T) {
|
||||||
var r Record
|
var r Record
|
||||||
|
|
||||||
|
|
@ -174,6 +181,7 @@ func TestGetSetOverwrite(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSignEncodeAndDecode tests signing, RLP encoding and RLP decoding of a record.
|
||||||
func TestSignEncodeAndDecode(t *testing.T) {
|
func TestSignEncodeAndDecode(t *testing.T) {
|
||||||
privkey, err := crypto.HexToECDSA(privkeyHex)
|
privkey, err := crypto.HexToECDSA(privkeyHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -217,6 +225,7 @@ func TestSignEncodeAndDecode(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestNodeAddress tests that record returns correct node address - keccak256 hash of the public key.
|
||||||
func TestNodeAddress(t *testing.T) {
|
func TestNodeAddress(t *testing.T) {
|
||||||
privkey, err := crypto.HexToECDSA(privkeyHex)
|
privkey, err := crypto.HexToECDSA(privkeyHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -242,6 +251,7 @@ func TestNodeAddress(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestPythonInterop tests that Go implementation can successfully RLP decode a record produced by Python implementation.
|
||||||
func TestPythonInterop(t *testing.T) {
|
func TestPythonInterop(t *testing.T) {
|
||||||
enc, _ := hex.DecodeString("f896b840638a54215d80a6713c8d523a6adc4e6e73652d859103a36b700851cb0e61b66b8ebfc1a610c57d732ec6e0a8f06a9a7a28df5051ece514702ff9cdff0b11f454018664697363763582765f82696490736563703235366b312d6b656363616b83697034847f00000189736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138")
|
enc, _ := hex.DecodeString("f896b840638a54215d80a6713c8d523a6adc4e6e73652d859103a36b700851cb0e61b66b8ebfc1a610c57d732ec6e0a8f06a9a7a28df5051ece514702ff9cdff0b11f454018664697363763582765f82696490736563703235366b312d6b656363616b83697034847f00000189736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138")
|
||||||
var r Record
|
var r Record
|
||||||
|
|
@ -271,6 +281,7 @@ func TestPythonInterop(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestRecordTooBig tests that records bigger than 300 bytes cannot be signed.
|
||||||
func TestRecordTooBig(t *testing.T) {
|
func TestRecordTooBig(t *testing.T) {
|
||||||
privkey, err := crypto.HexToECDSA(privkeyHex)
|
privkey, err := crypto.HexToECDSA(privkeyHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -296,6 +307,7 @@ func TestRecordTooBig(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSignEncodeAndDecodeRandom tests encoding/decoding of records containing random key/value pairs.
|
||||||
func TestSignEncodeAndDecodeRandom(t *testing.T) {
|
func TestSignEncodeAndDecodeRandom(t *testing.T) {
|
||||||
privkey, err := crypto.HexToECDSA(privkeyHex)
|
privkey, err := crypto.HexToECDSA(privkeyHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ func (g *generic) DecodeRLP(s *rlp.Stream) error {
|
||||||
return s.Decode(&g.value)
|
return s.Decode(&g.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithKey returns a new Key that can be set in a Record.
|
||||||
|
// v must implement the rlp.Encoder and rlp.Decoder interface.
|
||||||
func WithKey(k string, v interface{}) Key {
|
func WithKey(k string, v interface{}) Key {
|
||||||
return &generic{key: k, value: v}
|
return &generic{key: k, value: v}
|
||||||
}
|
}
|
||||||
|
|
@ -50,6 +52,7 @@ func WithKey(k string, v interface{}) Key {
|
||||||
// DiscPort represents an UDP port for discovery v5.
|
// DiscPort represents an UDP port for discovery v5.
|
||||||
type DiscPort uint16
|
type DiscPort uint16
|
||||||
|
|
||||||
|
// ENRKey returns the node record key for an UDP port for discovery.
|
||||||
func (DiscPort) ENRKey() string {
|
func (DiscPort) ENRKey() string {
|
||||||
return "discv5"
|
return "discv5"
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +62,7 @@ const ID_SECP256k1_KECCAK = "secp256k1-keccak" // identity scheme identifier
|
||||||
// ID is the name of the identity scheme, e.g. "secp256k1-keccak".
|
// ID is the name of the identity scheme, e.g. "secp256k1-keccak".
|
||||||
type ID string
|
type ID string
|
||||||
|
|
||||||
|
// ENRKey returns the node record key for its identity scheme.
|
||||||
func (ID) ENRKey() string {
|
func (ID) ENRKey() string {
|
||||||
return "id"
|
return "id"
|
||||||
}
|
}
|
||||||
|
|
@ -71,6 +75,7 @@ func (IP4) ENRKey() string {
|
||||||
return "ip4"
|
return "ip4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodeRLP implements rlp.Encoder.
|
||||||
func (v IP4) EncodeRLP(w io.Writer) error {
|
func (v IP4) EncodeRLP(w io.Writer) error {
|
||||||
ip4 := net.IP(v).To4()
|
ip4 := net.IP(v).To4()
|
||||||
if ip4 == nil {
|
if ip4 == nil {
|
||||||
|
|
@ -79,6 +84,7 @@ func (v IP4) EncodeRLP(w io.Writer) error {
|
||||||
return rlp.Encode(w, ip4)
|
return rlp.Encode(w, ip4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecodeRLP implements rlp.Decoder.
|
||||||
func (v *IP4) DecodeRLP(s *rlp.Stream) error {
|
func (v *IP4) DecodeRLP(s *rlp.Stream) error {
|
||||||
if err := s.Decode((*net.IP)(v)); err != nil {
|
if err := s.Decode((*net.IP)(v)); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -97,11 +103,13 @@ func (IP6) ENRKey() string {
|
||||||
return "ip6"
|
return "ip6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodeRLP implements rlp.Encoder.
|
||||||
func (v IP6) EncodeRLP(w io.Writer) error {
|
func (v IP6) EncodeRLP(w io.Writer) error {
|
||||||
ip6 := net.IP(v)
|
ip6 := net.IP(v)
|
||||||
return rlp.Encode(w, ip6)
|
return rlp.Encode(w, ip6)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecodeRLP implements rlp.Decoder.
|
||||||
func (v *IP6) DecodeRLP(s *rlp.Stream) error {
|
func (v *IP6) DecodeRLP(s *rlp.Stream) error {
|
||||||
if err := s.Decode((*net.IP)(v)); err != nil {
|
if err := s.Decode((*net.IP)(v)); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -115,16 +123,19 @@ func (v *IP6) DecodeRLP(s *rlp.Stream) error {
|
||||||
// Secp256k1 is compressed secp256k1 public key.
|
// Secp256k1 is compressed secp256k1 public key.
|
||||||
type Secp256k1 ecdsa.PublicKey
|
type Secp256k1 ecdsa.PublicKey
|
||||||
|
|
||||||
|
// ENRKey returns the node record key for the secp256k1 public key.
|
||||||
func (Secp256k1) ENRKey() string {
|
func (Secp256k1) ENRKey() string {
|
||||||
return "secp256k1"
|
return "secp256k1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodeRLP implements rlp.Encoder.
|
||||||
func (v Secp256k1) EncodeRLP(w io.Writer) error {
|
func (v Secp256k1) EncodeRLP(w io.Writer) error {
|
||||||
pk := btcec.PublicKey(v)
|
pk := btcec.PublicKey(v)
|
||||||
|
|
||||||
return rlp.Encode(w, pk.SerializeCompressed())
|
return rlp.Encode(w, pk.SerializeCompressed())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecodeRLP implements rlp.Decoder.
|
||||||
func (v *Secp256k1) DecodeRLP(s *rlp.Stream) error {
|
func (v *Secp256k1) DecodeRLP(s *rlp.Stream) error {
|
||||||
buf := make([]byte, 33)
|
buf := make([]byte, 33)
|
||||||
if err := s.Decode(&buf); err != nil {
|
if err := s.Decode(&buf); err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue