From 3665c80b25ee1b4cd5c53c3bf070c62a6cd16b3b Mon Sep 17 00:00:00 2001 From: "hinto.janai" Date: Tue, 19 Nov 2024 17:38:41 -0500 Subject: [PATCH] fix optional values --- rpc/types/src/bin.rs | 78 +++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/rpc/types/src/bin.rs b/rpc/types/src/bin.rs index efec442..6f56bca 100644 --- a/rpc/types/src/bin.rs +++ b/rpc/types/src/bin.rs @@ -134,6 +134,8 @@ define_request! { } } +// TODO: add `top_block_hash` field +// #[doc = define_request_and_response_doc!( "request" => GetBlocksRequest, get_blocksbin, @@ -268,6 +270,8 @@ impl EpeeObjectBuilder for __GetBlocksResponseEpeeBuilder { }; } + // HACK/INVARIANT: this must be manually updated + // if a field is added to `GetBlocksResponse`. read_epee_field! { status, untrusted, @@ -286,54 +290,46 @@ impl EpeeObjectBuilder for __GetBlocksResponseEpeeBuilder { } fn finish(self) -> error::Result { - const ELSE: error::Error = error::Error::Format("Required field was not found!"); + /// The error returned when a required field is missing. + fn error(name: &'static str) -> error::Error { + error::Error::Value(format!("Required field was not found: {name}")) + } - let status = self.status.ok_or(ELSE)?; - let untrusted = self.untrusted.ok_or(ELSE)?; - let blocks = self.blocks.ok_or(ELSE)?; - let start_height = self.start_height.ok_or(ELSE)?; - let current_height = self.current_height.ok_or(ELSE)?; - let output_indices = self.output_indices.ok_or(ELSE)?; - let daemon_time = self.daemon_time.ok_or(ELSE)?; - let pool_info_extent = self.pool_info_extent.ok_or(ELSE)?; + // INVARIANT: + // `monerod` omits serializing the field itself when a container is empty, + // `unwrap_or_default()` is used over `error()` in these cases. + // Some of the uses are when values have default fallbacks: `daemon_time`, `pool_info_extent`. + // Deserialize the common fields. + let header = GetBlocksResponseHeader { + status: self.status.ok_or_else(|| error("status"))?, + untrusted: self.untrusted.ok_or_else(|| error("untrusted"))?, + blocks: self.blocks.unwrap_or_default(), + start_height: self.start_height.ok_or_else(|| error("start_height"))?, + current_height: self.current_height.ok_or_else(|| error("current_height"))?, + output_indices: self.output_indices.unwrap_or_default(), + daemon_time: self.daemon_time.unwrap_or_default(), + }; + + // Specialize depending on the `pool_info_extent`. + let pool_info_extent = self.pool_info_extent.unwrap_or_default(); let this = match pool_info_extent { PoolInfoExtent::None => { - GetBlocksResponse::PoolInfoNone(GetBlocksResponsePoolInfoNone { - status, - untrusted, - blocks, - start_height, - current_height, - output_indices, - daemon_time, - }) + GetBlocksResponse::PoolInfoNone(GetBlocksResponsePoolInfoNone { header }) } PoolInfoExtent::Incremental => { GetBlocksResponse::PoolInfoIncremental(GetBlocksResponsePoolInfoIncremental { - status, - untrusted, - blocks, - start_height, - current_height, - output_indices, - daemon_time, - added_pool_txs: self.added_pool_txs.ok_or(ELSE)?, - remaining_added_pool_txids: self.remaining_added_pool_txids.ok_or(ELSE)?, - removed_pool_txids: self.removed_pool_txids.ok_or(ELSE)?, + header, + added_pool_txs: self.added_pool_txs.unwrap_or_default(), + remaining_added_pool_txids: self.remaining_added_pool_txids.unwrap_or_default(), + removed_pool_txids: self.removed_pool_txids.unwrap_or_default(), }) } PoolInfoExtent::Full => { GetBlocksResponse::PoolInfoFull(GetBlocksResponsePoolInfoFull { - status, - untrusted, - blocks, - start_height, - current_height, - output_indices, - daemon_time, - added_pool_txs: self.added_pool_txs.ok_or(ELSE)?, - remaining_added_pool_txids: self.remaining_added_pool_txids.ok_or(ELSE)?, + header, + added_pool_txs: self.added_pool_txs.unwrap_or_default(), + remaining_added_pool_txids: self.remaining_added_pool_txids.unwrap_or_default(), }) } }; @@ -358,18 +354,20 @@ impl EpeeObject for GetBlocksResponse { } fn write_fields(self, w: &mut B) -> error::Result<()> { + const FIELD: &str = "pool_info_extent"; + match self { Self::PoolInfoNone(s) => { s.write_fields(w)?; - write_field(PoolInfoExtent::None.to_u8(), "pool_info_extent", w)?; + write_field(PoolInfoExtent::None.to_u8(), FIELD, w)?; } Self::PoolInfoIncremental(s) => { s.write_fields(w)?; - write_field(PoolInfoExtent::Incremental.to_u8(), "pool_info_extent", w)?; + write_field(PoolInfoExtent::Incremental.to_u8(), FIELD, w)?; } Self::PoolInfoFull(s) => { s.write_fields(w)?; - write_field(PoolInfoExtent::Full.to_u8(), "pool_info_extent", w)?; + write_field(PoolInfoExtent::Full.to_u8(), FIELD, w)?; } }