improve sort order during eth_sendRawTransaction
This commit is contained in:
parent
9ac3ef1e3d
commit
ca1e550370
3
TODO.md
3
TODO.md
|
@ -324,6 +324,9 @@ These are not yet ordered. There might be duplicates. We might not actually need
|
||||||
- [x] improve waiting for sync when rate limited
|
- [x] improve waiting for sync when rate limited
|
||||||
- [x] improve pager duty errors for smarter deduping
|
- [x] improve pager duty errors for smarter deduping
|
||||||
- [x] add create_key cli command
|
- [x] add create_key cli command
|
||||||
|
- [x] short lived cache on /health
|
||||||
|
- [x] cache /status for longer
|
||||||
|
- [x] sort connections during eth_sendRawTransaction
|
||||||
- [-] proxy mode for benchmarking all backends
|
- [-] proxy mode for benchmarking all backends
|
||||||
- [-] proxy mode for sending to multiple backends
|
- [-] proxy mode for sending to multiple backends
|
||||||
- [-] let users choose a % of reverts to log (or maybe x/second). someone like curve logging all reverts will be a BIG database very quickly
|
- [-] let users choose a % of reverts to log (or maybe x/second). someone like curve logging all reverts will be a BIG database very quickly
|
||||||
|
|
|
@ -35,6 +35,12 @@ pub enum ProviderState {
|
||||||
Connected(Arc<Web3Provider>),
|
Connected(Arc<Web3Provider>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for ProviderState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ProviderState {
|
impl ProviderState {
|
||||||
pub async fn provider(&self, allow_not_ready: bool) -> Option<&Arc<Web3Provider>> {
|
pub async fn provider(&self, allow_not_ready: bool) -> Option<&Arc<Web3Provider>> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -59,6 +65,7 @@ impl ProviderState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An active connection to a Web3 RPC server like geth or erigon.
|
/// An active connection to a Web3 RPC server like geth or erigon.
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Web3Connection {
|
pub struct Web3Connection {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub display_name: Option<String>,
|
pub display_name: Option<String>,
|
||||||
|
|
|
@ -678,17 +678,21 @@ impl Web3Connections {
|
||||||
|
|
||||||
let mut tried = HashSet::new();
|
let mut tried = HashSet::new();
|
||||||
|
|
||||||
let conns_to_try = itertools::chain(
|
let mut synced_conns = self
|
||||||
// TODO: sort by tier
|
.watch_consensus_connections_sender
|
||||||
self.watch_consensus_connections_sender
|
|
||||||
.borrow()
|
.borrow()
|
||||||
.conns
|
.conns
|
||||||
.clone(),
|
.clone();
|
||||||
// TODO: sort by tier
|
|
||||||
self.conns.values().cloned(),
|
|
||||||
);
|
|
||||||
|
|
||||||
for connection in conns_to_try {
|
// synced connections are all on the same block. sort them by tier with higher soft limits first
|
||||||
|
synced_conns.sort_by_cached_key(|x| (x.tier, u32::MAX - x.soft_limit));
|
||||||
|
|
||||||
|
// if there aren't enough synced connections, include more connections
|
||||||
|
let mut all_conns: Vec<_> = self.conns.values().cloned().collect();
|
||||||
|
|
||||||
|
sort_connections_by_sync_status(&mut all_conns);
|
||||||
|
|
||||||
|
for connection in itertools::chain(synced_conns, all_conns) {
|
||||||
if max_count == 0 {
|
if max_count == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1147,6 +1151,22 @@ impl Serialize for Web3Connections {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// sort by block number (descending) and tier (ascending)
|
||||||
|
fn sort_connections_by_sync_status(rpcs: &mut Vec<Arc<Web3Connection>>) {
|
||||||
|
rpcs.sort_by_cached_key(|x| {
|
||||||
|
let reversed_head_block = u64::MAX
|
||||||
|
- x.head_block
|
||||||
|
.read()
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| x.number().as_u64())
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
let tier = x.tier;
|
||||||
|
|
||||||
|
(reversed_head_block, tier)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
mod tests {
|
mod tests {
|
||||||
// TODO: why is this allow needed? does tokio::test get in the way somehow?
|
// TODO: why is this allow needed? does tokio::test get in the way somehow?
|
||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
|
@ -1162,6 +1182,80 @@ mod tests {
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use tokio::sync::RwLock as AsyncRwLock;
|
use tokio::sync::RwLock as AsyncRwLock;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_sort_connections_by_sync_status() {
|
||||||
|
let block_0 = Block {
|
||||||
|
number: Some(0.into()),
|
||||||
|
hash: Some(H256::random()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let block_1 = Block {
|
||||||
|
number: Some(1.into()),
|
||||||
|
hash: Some(H256::random()),
|
||||||
|
parent_hash: block_0.hash.unwrap(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let block_2 = Block {
|
||||||
|
number: Some(2.into()),
|
||||||
|
hash: Some(H256::random()),
|
||||||
|
parent_hash: block_1.hash.unwrap(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let blocks: Vec<_> = [block_0, block_1, block_2]
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| SavedBlock::new(Arc::new(x)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut rpcs = [
|
||||||
|
Web3Connection {
|
||||||
|
name: "a".to_string(),
|
||||||
|
tier: 0,
|
||||||
|
head_block: RwLock::new(None),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Web3Connection {
|
||||||
|
name: "b".to_string(),
|
||||||
|
tier: 0,
|
||||||
|
head_block: RwLock::new(blocks.get(1).cloned()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Web3Connection {
|
||||||
|
name: "c".to_string(),
|
||||||
|
tier: 0,
|
||||||
|
head_block: RwLock::new(blocks.get(2).cloned()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Web3Connection {
|
||||||
|
name: "d".to_string(),
|
||||||
|
tier: 1,
|
||||||
|
head_block: RwLock::new(None),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Web3Connection {
|
||||||
|
name: "e".to_string(),
|
||||||
|
tier: 1,
|
||||||
|
head_block: RwLock::new(blocks.get(1).cloned()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Web3Connection {
|
||||||
|
name: "f".to_string(),
|
||||||
|
tier: 1,
|
||||||
|
head_block: RwLock::new(blocks.get(2).cloned()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(Arc::new)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
sort_connections_by_sync_status(&mut rpcs);
|
||||||
|
|
||||||
|
let names_in_sort_order: Vec<_> = rpcs.iter().map(|x| x.name.as_str()).collect();
|
||||||
|
|
||||||
|
assert_eq!(names_in_sort_order, ["c", "f", "b", "e", "a", "d"]);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_server_selection_by_height() {
|
async fn test_server_selection_by_height() {
|
||||||
// TODO: do this better. can test_env_logger and tokio test be stacked?
|
// TODO: do this better. can test_env_logger and tokio test be stacked?
|
||||||
|
|
Loading…
Reference in New Issue