Basic Dandelion transaction routing (#719)
* Initial Dandelion Commit * Changed stem_tx_pool to tx_stempool * Introduction of stem memory pool and stem pool config * Pool push now send to stem memory pool * Add stem transaction functions * Add stem transaction pool * Drastically simplified code structure * Add monitor transactions * Add Dandelion monitor and remove transactions from stempool * Add peer relay monitor * Reconcile block with stempool * Fix total size bug * Add fluff option for pool push * Added details on dandelion monitor * Fix issue with missing parent * Child transaction with stempool parent are now forced stem * Update Dandelion Relay from outgoing peers * Fix missing pool reconciliation * Add the ability to fluff a transaction directly * Fix tests for Dandelion * Missing send_stem_transaction method... * Add fluff handler for wallet * Add logger when successfully updated Dandelion relay * Launch transaction monitor last * Fix dandelion relay misplaced * Add logging and updating for stempool * Additionnal check for stem transaction * Fix 2 Locks in a row
This commit is contained in:
committed by
Ignotus Peverell
parent
7816f35238
commit
fcfe7bc6a4
@@ -64,6 +64,7 @@ enum_from_primitive! {
|
||||
Block,
|
||||
GetCompactBlock,
|
||||
CompactBlock,
|
||||
StemTransaction,
|
||||
Transaction,
|
||||
TxHashSetRequest,
|
||||
TxHashSetArchive
|
||||
|
||||
+22
-2
@@ -235,6 +235,26 @@ impl Peer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends the provided stem transaction to the remote peer. The request may be
|
||||
/// dropped if the remote peer is known to already have the stem transaction.
|
||||
pub fn send_stem_transaction(&self, tx: &core::Transaction) -> Result<(), Error> {
|
||||
if !self.tracking_adapter.has(tx.hash()) {
|
||||
debug!(LOGGER, "Send tx {} to {}", tx.hash(), self.info.addr);
|
||||
self.connection
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send(tx, msg::Type::StemTransaction)
|
||||
} else {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Not sending tx {} to {} (already seen)",
|
||||
tx.hash(),
|
||||
self.info.addr
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends a request for block headers from the provided block locator
|
||||
pub fn send_header_request(&self, locator: Vec<Hash>) -> Result<(), Error> {
|
||||
self.connection
|
||||
@@ -356,9 +376,9 @@ impl ChainAdapter for TrackingAdapter {
|
||||
self.adapter.total_height()
|
||||
}
|
||||
|
||||
fn transaction_received(&self, tx: core::Transaction) {
|
||||
fn transaction_received(&self, tx: core::Transaction, stem: bool) {
|
||||
self.push(tx.hash());
|
||||
self.adapter.transaction_received(tx)
|
||||
self.adapter.transaction_received(tx, stem)
|
||||
}
|
||||
|
||||
fn block_received(&self, b: core::Block, addr: SocketAddr) -> bool {
|
||||
|
||||
+69
-2
@@ -33,6 +33,7 @@ pub struct Peers {
|
||||
pub adapter: Arc<ChainAdapter>,
|
||||
store: PeerStore,
|
||||
peers: RwLock<HashMap<SocketAddr, Arc<RwLock<Peer>>>>,
|
||||
dandelion_relay: RwLock<HashMap<i64, Arc<RwLock<Peer>>>>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Peers {}
|
||||
@@ -44,6 +45,7 @@ impl Peers {
|
||||
adapter,
|
||||
store,
|
||||
peers: RwLock::new(HashMap::new()),
|
||||
dandelion_relay: RwLock::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +73,34 @@ impl Peers {
|
||||
apeer.clone()
|
||||
}
|
||||
|
||||
// Update the dandelion relay
|
||||
pub fn update_dandelion_relay(&self) {
|
||||
let peers = self.outgoing_connected_peers();
|
||||
|
||||
match thread_rng().choose(&peers) {
|
||||
Some(peer) => {
|
||||
// Clear the map and add new relay
|
||||
let dandelion_relay = &self.dandelion_relay;
|
||||
dandelion_relay.write().unwrap().clear();
|
||||
dandelion_relay
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(time::now_utc().to_timespec().sec, peer.clone());
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Successfully updated Dandelion relay to: {}",
|
||||
peer.try_read().unwrap().info.addr
|
||||
);
|
||||
}
|
||||
None => error!(LOGGER, "Could not update dandelion relay"),
|
||||
};
|
||||
}
|
||||
// Get the dandelion relay
|
||||
pub fn get_dandelion_relay(&self) -> HashMap<i64, Arc<RwLock<Peer>>> {
|
||||
let res = self.dandelion_relay.read().unwrap().clone();
|
||||
res
|
||||
}
|
||||
|
||||
pub fn is_known(&self, addr: &SocketAddr) -> bool {
|
||||
self.get_connected_peer(addr).is_some()
|
||||
}
|
||||
@@ -87,6 +117,19 @@ impl Peers {
|
||||
res
|
||||
}
|
||||
|
||||
pub fn outgoing_connected_peers(&self) -> Vec<Arc<RwLock<Peer>>> {
|
||||
let peers = self.connected_peers();
|
||||
let res = peers
|
||||
.iter()
|
||||
.filter(|x| match x.try_read() {
|
||||
Ok(peer) => peer.info.direction == Direction::Outbound,
|
||||
Err(_) => false,
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
res
|
||||
}
|
||||
|
||||
/// Get a peer we're connected to by address.
|
||||
pub fn get_connected_peer(&self, addr: &SocketAddr) -> Option<Arc<RwLock<Peer>>> {
|
||||
self.peers.read().unwrap().get(addr).map(|p| p.clone())
|
||||
@@ -298,6 +341,30 @@ impl Peers {
|
||||
);
|
||||
}
|
||||
|
||||
/// Broadcasts the provided stem transaction to our peer relay.
|
||||
pub fn broadcast_stem_transaction(&self, tx: &core::Transaction) {
|
||||
let dandelion_relay = self.get_dandelion_relay();
|
||||
if dandelion_relay.is_empty() {
|
||||
debug!(LOGGER, "No dandelion relay updating");
|
||||
self.update_dandelion_relay();
|
||||
}
|
||||
// If still empty broadcast then broadcast transaction normally
|
||||
if dandelion_relay.is_empty() {
|
||||
self.broadcast_transaction(tx);
|
||||
}
|
||||
for relay in dandelion_relay.values() {
|
||||
let relay = relay.read().unwrap();
|
||||
if relay.is_connected() {
|
||||
if let Err(e) = relay.send_stem_transaction(tx) {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Error sending stem transaction to peer relay: {:?}", e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Broadcasts the provided transaction to PEER_PREFERRED_COUNT of our peers.
|
||||
/// We may be connected to PEER_MAX_COUNT peers so we only
|
||||
/// want to broadcast to a random subset of peers.
|
||||
@@ -438,8 +505,8 @@ impl ChainAdapter for Peers {
|
||||
fn total_height(&self) -> u64 {
|
||||
self.adapter.total_height()
|
||||
}
|
||||
fn transaction_received(&self, tx: core::Transaction) {
|
||||
self.adapter.transaction_received(tx)
|
||||
fn transaction_received(&self, tx: core::Transaction, stem: bool) {
|
||||
self.adapter.transaction_received(tx, stem)
|
||||
}
|
||||
fn block_received(&self, b: core::Block, peer_addr: SocketAddr) -> bool {
|
||||
let hash = b.hash();
|
||||
|
||||
+7
-1
@@ -63,7 +63,13 @@ impl MessageHandler for Protocol {
|
||||
|
||||
Type::Transaction => {
|
||||
let tx: core::Transaction = msg.body()?;
|
||||
adapter.transaction_received(tx);
|
||||
adapter.transaction_received(tx, false);
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
Type::StemTransaction => {
|
||||
let tx: core::Transaction = msg.body()?;
|
||||
adapter.transaction_received(tx, true);
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -205,7 +205,7 @@ impl ChainAdapter for DummyAdapter {
|
||||
fn total_height(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
fn transaction_received(&self, _: core::Transaction) {}
|
||||
fn transaction_received(&self, _: core::Transaction, stem: bool) {}
|
||||
fn compact_block_received(&self, _cb: core::CompactBlock, _addr: SocketAddr) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
+1
-1
@@ -167,7 +167,7 @@ pub trait ChainAdapter: Sync + Send {
|
||||
fn total_height(&self) -> u64;
|
||||
|
||||
/// A valid transaction has been received from one of our peers
|
||||
fn transaction_received(&self, tx: core::Transaction);
|
||||
fn transaction_received(&self, tx: core::Transaction, stem: bool);
|
||||
|
||||
/// A block has been received from one of our peers. Returns true if the
|
||||
/// block could be handled properly and is not deemed defective by the
|
||||
|
||||
Reference in New Issue
Block a user