From c164cd52b980b01ac4eae3d9310433ec9938f432 Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 12:07:08 +0200 Subject: [PATCH 01/23] ZIPs were updated to remove ambiguity, this was tracked in #1267. --- zebra-chain/src/work/difficulty/tests/vectors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra-chain/src/work/difficulty/tests/vectors.rs b/zebra-chain/src/work/difficulty/tests/vectors.rs index 3a64cdec6f1..708e2acafa1 100644 --- a/zebra-chain/src/work/difficulty/tests/vectors.rs +++ b/zebra-chain/src/work/difficulty/tests/vectors.rs @@ -457,7 +457,7 @@ fn check_testnet_minimum_difficulty_block(height: block::Height) -> Result<(), R .signed_duration_since(previous_block.header.time); // zcashd requires a gap that's strictly greater than 6 times the target - // threshold, but ZIP-205 and ZIP-208 are ambiguous. See bug #1276. + // threshold. match NetworkUpgrade::minimum_difficulty_spacing_for_height(Network::Testnet, height) { None => Err(eyre!("the minimum difficulty rule is not active"))?, Some(spacing) if (time_gap <= spacing) => Err(eyre!( From 9f8161db103e92821a954b32a4740c190097fa8c Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 12:17:18 +0200 Subject: [PATCH 02/23] #2105 was fixed by #3039 and #2379 was closed by #3069 --- zebra-consensus/src/transaction.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/zebra-consensus/src/transaction.rs b/zebra-consensus/src/transaction.rs index 28ecc7e0394..674438c23c0 100644 --- a/zebra-consensus/src/transaction.rs +++ b/zebra-consensus/src/transaction.rs @@ -740,10 +740,6 @@ where orchard_shielded_data, &shielded_sighash, )?)) - - // TODO: - // - verify orchard shielded pool (ZIP-224) (#2105) - // - shielded input and output limits? (#2379) } /// Verifies if a V5 `transaction` is supported by `network_upgrade`. From 39f86f7ce68cad5a4e5913adb49f589cc06180a7 Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 12:19:51 +0200 Subject: [PATCH 03/23] #2230 was a duplicate of #2231 which was closed by #2511 --- zebra-state/src/service/finalized_state/tests/prop.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra-state/src/service/finalized_state/tests/prop.rs b/zebra-state/src/service/finalized_state/tests/prop.rs index 5893d4ff2ea..bdc6438f551 100644 --- a/zebra-state/src/service/finalized_state/tests/prop.rs +++ b/zebra-state/src/service/finalized_state/tests/prop.rs @@ -35,7 +35,6 @@ fn blocks_with_v5_transactions() -> Result<()> { ); prop_assert_eq!(Some(height), state.finalized_tip_height()); prop_assert_eq!(hash.unwrap(), block.hash); - // TODO: check that the nullifiers were correctly inserted (#2230) height = Height(height.0 + 1); } }); From 2e362d99a59d4f96c764d24eb26eeeccd3f4bf60 Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 14:15:14 +0200 Subject: [PATCH 04/23] #3235 was obsoleted by #2156 which was fixed by #3505 --- zebra-network/src/policies.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/zebra-network/src/policies.rs b/zebra-network/src/policies.rs index 58ed093c64a..8e9f3c2af0b 100644 --- a/zebra-network/src/policies.rs +++ b/zebra-network/src/policies.rs @@ -34,9 +34,6 @@ impl Policy Some( // Let other tasks run, so we're more likely to choose a different peer, // and so that any notfound inv entries win the race to the PeerSet. - // - // TODO: move syncer retries into the PeerSet, - // so we always choose different peers (#3235) Box::pin(tokio::task::yield_now().map(move |()| retry_outcome)), ) } else { From 9b67e09dfe7ef9029852675d97087fde64c6282c Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 14:24:35 +0200 Subject: [PATCH 05/23] #1850 was fixed by #2944, #1851 was fixed by #2961 and #2902 was fixed by #2969 --- zebra-network/src/peer_set/limit.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/zebra-network/src/peer_set/limit.rs b/zebra-network/src/peer_set/limit.rs index 6c1bfc76f2b..bcf7299b688 100644 --- a/zebra-network/src/peer_set/limit.rs +++ b/zebra-network/src/peer_set/limit.rs @@ -178,8 +178,6 @@ impl Drop for ConnectionTracker { // We ignore disconnected errors, because the receiver can be dropped // before some connections are dropped. - // - // TODO: This channel will be bounded by the connection limit (#1850, #1851, #2902). let _ = self.close_notification_tx.send(ConnectionClosed); } } From 8ba4367da1ed225362f30c89875080d6e70cacc7 Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 14:28:00 +0200 Subject: [PATCH 06/23] We migrated to Rust 2021 edition in Jan 2022 with #3332 --- zebra-network/src/peer_set/set.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra-network/src/peer_set/set.rs b/zebra-network/src/peer_set/set.rs index 88d53b5461a..5a331e9a285 100644 --- a/zebra-network/src/peer_set/set.rs +++ b/zebra-network/src/peer_set/set.rs @@ -504,7 +504,6 @@ where /// Checks if the minimum peer version has changed, and disconnects from outdated peers. fn disconnect_from_outdated_peers(&mut self) { if let Some(minimum_version) = self.minimum_peer_version.changed() { - // TODO: Remove when the code base migrates to Rust 2021 edition (#2709). let preselected_p2c_peer = &mut self.preselected_p2c_peer; self.ready_services.retain(|address, peer| { From 725283b4ab3f262768848cc630b45b003be13410 Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 14:38:54 +0200 Subject: [PATCH 07/23] #1631 was closed as not needed --- zebra-network/src/config.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra-network/src/config.rs b/zebra-network/src/config.rs index 14f46ec4ff2..c1d49ab7905 100644 --- a/zebra-network/src/config.rs +++ b/zebra-network/src/config.rs @@ -347,7 +347,6 @@ impl<'de> Deserialize<'de> for Config { let config = DConfig::deserialize(deserializer)?; - // TODO: perform listener DNS lookups asynchronously with a timeout (#1631) let listen_addr = match config.listen_addr.parse::() { Ok(socket) => Ok(socket), Err(_) => match config.listen_addr.parse::() { From c141645536a18711e8bca4da7b4b2b7da49cfcc0 Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 15:07:45 +0200 Subject: [PATCH 08/23] #338 was fixed by #3040 and #1162 was fixed by #3067 --- zebra-state/src/service/check/utxo.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra-state/src/service/check/utxo.rs b/zebra-state/src/service/check/utxo.rs index 22001923702..0cd8a0f0dc2 100644 --- a/zebra-state/src/service/check/utxo.rs +++ b/zebra-state/src/service/check/utxo.rs @@ -229,7 +229,6 @@ pub fn remaining_transaction_value( utxos: &HashMap, ) -> Result<(), ValidateContextError> { for (tx_index_in_block, transaction) in prepared.block.transactions.iter().enumerate() { - // TODO: check coinbase transaction remaining value (#338, #1162) if transaction.is_coinbase() { continue; } From 2be03317cc4c476c507e1a5fbd77e64bb7013b4c Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 15:12:28 +0200 Subject: [PATCH 09/23] #2079 was fixed by #2445 --- zebra-chain/src/orchard/sinsemilla.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/zebra-chain/src/orchard/sinsemilla.rs b/zebra-chain/src/orchard/sinsemilla.rs index 060fbfb39e8..d7d05813a5c 100644 --- a/zebra-chain/src/orchard/sinsemilla.rs +++ b/zebra-chain/src/orchard/sinsemilla.rs @@ -159,10 +159,6 @@ pub fn sinsemilla_hash(D: &[u8], M: &BitVec) -> Option { extract_p_bottom(sinsemilla_hash_to_point(D, M)) } -// TODO: test the above correctness and compatibility with the zcash-hackworks test vectors -// https://github.com/ZcashFoundation/zebra/issues/2079 -// https://github.com/zcash-hackworks/zcash-test-vectors/pulls - #[cfg(test)] mod tests { From 778cce7fa97343ec0935adf110218d34d7599e54 Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 15:14:35 +0200 Subject: [PATCH 10/23] #4794 was fixed by #6122 --- zebra-rpc/src/methods/get_block_template_rpcs.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zebra-rpc/src/methods/get_block_template_rpcs.rs b/zebra-rpc/src/methods/get_block_template_rpcs.rs index 5a94be6ceb0..f9360472b70 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs.rs @@ -110,8 +110,7 @@ pub trait GetBlockTemplateRpc { /// - the parent block is a valid block that Zebra already has, or will receive soon. /// /// Zebra verifies blocks in parallel, and keeps recent chains in parallel, - /// so moving between chains is very cheap. (But forking a new chain may take some time, - /// until bug #4794 is fixed.) + /// so moving between chains is very cheap. /// /// This rpc method is available only if zebra is built with `--features getblocktemplate-rpcs`. #[rpc(name = "getblocktemplate")] From f1e04dc5276c04073b364ef9603740f015e22ba9 Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 15:16:13 +0200 Subject: [PATCH 11/23] #1678 stopped being an issue --- zebra-network/src/peer_set/set.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/zebra-network/src/peer_set/set.rs b/zebra-network/src/peer_set/set.rs index 5a331e9a285..e4b21d60b47 100644 --- a/zebra-network/src/peer_set/set.rs +++ b/zebra-network/src/peer_set/set.rs @@ -418,8 +418,6 @@ where for guard in self.guards.iter() { guard.abort(); } - - // TODO: implement graceful shutdown for InventoryRegistry (#1678) } /// Check busy peer services for request completion or errors. From 3bdf2cf3195035262fdd4e3570658624d72a8f80 Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 15:18:10 +0200 Subject: [PATCH 12/23] #3151 was fixed by #3934 --- .../src/service/finalized_state/zebra_db/block/tests/snapshot.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs index f40b40156b8..8ce1e67ece5 100644 --- a/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs +++ b/zebra-state/src/service/finalized_state/zebra_db/block/tests/snapshot.rs @@ -253,7 +253,6 @@ fn snapshot_block_and_transaction_data(state: &FinalizedState) { // test the rest of the chain data (value balance). let history_tree_at_tip = state.history_tree(); - // TODO: split out block snapshots into their own function (#3151) for query_height in 0..=max_height.0 { let query_height = Height(query_height); From af3a487780d6f09729905a3f756b4b3847b8ea3e Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 15:19:46 +0200 Subject: [PATCH 13/23] #3204 was closed as not needed --- zebra-network/src/peer_set/unready_service/tests/vectors.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/zebra-network/src/peer_set/unready_service/tests/vectors.rs b/zebra-network/src/peer_set/unready_service/tests/vectors.rs index 6869900f93d..4f78980ea6a 100644 --- a/zebra-network/src/peer_set/unready_service/tests/vectors.rs +++ b/zebra-network/src/peer_set/unready_service/tests/vectors.rs @@ -1,6 +1,4 @@ //! Fixed test vectors for unready services. -//! -//! TODO: test that inner service errors are handled correctly (#3204) use std::marker::PhantomData; From d3456b8ff8e8cdd3248f6545800b5e79735ece73 Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 15:23:00 +0200 Subject: [PATCH 14/23] #1213 was fixed by #4586 --- zebra-state/src/config.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/zebra-state/src/config.rs b/zebra-state/src/config.rs index b350f82ac24..ba62f834c9a 100644 --- a/zebra-state/src/config.rs +++ b/zebra-state/src/config.rs @@ -29,10 +29,7 @@ pub struct Config { /// When Zebra's state format changes, it creates a new state subdirectory for that version, /// and re-syncs from genesis. /// - /// Old state versions are [not automatically deleted](https://github.com/ZcashFoundation/zebra/issues/1213). - /// It is ok to manually delete old state versions. - /// - /// It is also ok to delete the entire cached state directory. + /// It is ok to delete the entire cached state directory. /// If you do, Zebra will re-sync from genesis next time it is launched. /// /// The default directory is platform dependent, based on From 6ed7bcaf9df996016f884aad7f1ca3d270376168 Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 15:24:36 +0200 Subject: [PATCH 15/23] #1774 was closed as not needed --- zebra-network/src/protocol/external/codec.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/zebra-network/src/protocol/external/codec.rs b/zebra-network/src/protocol/external/codec.rs index aec54772c85..8dbb038d633 100644 --- a/zebra-network/src/protocol/external/codec.rs +++ b/zebra-network/src/protocol/external/codec.rs @@ -184,10 +184,6 @@ impl Codec { /// Obtain the size of the body of a given message. This will match the /// number of bytes written to the writer provided to `write_body` for the /// same message. - /// - /// TODO: Replace with a size estimate, to avoid multiple serializations - /// for large data structures like lists, blocks, and transactions. - /// See #1774. fn body_length(&self, msg: &Message) -> usize { let mut writer = FakeWriter(0); From b56f858a981df6e3e6644a982894fab7f13b73d4 Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Fri, 19 May 2023 15:26:46 +0200 Subject: [PATCH 16/23] #4633 was closed as not needed --- zebra-network/src/protocol/external/message.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/zebra-network/src/protocol/external/message.rs b/zebra-network/src/protocol/external/message.rs index 009566dc24d..74b83a1f222 100644 --- a/zebra-network/src/protocol/external/message.rs +++ b/zebra-network/src/protocol/external/message.rs @@ -401,8 +401,6 @@ impl TryFrom for VersionMessage { } } -// TODO: add tests for Error conversion and Reject message serialization (#4633) -// (Zebra does not currently send reject messages, and it ignores received reject messages.) impl From for Message where E: Error, From da6b1f52314957d18766263b2ba21beb693dc9ca Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Mon, 22 May 2023 10:04:01 +0200 Subject: [PATCH 17/23] Clarify behaviour of difficulty spacing Co-authored-by: teor --- zebra-chain/src/work/difficulty/tests/vectors.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zebra-chain/src/work/difficulty/tests/vectors.rs b/zebra-chain/src/work/difficulty/tests/vectors.rs index 708e2acafa1..d198fd32c4b 100644 --- a/zebra-chain/src/work/difficulty/tests/vectors.rs +++ b/zebra-chain/src/work/difficulty/tests/vectors.rs @@ -457,7 +457,9 @@ fn check_testnet_minimum_difficulty_block(height: block::Height) -> Result<(), R .signed_duration_since(previous_block.header.time); // zcashd requires a gap that's strictly greater than 6 times the target - // threshold. + // threshold, as documented in ZIP-205 and ZIP-208: + // https://zips.z.cash/zip-0205#change-to-difficulty-adjustment-on-testnet + // https://zips.z.cash/zip-0208#minimum-difficulty-blocks-on-testnet match NetworkUpgrade::minimum_difficulty_spacing_for_height(Network::Testnet, height) { None => Err(eyre!("the minimum difficulty rule is not active"))?, Some(spacing) if (time_gap <= spacing) => Err(eyre!( From ea15a487c8283cab541e1076867c7aba1f8bd9af Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Mon, 22 May 2023 10:05:13 +0200 Subject: [PATCH 18/23] Update comment to reflect implemented behaviour Co-authored-by: teor --- zebra-network/src/peer_set/limit.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zebra-network/src/peer_set/limit.rs b/zebra-network/src/peer_set/limit.rs index bcf7299b688..5b5f4a61273 100644 --- a/zebra-network/src/peer_set/limit.rs +++ b/zebra-network/src/peer_set/limit.rs @@ -178,6 +178,9 @@ impl Drop for ConnectionTracker { // We ignore disconnected errors, because the receiver can be dropped // before some connections are dropped. + // # Security + // + // This channel is actually bounded by the inbound and outbound connection limit. let _ = self.close_notification_tx.send(ConnectionClosed); } } From d98f55dbda32ab570f5a6b5753d06056e20d3d4f Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Mon, 22 May 2023 10:06:56 +0200 Subject: [PATCH 19/23] Update comment to reflect implemented behaviour when retrying block downloads Co-authored-by: teor --- zebra-network/src/policies.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zebra-network/src/policies.rs b/zebra-network/src/policies.rs index 8e9f3c2af0b..b3af056a60b 100644 --- a/zebra-network/src/policies.rs +++ b/zebra-network/src/policies.rs @@ -34,6 +34,11 @@ impl Policy Some( // Let other tasks run, so we're more likely to choose a different peer, // and so that any notfound inv entries win the race to the PeerSet. + // # Security + // + // We want to choose different peers for retries, so we have a better chance of getting each block. + // This is implemented by the connection state machine sending synthetic `notfound`s to the + // `InventoryRegistry`, as well as forwarding actual `notfound`s from peers. Box::pin(tokio::task::yield_now().map(move |()| retry_outcome)), ) } else { From 14899f3b1d52a5f0907a8bae6fafb0332a19194e Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Mon, 22 May 2023 10:08:10 +0200 Subject: [PATCH 20/23] Update `TODO` to remove closed issue and clarify when we might want to fix Co-authored-by: teor --- zebra-network/src/protocol/external/codec.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zebra-network/src/protocol/external/codec.rs b/zebra-network/src/protocol/external/codec.rs index 8dbb038d633..7aee299dafa 100644 --- a/zebra-network/src/protocol/external/codec.rs +++ b/zebra-network/src/protocol/external/codec.rs @@ -184,6 +184,10 @@ impl Codec { /// Obtain the size of the body of a given message. This will match the /// number of bytes written to the writer provided to `write_body` for the /// same message. + // # Performance TODO + // + // If this code shows up in profiles, replace with a size estimate or cached size, + // to avoid multiple serializations for large data structures like lists, blocks, and transactions. fn body_length(&self, msg: &Message) -> usize { let mut writer = FakeWriter(0); From 23fdc81830bcf69ec3560f10e2393a0561cd49be Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Mon, 22 May 2023 10:09:12 +0200 Subject: [PATCH 21/23] Update `TODO` to remove closed issue and clarify what we might want to change in future Co-authored-by: teor --- zebra-network/src/protocol/external/message.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zebra-network/src/protocol/external/message.rs b/zebra-network/src/protocol/external/message.rs index 74b83a1f222..52e37c9eb9a 100644 --- a/zebra-network/src/protocol/external/message.rs +++ b/zebra-network/src/protocol/external/message.rs @@ -401,6 +401,8 @@ impl TryFrom for VersionMessage { } } +// TODO: add tests for Error conversion and Reject message serialization + // (Zebra does not currently send reject messages, and it ignores received reject messages.) impl From for Message where E: Error, From 7c5d6b6334558d05dd7856d55830664ebe1364be Mon Sep 17 00:00:00 2001 From: Pili Guerra Date: Mon, 22 May 2023 10:10:12 +0200 Subject: [PATCH 22/23] Clarify benefits of how we do block verification Co-authored-by: teor --- zebra-rpc/src/methods/get_block_template_rpcs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra-rpc/src/methods/get_block_template_rpcs.rs b/zebra-rpc/src/methods/get_block_template_rpcs.rs index f9360472b70..f7ea4e3f98f 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs.rs @@ -110,7 +110,7 @@ pub trait GetBlockTemplateRpc { /// - the parent block is a valid block that Zebra already has, or will receive soon. /// /// Zebra verifies blocks in parallel, and keeps recent chains in parallel, - /// so moving between chains is very cheap. + /// so moving between chains and forking chains is very cheap. /// /// This rpc method is available only if zebra is built with `--features getblocktemplate-rpcs`. #[rpc(name = "getblocktemplate")] From f4dcdc0571328c0471c77631df2e0ca8d365b407 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 23 May 2023 11:02:02 +1000 Subject: [PATCH 23/23] Fix rustfmt errors --- zebra-network/src/policies.rs | 3 ++- zebra-network/src/protocol/external/message.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/zebra-network/src/policies.rs b/zebra-network/src/policies.rs index b3af056a60b..5e00207ba75 100644 --- a/zebra-network/src/policies.rs +++ b/zebra-network/src/policies.rs @@ -34,10 +34,11 @@ impl Policy Some( // Let other tasks run, so we're more likely to choose a different peer, // and so that any notfound inv entries win the race to the PeerSet. + // // # Security // // We want to choose different peers for retries, so we have a better chance of getting each block. - // This is implemented by the connection state machine sending synthetic `notfound`s to the + // This is implemented by the connection state machine sending synthetic `notfound`s to the // `InventoryRegistry`, as well as forwarding actual `notfound`s from peers. Box::pin(tokio::task::yield_now().map(move |()| retry_outcome)), ) diff --git a/zebra-network/src/protocol/external/message.rs b/zebra-network/src/protocol/external/message.rs index 52e37c9eb9a..f8ee8cbc9b8 100644 --- a/zebra-network/src/protocol/external/message.rs +++ b/zebra-network/src/protocol/external/message.rs @@ -402,7 +402,7 @@ impl TryFrom for VersionMessage { } // TODO: add tests for Error conversion and Reject message serialization - // (Zebra does not currently send reject messages, and it ignores received reject messages.) +// (Zebra does not currently send reject messages, and it ignores received reject messages.) impl From for Message where E: Error,