Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

implement Ethereum Node Entry, EIP-778 #11354

Closed
wants to merge 4 commits into from

Conversation

NamsooCho
Copy link
Contributor

Implemets EIP-778(Ethereum Node Entry).
This is required to make EIP-2364(My current WIP PR(#11300 ).

@parity-cla-bot
Copy link

It looks like @NamsooCho signed our Contributor License Agreement. 👍

Many thanks,

Parity Technologies CLA Bot

@dvdplm dvdplm added the A0-pleasereview 🤓 Pull request needs code review. label Jan 6, 2020
seq: u64,
signature: Option<Vec<u8>>,
raw: Option<Vec<u8>>, // RLP encoded record.
pairs: HashMap<String, Value>, // Sorted list of key/value pairs.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean by sorted list here, but HashMap is an unordered collection if you want sorted by the keys then use BTreeMap instead

Copy link
Contributor Author

@NamsooCho NamsooCho Jan 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

pub fn set(&mut self, value: &Value) {
self.invalidate();
let val = self.pairs.entry(value.enr_key()).or_insert(value.clone());
*val = value.clone();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems needless to first write value if it is empty and then replace one more time,

replace line 127-128 with self.pairs.insert(value.enr_key(), value.clone()) since we just overwrite previous values if it's already in the map?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

/// Add or update a value for a key.
pub fn set(&mut self, value: &Value) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider taking Value by value instead because it is intended to be consumed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


/// Provide custom verify method for each scheme.
pub trait Scheme {
fn verify(&self, r: &Record, sig: &Vec<u8>) -> bool;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make more generic by taking slice instead of Vec

Suggested change
fn verify(&self, r: &Record, sig: &Vec<u8>) -> bool;
fn verify(&self, r: &Record, sig: &[u8]) -> bool;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

/// A node record entry.
/// A new node record entry should implements this trait.
pub trait Entry {
fn enr_key(&self) -> String;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we replace this with an associated constant since these are just constants for each type that implements it?

In order to avoid allocating a string each time this is called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This codes use trait object for Entry type.
rust-lang/rust#26847

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So an Entry is a key-value abstraction, but do we actually use it and need it?

}

/// Holes scheme for some type.
pub struct SchemeMap<T: Scheme>(HashMap<String, T>);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trait bounds on structs are considered a bad practice,

Suggested change
pub struct SchemeMap<T: Scheme>(HashMap<String, T>);
pub struct SchemeMap<T>(HashMap<String, T>);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

/// Holes scheme for some type.
pub struct SchemeMap<T: Scheme>(HashMap<String, T>);

impl<T: Scheme> SchemeMap<T> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain the relation between SchemeMap and Record?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current ENR scheme is only "v4".
But may be added later.
SchemeMap contains many schemes like "v4" and others.
Record represents one version of scheme.
This implementation supports many version of schemes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

identity scheme is defined as a predefined id key in the spec
https://eips.ethereum.org/EIPS/eip-778
I'm not sure we need SchemeMap here as well
also see https://github.com/sigp/rust-libp2p/blob/discv5/misc/enr/src/lib.rs

self.signature.clone()
}

pub fn scheme(&self) -> Option<String> {
Copy link
Collaborator

@niklasad1 niklasad1 Jan 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

documentation please,

I'm getting confused why this using Id("".to_owned()) only? Does scheme mean Id or what?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get the scheme represented by a string.
Since parameter id of get() has a Id type,
get can call enr_key().
So, we just pass it with empty string.

self.raw = None;
}

pub fn seq(&self) -> u64 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn seq(&self) -> u64 {
pub fn get_seq(&self) -> u64 {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


/// Tcp port of a node
#[derive(Clone, PartialEq, Debug)]
pub struct Tcp(u16);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All those probably should have pub modifiers or Deref/AsRef implementations. Otherwise the inner value will not be accessible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@sorpaas
Copy link
Collaborator

sorpaas commented Jan 9, 2020

Nice work @NamsooCho, and just want to note that we have another Rust ENR library available (from sigp, https://github.com/sigp/rust-libp2p/tree/discv5/misc/enr), which may be reference for us.


/// Value type for KeyValue pairs in Record struct.
#[derive(Clone, PartialEq, Debug)]
pub enum Value {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is correct, the Value should be a Vec<u8>, these types are just predefined keys
maybe it's better to have them as methods on Record?

seq: u64,
signature: Option<Vec<u8>>,
raw: Option<Vec<u8>>, // RLP encoded record.
pairs: BTreeMap<String, Value>, // Sorted list of key/value pairs.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The keys can technically be any byte sequence

Not all bytes sequence are valid utf-8 strings, so let's create a type for keys that wraps Vec<u8>?
Also I think it should implement rlp::{Encodable, Decodable}

pub struct Record {
seq: u64,
signature: Option<Vec<u8>>,
raw: Option<Vec<u8>>, // RLP encoded record.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not present in the spec, is that some sort of a cache of encoding? can you elaborate why we need this?

#[derive(Default)]
pub struct Record {
seq: u64,
signature: Option<Vec<u8>>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not Vec<u8>?

/// Holes scheme for some type.
pub struct SchemeMap<T: Scheme>(HashMap<String, T>);

impl<T: Scheme> SchemeMap<T> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

identity scheme is defined as a predefined id key in the spec
https://eips.ethereum.org/EIPS/eip-778
I'm not sure we need SchemeMap here as well
also see https://github.com/sigp/rust-libp2p/blob/discv5/misc/enr/src/lib.rs

}

if s.len() > ENR_MAX_SIZE {
error!(target: "network", "Encoded bytes exceed limit(300 bytes), length is {:?}", s.len())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should have a way to return an error instead of just printing a warning

/// A node record entry.
/// A new node record entry should implements this trait.
pub trait Entry {
fn enr_key(&self) -> String;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So an Entry is a key-value abstraction, but do we actually use it and need it?

@ordian
Copy link
Collaborator

ordian commented Feb 10, 2020

hey @NamsooCho, thanks for the PR, may I ask you why you closed it?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A0-pleasereview 🤓 Pull request needs code review.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants