Refactor(electrum): Remove unwraps and expects#956
Refactor(electrum): Remove unwraps and expects#956vatsalkeshav wants to merge 5 commits intogetfloresta:masterfrom
Conversation
remove all .unwrap() and non-infallible .expect() calls in non-test code of /floresta-electrum/s/electrum_protocol.rs contribute to issue getfloresta#463
|
Did you tested this ? I dont think that the approach of just logging the error is efficient but i may be missing something about the electrum protocol... Ill take a read about it and after that ill do a review... Also, another strange thing are the |
Davidson-Souza
left a comment
There was a problem hiding this comment.
First pass through the code
|
|
||
| let position = self.address_cache.get_position(&prevout.txid).unwrap(); | ||
| for (utxo, prevout) in utxos.into_iter() { | ||
| let height = self.address_cache.get_height(&prevout.txid).unwrap_or(0); |
There was a problem hiding this comment.
getting a None means we don't have it cached, so we should send and empty reply
There was a problem hiding this comment.
done.
I initially left unwrap_or(0) as electrum treats 0 as sentinel for unconfirmed tx - sorry for that
| .chain | ||
| .get_block_hash(0) | ||
| .expect("Genesis block should be present"); | ||
| .expect("genesis block is always in the chain store"); |
There was a problem hiding this comment.
| .expect("genesis block is always in the chain store"); | |
| .expect("Genesis block is always in the chain store"); |
| let unconfirmed = match self.address_cache.find_unconfirmed() { | ||
| Ok(txs) => txs, | ||
| Err(e) => { | ||
| error!("Could not fetch unconfirmed transactions for rebroadcast: {e}"); | ||
| return; | ||
| } | ||
| }; |
There was a problem hiding this comment.
This should be propagated back. Our convension is to not handle errors in utility functions like this
| let Ok(blocks) = | ||
| cfilters.match_any(_addresses, start_height, stop_height, self.chain.clone()) | ||
| else { | ||
| info!("Could not match block filters"); |
There was a problem hiding this comment.
these are errors, not info
| match self.chain.get_height() { | ||
| Ok(chain_height) => { | ||
| if chain_height == height { | ||
| for client in &mut self.clients.values() { | ||
| let res = client.write( | ||
| serde_json::to_string(&result) | ||
| .expect("serde_json::Value is always serializable") | ||
| .as_bytes(), | ||
| ); | ||
| if res.is_err() { | ||
| info!("Could not write to client {client:?}"); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
please reduce nesting. I think you can use combinators here
| client.write( | ||
| serde_json::to_string(&res) | ||
| .expect("serde_json::Value is always serializable") | ||
| .as_bytes(), | ||
| )?; |
There was a problem hiding this comment.
| client.write( | |
| serde_json::to_string(&res) | |
| .expect("serde_json::Value is always serializable") | |
| .as_bytes(), | |
| )?; | |
| let res = serde_json::to_string(&res) | |
| .expect("serde_json::Value is always serializable"); | |
| client.write( | |
| res.as_bytes(), | |
| )?; |
|
Is this enough to forbid |
…ap_or(), flatten nesting
yes it is Thanks for the review! |
fixed unwrap_or calls after review |
| error!("main loop receiver dropped: {e:?}"); | ||
| break; | ||
| } | ||
| } |
There was a problem hiding this comment.
prefer the a if let Err(e) = self.message_transmitter.send(Message::Message((self.client_id, line))) instead of a whole match.
Theres an example on line 80 in this same file
| match self.message_transmitter.send(Message::Disconnect(self.client_id)) { | ||
| Ok(_) => {} | ||
| Err(e) => error!("main loop receiver dropped: {e:?}"), | ||
| } |
There was a problem hiding this comment.
| match self.message_transmitter.send(Message::Disconnect(self.client_id)) { | ||
| Ok(_) => {} | ||
| Err(e) => error!("main loop receiver dropped: {e:?}"), | ||
| } |
There was a problem hiding this comment.
|
|
||
| Err(super::error::Error::InvalidParams) | ||
| let Some(proof) = self.address_cache.get_merkle_proof(&tx_id) else { | ||
| return Err(super::error::Error::InvalidParams); |
There was a problem hiding this comment.
| return Err(super::error::Error::InvalidParams); | |
| return Err(Error::InvalidParams); |
| let Some(height) = self.address_cache.get_height(&tx_id) else { | ||
| return Err(super::error::Error::InvalidParams); | ||
| }; |
There was a problem hiding this comment.
| let Some(height) = self.address_cache.get_height(&tx_id) else { | |
| return Err(super::error::Error::InvalidParams); | |
| }; | |
| let Some(height) = self.address_cache.get_height(&tx_id) else { | |
| return Err(Error::InvalidParams); | |
| }; |
| let unconfirmed = self | ||
| .address_cache | ||
| .find_unconfirmed() | ||
| .map_err(|e| super::error::Error::WatchOnly(Box::new(e)))?; |
There was a problem hiding this comment.
| .map_err(|e| super::error::Error::WatchOnly(Box::new(e)))?; | |
| .map_err(|e| Error::WatchOnly(Box::new(e)))?; |
|
|
||
| pub async fn rebroadcast_mempool_transactions(&self) { | ||
| let unconfirmed = self.address_cache.find_unconfirmed().unwrap(); | ||
| pub async fn rebroadcast_mempool_transactions(&self) -> Result<(), super::error::Error> { |
There was a problem hiding this comment.
| pub async fn rebroadcast_mempool_transactions(&self) -> Result<(), super::error::Error> { | |
| pub async fn rebroadcast_mempool_transactions(&self) -> Result<(), Error> { |
| let Ok(blocks) = | ||
| cfilters.match_any(_addresses, start_height, stop_height, self.chain.clone()) | ||
| else { | ||
| error!("Could not match block filters"); |
There was a problem hiding this comment.
| error!("Could not match block filters"); | |
| error!("Could not find matching block filters"); |
| match message_transmitter | ||
| .send(Message::NewClient((client.client_id, client))) | ||
| .expect("Main loop is broken"); | ||
| id_count += 1; | ||
| { | ||
| Ok(_) => { | ||
| id_count += 1; | ||
| } | ||
| Err(e) => { | ||
| error!("main loop receiver dropped: {e:?}"); | ||
| break; | ||
| } | ||
| } |
There was a problem hiding this comment.
| match message_transmitter.send(Message::NewClient((client.client_id, client))) { | ||
| Ok(_) => { | ||
| id_count += 1; | ||
| } | ||
| Err(e) => { | ||
| error!("main loop receiver dropped: {e:?}"); | ||
| break; | ||
| } | ||
| } |
There was a problem hiding this comment.
… instead of pattern matching, shorter erro path
jaoleal
left a comment
There was a problem hiding this comment.
After reading a little about the Electrum protocol, it appears to leave to the server implementation to decide the error handling, similar to how the jsonrpc server should handle errors, following the spec of course.
Maybe we should follow another implementation as a standard ? Should we define our own standards for that as were doing on #831 ?
| Vec::from_hex(&tx).map_err(|_| super::error::Error::InvalidParams)?; | ||
| let tx: Transaction = | ||
| deserialize(&hex).map_err(|_| super::error::Error::InvalidParams)?; | ||
| let hex: Vec<_> = Vec::from_hex(&tx).map_err(|_| Error::InvalidParams)?; |
There was a problem hiding this comment.
| let hex: Vec<_> = Vec::from_hex(&tx).map_err(|_| Error::InvalidParams)?; | |
| let hex = Vec::from_hex(&tx).map_err(|_| Error::InvalidParams)?; |
| let Some(height) = self.address_cache.get_height(&prevout.txid) else { | ||
| return json_rpc_res!(request, []); | ||
| }; | ||
| let Some(position) = self.address_cache.get_position(&prevout.txid) else { | ||
| return json_rpc_res!(request, []); | ||
| }; |
There was a problem hiding this comment.
You should be returning errors here too no ?
There was a problem hiding this comment.
I know this isnt focused on error handling but it should replace unwraps with errors atleast right ?
There was a problem hiding this comment.
makes sense
but None means not cached, so @davidsonsouza suggested sending []
I'll try forcing the error with electrum daemon to be sure though
There was a problem hiding this comment.
Oh, if it was a recommendation from Davidson you can just forget this, thank you for telling me this.
Description and Notes
This pr removes all .unwrap() and non-infallible .expect() calls in non-test code of
floresta-electrumcontributes to issue #463
note to reviewers : added
self.addresses_to_scan.extend(addresses)to avoid silent address drop in at get_block_height failure inrescan_with_block_filtersfnContributor Checklist
just pcc(recommended but slower)just lint-features '-- -D warnings' && cargo test --releaseFinally, you are encouraged to sign all your commits (it proves authorship and guards against tampering—see How (and why) to sign Git commits and GitHub's guide to signing commits).