-
Notifications
You must be signed in to change notification settings - Fork 131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: enr signature changes on restart even if enr content is the same #952
Changes from 4 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,6 @@ use crate::socket; | |
use anyhow::anyhow; | ||
use async_trait::async_trait; | ||
use bytes::BytesMut; | ||
use discv5::enr::EnrPublicKey; | ||
use discv5::{ | ||
enr::{CombinedKey, EnrBuilder, NodeId}, | ||
ConfigBuilder, Discv5, Event, ListenConfig, RequestError, TalkRequest, | ||
|
@@ -17,6 +16,7 @@ use rlp::RlpStream; | |
use serde_json::{json, Value}; | ||
use std::hash::{Hash, Hasher}; | ||
use std::net::Ipv4Addr; | ||
use std::path::PathBuf; | ||
use std::str::FromStr; | ||
use std::{convert::TryFrom, fmt, fs, io, net::SocketAddr, sync::Arc}; | ||
use tokio::sync::mpsc; | ||
|
@@ -69,7 +69,7 @@ impl fmt::Debug for Discovery { | |
} | ||
|
||
impl Discovery { | ||
pub fn new(portal_config: PortalnetConfig) -> Result<Self, String> { | ||
pub fn new(portal_config: PortalnetConfig, node_data_dir: PathBuf) -> Result<Self, String> { | ||
let listen_all_ips = SocketAddr::new( | ||
"0.0.0.0" | ||
.parse() | ||
|
@@ -112,27 +112,28 @@ impl Discovery { | |
}; | ||
|
||
// Check if we have an old version of our Enr and if we do, increase our sequence number | ||
if let Some(enr_file_location) = portal_config.enr_file_location { | ||
let trin_enr_file_location = enr_file_location.join(ENR_FILE_NAME); | ||
if trin_enr_file_location.is_file() { | ||
let data = fs::read_to_string(trin_enr_file_location.clone()) | ||
.expect("Unable to read Trin Enr from file"); | ||
let old_enr = Enr::from_str(&data).expect("Expected read trin.enr to be valid"); | ||
|
||
enr.set_seq(old_enr.seq(), &enr_key) | ||
.expect("Unable to set Enr sequence number"); | ||
|
||
// If the old Enr's signature is different then the new one | ||
if !verify_by_signature(&enr, old_enr.signature()) | ||
&& !verify_by_signature(&old_enr, enr.signature()) | ||
{ | ||
enr.set_seq(old_enr.seq() + 1, &enr_key) | ||
.expect("Unable to increase Enr sequence number"); | ||
} | ||
let trin_enr_path = node_data_dir.join(ENR_FILE_NAME); | ||
if trin_enr_path.is_file() { | ||
let data = fs::read_to_string(trin_enr_path.clone()) | ||
.expect("Unable to read Trin Enr from file"); | ||
let old_enr = Enr::from_str(&data).expect("Expected read trin.enr to be valid"); | ||
enr.set_seq(old_enr.seq(), &enr_key) | ||
.expect("Unable to set Enr sequence number"); | ||
|
||
// If the content is different then increase the sequence number | ||
if get_enr_rlp_content(&enr) != get_enr_rlp_content(&old_enr) { | ||
enr.set_seq(old_enr.seq() + 1, &enr_key) | ||
.expect("Unable to increase Enr sequence number"); | ||
fs::write(trin_enr_path, enr.to_base64()) | ||
.expect("Unable to update Trin Enr to file"); | ||
} else { | ||
// the content is the same, we don't want to change signatures on restart | ||
// so set enr to old one to keep the same signature per sequence number | ||
enr = old_enr; | ||
} | ||
} else { | ||
// Write enr to disk | ||
fs::write(trin_enr_file_location, enr.to_base64()) | ||
.expect("Unable to write Trin Enr to file"); | ||
fs::write(trin_enr_path, enr.to_base64()).expect("Unable to write Trin Enr to file"); | ||
} | ||
|
||
let listen_config = ListenConfig::Ipv4 { | ||
|
@@ -425,7 +426,7 @@ impl AsyncUdpSocket<UtpEnr> for Discv5UdpSocket { | |
|
||
// todo: remove this once sigp/enr implements this for enr's | ||
// we need this because signatures can be different for the same data but still valid | ||
fn verify_by_signature(enr: &Enr, signature: &[u8]) -> bool { | ||
fn get_enr_rlp_content(enr: &Enr) -> BytesMut { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @KolbyML I don't think there is any harm in exposing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we get the update Enr version we can just use compare_content. If we want to expose rlp_content() that is fine too. It just looked like rlp_content() was intentionally privated so that is why I tried to get a compare/verify_by_signature* function added. Cause I didn't want to manually calculate rlp_content in multiple codebases. Anyways up to you. I didn't know making the rlp_content() function public was an option tbh. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do think compare_content is cleaner though There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Neither is a problem. Nothing wrong with exposing it, this does not change the enr and it's not private info in any way |
||
match enr.id() { | ||
Some(ref id) if id == "v4" => { | ||
let mut stream = RlpStream::new_with_buffer(BytesMut::with_capacity(300)); | ||
|
@@ -439,10 +440,10 @@ fn verify_by_signature(enr: &Enr, signature: &[u8]) -> bool { | |
stream.append_raw(v, 1); | ||
} | ||
|
||
enr.public_key().verify_v4(&stream.out(), signature) | ||
stream.out() | ||
} | ||
// unsupported identity schemes | ||
_ => false, | ||
_ => BytesMut::with_capacity(0), | ||
} | ||
} | ||
|
||
|
@@ -463,7 +464,6 @@ mod tests { | |
let mut portalnet_config = PortalnetConfig { | ||
private_key, | ||
bootnodes: Bootnodes::None, | ||
enr_file_location: Some(node_data_dir.clone()), | ||
..Default::default() | ||
}; | ||
|
||
|
@@ -472,15 +472,15 @@ mod tests { | |
assert!(!trin_enr_file_location.is_file()); | ||
|
||
// test trin.enr is made on first run | ||
let discovery = Discovery::new(portalnet_config.clone()).unwrap(); | ||
let discovery = Discovery::new(portalnet_config.clone(), node_data_dir.clone()).unwrap(); | ||
let data = fs::read_to_string(trin_enr_file_location.clone()).unwrap(); | ||
let old_enr = Enr::from_str(&data).unwrap(); | ||
assert_eq!(discovery.local_enr(), old_enr); | ||
assert_eq!(old_enr.seq(), 1); | ||
|
||
// test if Enr changes the Enr sequence is increased and if it is written to disk | ||
portalnet_config.listen_port = 2424; | ||
let discovery = Discovery::new(portalnet_config.clone()).unwrap(); | ||
let discovery = Discovery::new(portalnet_config.clone(), node_data_dir.clone()).unwrap(); | ||
assert_ne!(discovery.local_enr(), old_enr); | ||
let data = fs::read_to_string(trin_enr_file_location.clone()).unwrap(); | ||
let old_enr = Enr::from_str(&data).unwrap(); | ||
|
@@ -489,11 +489,8 @@ mod tests { | |
assert_eq!(discovery.local_enr(), old_enr); | ||
|
||
// test if the enr isn't changed that it's sequence stays the same | ||
let discovery = Discovery::new(portalnet_config).unwrap(); | ||
assert!( | ||
verify_by_signature(&discovery.local_enr(), old_enr.signature()) | ||
&& verify_by_signature(&old_enr, discovery.local_enr().signature()) | ||
); | ||
let discovery = Discovery::new(portalnet_config, node_data_dir).unwrap(); | ||
assert_eq!(discovery.local_enr(), old_enr); | ||
let data = fs::read_to_string(trin_enr_file_location).unwrap(); | ||
let old_enr = Enr::from_str(&data).unwrap(); | ||
assert_eq!(discovery.local_enr().seq(), 2); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
"Expected to read valid Trin Enr from file"