mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 01:13:45 +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
|
||||
}
|
||||
|
||||
// Record represents Ethereum Node Record
|
||||
type Record struct {
|
||||
seq uint32 // sequence number
|
||||
signature []byte // record's signature
|
||||
|
|
@ -65,15 +66,20 @@ type Record struct {
|
|||
pairs []pair // sorted list of all key/value pairs
|
||||
}
|
||||
|
||||
// Seq return record's sequence number
|
||||
func (r Record) Seq() uint32 {
|
||||
return r.seq
|
||||
}
|
||||
|
||||
// SetSeq update record's sequence number. Nodes should increase the number whenever the record changes.
|
||||
func (r *Record) SetSeq(s uint32) {
|
||||
r.signature = nil
|
||||
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) {
|
||||
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})
|
||||
}
|
||||
|
||||
// EncodeRLP implements rlp.Encoder.
|
||||
// Sign must be called prior to calling rlp.Encode
|
||||
func (r Record) EncodeRLP(w io.Writer) error {
|
||||
if r.signature == nil {
|
||||
return errors.New("record is not signed")
|
||||
|
|
@ -117,6 +125,7 @@ func (r Record) EncodeRLP(w io.Writer) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// DecodeRLP implements rlp.Decoder.
|
||||
func (r *Record) DecodeRLP(s *rlp.Stream) error {
|
||||
raw, err := s.Raw()
|
||||
if err != nil {
|
||||
|
|
@ -174,6 +183,7 @@ func (r *Record) DecodeRLP(s *rlp.Stream) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// NodeAddr returns node's address - keccak256 hash of the public key.
|
||||
func (r *Record) NodeAddr() ([]byte, error) {
|
||||
var secp256k1 Secp256k1
|
||||
|
||||
|
|
@ -189,6 +199,9 @@ func (r *Record) NodeAddr() ([]byte, error) {
|
|||
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 {
|
||||
pk := (*btcec.PublicKey)(&privkey.PublicKey)
|
||||
r.seq = r.seq + 1
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ const (
|
|||
privkeyHex = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
||||
)
|
||||
|
||||
// TestGetSetID tests encoding/decoding and setting/getting of the enr.ID type
|
||||
func TestGetSetID(t *testing.T) {
|
||||
id := ID("someid")
|
||||
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) {
|
||||
ip := IP4(net.IP{192, 168, 0, 3})
|
||||
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) {
|
||||
ip := IP6(net.IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68})
|
||||
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) {
|
||||
port := DiscPort(30309)
|
||||
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) {
|
||||
privkey, err := crypto.HexToECDSA(privkeyHex)
|
||||
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) {
|
||||
privkey, err := crypto.HexToECDSA(privkeyHex)
|
||||
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) {
|
||||
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) {
|
||||
privkey, err := crypto.HexToECDSA(privkeyHex)
|
||||
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) {
|
||||
privkey, err := crypto.HexToECDSA(privkeyHex)
|
||||
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) {
|
||||
enc, _ := hex.DecodeString("f896b840638a54215d80a6713c8d523a6adc4e6e73652d859103a36b700851cb0e61b66b8ebfc1a610c57d732ec6e0a8f06a9a7a28df5051ece514702ff9cdff0b11f454018664697363763582765f82696490736563703235366b312d6b656363616b83697034847f00000189736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138")
|
||||
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) {
|
||||
privkey, err := crypto.HexToECDSA(privkeyHex)
|
||||
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) {
|
||||
privkey, err := crypto.HexToECDSA(privkeyHex)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ func (g *generic) DecodeRLP(s *rlp.Stream) error {
|
|||
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 {
|
||||
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.
|
||||
type DiscPort uint16
|
||||
|
||||
// ENRKey returns the node record key for an UDP port for discovery.
|
||||
func (DiscPort) ENRKey() string {
|
||||
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".
|
||||
type ID string
|
||||
|
||||
// ENRKey returns the node record key for its identity scheme.
|
||||
func (ID) ENRKey() string {
|
||||
return "id"
|
||||
}
|
||||
|
|
@ -71,6 +75,7 @@ func (IP4) ENRKey() string {
|
|||
return "ip4"
|
||||
}
|
||||
|
||||
// EncodeRLP implements rlp.Encoder.
|
||||
func (v IP4) EncodeRLP(w io.Writer) error {
|
||||
ip4 := net.IP(v).To4()
|
||||
if ip4 == nil {
|
||||
|
|
@ -79,6 +84,7 @@ func (v IP4) EncodeRLP(w io.Writer) error {
|
|||
return rlp.Encode(w, ip4)
|
||||
}
|
||||
|
||||
// DecodeRLP implements rlp.Decoder.
|
||||
func (v *IP4) DecodeRLP(s *rlp.Stream) error {
|
||||
if err := s.Decode((*net.IP)(v)); err != nil {
|
||||
return err
|
||||
|
|
@ -97,11 +103,13 @@ func (IP6) ENRKey() string {
|
|||
return "ip6"
|
||||
}
|
||||
|
||||
// EncodeRLP implements rlp.Encoder.
|
||||
func (v IP6) EncodeRLP(w io.Writer) error {
|
||||
ip6 := net.IP(v)
|
||||
return rlp.Encode(w, ip6)
|
||||
}
|
||||
|
||||
// DecodeRLP implements rlp.Decoder.
|
||||
func (v *IP6) DecodeRLP(s *rlp.Stream) error {
|
||||
if err := s.Decode((*net.IP)(v)); err != nil {
|
||||
return err
|
||||
|
|
@ -115,16 +123,19 @@ func (v *IP6) DecodeRLP(s *rlp.Stream) error {
|
|||
// Secp256k1 is compressed secp256k1 public key.
|
||||
type Secp256k1 ecdsa.PublicKey
|
||||
|
||||
// ENRKey returns the node record key for the secp256k1 public key.
|
||||
func (Secp256k1) ENRKey() string {
|
||||
return "secp256k1"
|
||||
}
|
||||
|
||||
// EncodeRLP implements rlp.Encoder.
|
||||
func (v Secp256k1) EncodeRLP(w io.Writer) error {
|
||||
pk := btcec.PublicKey(v)
|
||||
|
||||
return rlp.Encode(w, pk.SerializeCompressed())
|
||||
}
|
||||
|
||||
// DecodeRLP implements rlp.Decoder.
|
||||
func (v *Secp256k1) DecodeRLP(s *rlp.Stream) error {
|
||||
buf := make([]byte, 33)
|
||||
if err := s.Decode(&buf); err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue