funnel survive rate limiting
This commit is contained in:
parent
dd674bb900
commit
27e07b3fc9
6
TODO.md
6
TODO.md
@ -1,8 +1,10 @@
|
|||||||
# Todo
|
# Todo
|
||||||
|
|
||||||
- [ ] it works for a few seconds and then gets stuck on something
|
- [x] it works for a few seconds and then gets stuck on something.
|
||||||
|
- [x] its working with one backend node, but multiple breaks. something to do with pending transactions
|
||||||
|
- [x] dashmap entry api is easy to deadlock! be careful with it!
|
||||||
- [ ] rpc errors propagate too far. one subscription failing ends the app. isolate the providers more
|
- [ ] rpc errors propagate too far. one subscription failing ends the app. isolate the providers more
|
||||||
- [ ] its working with one backend node, but multiple breaks. something to do with pending transactions
|
- [ ] ethers has a transactions_unsorted httprpc method that we should probably use. all rpcs probably don't support it, so make it okay for that to fail
|
||||||
- [ ] if web3 proxy gets an http error back, retry another node
|
- [ ] if web3 proxy gets an http error back, retry another node
|
||||||
- [x] refactor Connection::spawn. have it return a handle to the spawned future of it running with block and transaction subscriptions
|
- [x] refactor Connection::spawn. have it return a handle to the spawned future of it running with block and transaction subscriptions
|
||||||
- [x] refactor Connections::spawn. have it return a handle that is selecting on those handles?
|
- [x] refactor Connections::spawn. have it return a handle that is selecting on those handles?
|
||||||
|
@ -162,6 +162,7 @@ impl Web3Connection {
|
|||||||
// check the server's chain_id here
|
// check the server's chain_id here
|
||||||
// TODO: move this outside the `new` function and into a `start` function or something
|
// TODO: move this outside the `new` function and into a `start` function or something
|
||||||
// TODO: some public rpcs (on bsc and fantom) do not return an id and so this ends up being an error
|
// TODO: some public rpcs (on bsc and fantom) do not return an id and so this ends up being an error
|
||||||
|
// TODO: this will wait forever. do we want that?
|
||||||
let found_chain_id: Result<String, _> = connection
|
let found_chain_id: Result<String, _> = connection
|
||||||
.wait_for_request_handle()
|
.wait_for_request_handle()
|
||||||
.await
|
.await
|
||||||
@ -385,7 +386,6 @@ impl Web3Connection {
|
|||||||
// query the block once since the subscription doesn't send the current block
|
// query the block once since the subscription doesn't send the current block
|
||||||
// there is a very small race condition here where the stream could send us a new block right now
|
// there is a very small race condition here where the stream could send us a new block right now
|
||||||
// all it does is print "new block" for the same block as current block
|
// all it does is print "new block" for the same block as current block
|
||||||
// TODO: subscribe to Block<TransactionReceipt> instead?
|
|
||||||
let block: Result<Block<TxHash>, _> = self
|
let block: Result<Block<TxHash>, _> = self
|
||||||
.wait_for_request_handle()
|
.wait_for_request_handle()
|
||||||
.await
|
.await
|
||||||
@ -492,11 +492,12 @@ impl Web3Connection {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// be careful with this; it will wait forever!
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
pub async fn wait_for_request_handle(self: &Arc<Self>) -> ActiveRequestHandle {
|
pub async fn wait_for_request_handle(self: &Arc<Self>) -> ActiveRequestHandle {
|
||||||
// TODO: maximum wait time
|
// TODO: maximum wait time?
|
||||||
|
|
||||||
for _ in 0..10 {
|
loop {
|
||||||
match self.try_request_handle().await {
|
match self.try_request_handle().await {
|
||||||
Ok(pending_request_handle) => return pending_request_handle,
|
Ok(pending_request_handle) => return pending_request_handle,
|
||||||
Err(retry_after) => {
|
Err(retry_after) => {
|
||||||
@ -504,9 +505,6 @@ impl Web3Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: what should we do? panic isn't ever what we want
|
|
||||||
panic!("no request handle after 10 tries");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn try_request_handle(self: &Arc<Self>) -> Result<ActiveRequestHandle, Duration> {
|
pub async fn try_request_handle(self: &Arc<Self>) -> Result<ActiveRequestHandle, Duration> {
|
||||||
|
@ -161,15 +161,26 @@ impl Web3Connections {
|
|||||||
&self,
|
&self,
|
||||||
rpc: Arc<Web3Connection>,
|
rpc: Arc<Web3Connection>,
|
||||||
pending_tx_id: TxHash,
|
pending_tx_id: TxHash,
|
||||||
) -> Result<TxState, ProviderError> {
|
) -> Result<Option<TxState>, ProviderError> {
|
||||||
// TODO: yearn devs have had better luck with batching these, but i think that's likely just adding a delay itself
|
// TODO: yearn devs have had better luck with batching these, but i think that's likely just adding a delay itself
|
||||||
// TODO: there is a race here sometimes the rpc isn't yet ready to serve the transaction (even though they told us about it!)
|
// TODO: there is a race here sometimes the rpc isn't yet ready to serve the transaction (even though they told us about it!)
|
||||||
// TODO: maximum wait time
|
// TODO: maximum wait time
|
||||||
let pending_transaction: Transaction = rpc
|
let pending_transaction: Transaction = match rpc.try_request_handle().await {
|
||||||
.wait_for_request_handle()
|
Ok(request_handle) => {
|
||||||
.await
|
request_handle
|
||||||
.request("eth_getTransactionByHash", (pending_tx_id,))
|
.request("eth_getTransactionByHash", (pending_tx_id,))
|
||||||
.await?;
|
.await?
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
trace!(
|
||||||
|
?pending_tx_id,
|
||||||
|
?rpc,
|
||||||
|
?err,
|
||||||
|
"cancelled funneling transaction"
|
||||||
|
);
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
trace!(?pending_transaction, "pending");
|
trace!(?pending_transaction, "pending");
|
||||||
|
|
||||||
@ -177,9 +188,9 @@ impl Web3Connections {
|
|||||||
match &pending_transaction.block_hash {
|
match &pending_transaction.block_hash {
|
||||||
Some(_block_hash) => {
|
Some(_block_hash) => {
|
||||||
// the transaction is already confirmed. no need to save in the pending_transactions map
|
// the transaction is already confirmed. no need to save in the pending_transactions map
|
||||||
Ok(TxState::Confirmed(pending_transaction))
|
Ok(Some(TxState::Confirmed(pending_transaction)))
|
||||||
}
|
}
|
||||||
None => Ok(TxState::Pending(pending_transaction)),
|
None => Ok(Some(TxState::Pending(pending_transaction))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +218,7 @@ impl Web3Connections {
|
|||||||
// query the rpc for this transaction
|
// query the rpc for this transaction
|
||||||
// it is possible that another rpc is also being queried. thats fine. we want the fastest response
|
// it is possible that another rpc is also being queried. thats fine. we want the fastest response
|
||||||
match self._funnel_transaction(rpc.clone(), pending_tx_id).await {
|
match self._funnel_transaction(rpc.clone(), pending_tx_id).await {
|
||||||
Ok(tx_state) => {
|
Ok(Some(tx_state)) => {
|
||||||
let _ = pending_tx_sender.send(tx_state);
|
let _ = pending_tx_sender.send(tx_state);
|
||||||
|
|
||||||
trace!(?pending_tx_id, "sent");
|
trace!(?pending_tx_id, "sent");
|
||||||
@ -215,6 +226,7 @@ impl Web3Connections {
|
|||||||
// we sent the transaction. return now. don't break looping because that gives a warning
|
// we sent the transaction. return now. don't break looping because that gives a warning
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
Ok(None) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
trace!(?err, ?pending_tx_id, "failed fetching transaction");
|
trace!(?err, ?pending_tx_id, "failed fetching transaction");
|
||||||
// unable to update the entry. sleep and try again soon
|
// unable to update the entry. sleep and try again soon
|
||||||
|
Loading…
Reference in New Issue
Block a user