light: give free credits for reserved peers (#9448)

* light: give free credits for reserved peers

* Fix ethcore-light tests

* Test free_flow_params
This commit is contained in:
Wei Tang 2018-09-10 19:45:49 +08:00 committed by GitHub
parent 2177a0179e
commit 44531e3009
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 59 additions and 5 deletions

View File

@ -44,6 +44,9 @@ pub trait IoContext {
/// Persistent peer id /// Persistent peer id
fn persistent_peer_id(&self, peer: PeerId) -> Option<NodeId>; fn persistent_peer_id(&self, peer: PeerId) -> Option<NodeId>;
/// Whether given peer id is reserved peer
fn is_reserved_peer(&self, peer: PeerId) -> bool;
} }
impl<T> IoContext for T where T: ?Sized + NetworkContext { impl<T> IoContext for T where T: ?Sized + NetworkContext {
@ -76,6 +79,10 @@ impl<T> IoContext for T where T: ?Sized + NetworkContext {
fn persistent_peer_id(&self, peer: PeerId) -> Option<NodeId> { fn persistent_peer_id(&self, peer: PeerId) -> Option<NodeId> {
self.session_info(peer).and_then(|info| info.id) self.session_info(peer).and_then(|info| info.id)
} }
fn is_reserved_peer(&self, peer: PeerId) -> bool {
NetworkContext::is_reserved_peer(self, peer)
}
} }
/// Basic context for the protocol. /// Basic context for the protocol.

View File

@ -354,6 +354,7 @@ pub struct LightProtocol {
peers: RwLock<PeerMap>, peers: RwLock<PeerMap>,
capabilities: RwLock<Capabilities>, capabilities: RwLock<Capabilities>,
flow_params: RwLock<Arc<FlowParams>>, flow_params: RwLock<Arc<FlowParams>>,
free_flow_params: Arc<FlowParams>,
handlers: Vec<Arc<Handler>>, handlers: Vec<Arc<Handler>>,
req_id: AtomicUsize, req_id: AtomicUsize,
sample_store: Box<SampleStore>, sample_store: Box<SampleStore>,
@ -383,6 +384,7 @@ impl LightProtocol {
peers: RwLock::new(HashMap::new()), peers: RwLock::new(HashMap::new()),
capabilities: RwLock::new(params.capabilities), capabilities: RwLock::new(params.capabilities),
flow_params: RwLock::new(Arc::new(flow_params)), flow_params: RwLock::new(Arc::new(flow_params)),
free_flow_params: Arc::new(FlowParams::free()),
handlers: Vec::new(), handlers: Vec::new(),
req_id: AtomicUsize::new(0), req_id: AtomicUsize::new(0),
sample_store, sample_store,
@ -706,8 +708,13 @@ impl LightProtocol {
}; };
let capabilities = self.capabilities.read(); let capabilities = self.capabilities.read();
let local_flow = self.flow_params.read(); let cost_local_flow = self.flow_params.read();
let status_packet = status::write_handshake(&status, &capabilities, Some(&**local_flow)); let local_flow = if io.is_reserved_peer(peer) {
&*self.free_flow_params
} else {
&**cost_local_flow
};
let status_packet = status::write_handshake(&status, &capabilities, Some(local_flow));
self.pending_peers.write().insert(peer, PendingPeer { self.pending_peers.write().insert(peer, PendingPeer {
sent_head: chain_info.best_block_hash, sent_head: chain_info.best_block_hash,
@ -818,7 +825,11 @@ impl LightProtocol {
} }
let remote_flow = flow_params.map(|params| (params.create_credits(), params)); let remote_flow = flow_params.map(|params| (params.create_credits(), params));
let local_flow = self.flow_params.read().clone(); let local_flow = if io.is_reserved_peer(peer) {
self.free_flow_params.clone()
} else {
self.flow_params.read().clone()
};
self.peers.write().insert(peer, Mutex::new(Peer { self.peers.write().insert(peer, Mutex::new(Peer {
local_credits: local_flow.create_credits(), local_credits: local_flow.create_credits(),

View File

@ -87,6 +87,10 @@ impl IoContext for Expect {
fn persistent_peer_id(&self, _peer: PeerId) -> Option<NodeId> { fn persistent_peer_id(&self, _peer: PeerId) -> Option<NodeId> {
None None
} }
fn is_reserved_peer(&self, peer: PeerId) -> bool {
peer == 0xff
}
} }
// can't implement directly for Arc due to cross-crate orphan rules. // can't implement directly for Arc due to cross-crate orphan rules.
@ -190,6 +194,10 @@ fn write_handshake(status: &Status, capabilities: &Capabilities, proto: &LightPr
::net::status::write_handshake(status, capabilities, Some(&*flow_params)) ::net::status::write_handshake(status, capabilities, Some(&*flow_params))
} }
fn write_free_handshake(status: &Status, capabilities: &Capabilities, proto: &LightProtocol) -> Vec<u8> {
::net::status::write_handshake(status, capabilities, Some(&proto.free_flow_params))
}
// helper for setting up the protocol handler and provider. // helper for setting up the protocol handler and provider.
fn setup(capabilities: Capabilities) -> (Arc<TestProviderInner>, LightProtocol) { fn setup(capabilities: Capabilities) -> (Arc<TestProviderInner>, LightProtocol) {
let provider = Arc::new(TestProviderInner { let provider = Arc::new(TestProviderInner {
@ -231,6 +239,19 @@ fn handshake_expected() {
proto.on_connect(1, &Expect::Send(1, packet::STATUS, packet_body)); proto.on_connect(1, &Expect::Send(1, packet::STATUS, packet_body));
} }
#[test]
fn reserved_handshake_expected() {
let capabilities = capabilities();
let (provider, proto) = setup(capabilities);
let status = status(provider.client.chain_info());
let packet_body = write_free_handshake(&status, &capabilities, &proto);
proto.on_connect(0xff, &Expect::Send(0xff, packet::STATUS, packet_body));
}
#[test] #[test]
#[should_panic] #[should_panic]
fn genesis_mismatch() { fn genesis_mismatch() {

View File

@ -68,6 +68,7 @@ impl<'a> IoContext for TestIoContext<'a> {
fn protocol_version(&self, _peer: PeerId) -> Option<u8> { Some(::light::net::MAX_PROTOCOL_VERSION) } fn protocol_version(&self, _peer: PeerId) -> Option<u8> { Some(::light::net::MAX_PROTOCOL_VERSION) }
fn persistent_peer_id(&self, _peer: PeerId) -> Option<NodeId> { unimplemented!() } fn persistent_peer_id(&self, _peer: PeerId) -> Option<NodeId> { unimplemented!() }
fn is_reserved_peer(&self, _peer: PeerId) -> bool { false }
} }
// peer-specific data. // peer-specific data.

View File

@ -102,7 +102,7 @@ pub struct NetworkContext<'s> {
sessions: Arc<RwLock<Slab<SharedSession>>>, sessions: Arc<RwLock<Slab<SharedSession>>>,
session: Option<SharedSession>, session: Option<SharedSession>,
session_id: Option<StreamToken>, session_id: Option<StreamToken>,
_reserved_peers: &'s HashSet<NodeId>, reserved_peers: &'s HashSet<NodeId>,
} }
impl<'s> NetworkContext<'s> { impl<'s> NetworkContext<'s> {
@ -121,7 +121,7 @@ impl<'s> NetworkContext<'s> {
session_id: id, session_id: id,
session, session,
sessions, sessions,
_reserved_peers: reserved_peers, reserved_peers: reserved_peers,
} }
} }
@ -190,6 +190,13 @@ impl<'s> NetworkContextTrait for NetworkContext<'s> {
} }
fn subprotocol_name(&self) -> ProtocolId { self.protocol } fn subprotocol_name(&self) -> ProtocolId { self.protocol }
fn is_reserved_peer(&self, peer: PeerId) -> bool {
self.session_info(peer)
.and_then(|info| info.id)
.map(|node| self.reserved_peers.contains(&node))
.unwrap_or(false)
}
} }
/// Shared host information /// Shared host information

View File

@ -285,6 +285,9 @@ pub trait NetworkContext {
/// Returns this object's subprotocol name. /// Returns this object's subprotocol name.
fn subprotocol_name(&self) -> ProtocolId; fn subprotocol_name(&self) -> ProtocolId;
/// Returns whether the given peer ID is a reserved peer.
fn is_reserved_peer(&self, peer: PeerId) -> bool;
} }
impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext { impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext {
@ -331,6 +334,10 @@ impl<'a, T> NetworkContext for &'a T where T: ?Sized + NetworkContext {
fn subprotocol_name(&self) -> ProtocolId { fn subprotocol_name(&self) -> ProtocolId {
(**self).subprotocol_name() (**self).subprotocol_name()
} }
fn is_reserved_peer(&self, peer: PeerId) -> bool {
(**self).is_reserved_peer(peer)
}
} }
/// Network IO protocol handler. This needs to be implemented for each new subprotocol. /// Network IO protocol handler. This needs to be implemented for each new subprotocol.