-
Notifications
You must be signed in to change notification settings - Fork 127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Message Generator: fix serialization and add into_static for serde_sv2 primitives, broken unit tests, new unit test for NMJ message, #949
Conversation
df10ddf
to
f0381eb
Compare
Bencher
Click to view all benchmark results
Bencher - Continuous Benchmarking View Public Perf Page Docs | Repo | Chat | Help |
Bencher
🚨 2 ALERTS: Threshold Boundary Limits exceeded!
Click to view all benchmark results
Bencher - Continuous Benchmarking View Public Perf Page Docs | Repo | Chat | Help |
Bencher
🚨 11 ALERTS: Threshold Boundary Limits exceeded!
Click to view all benchmark results
Bencher - Continuous Benchmarking View Public Perf Page Docs | Repo | Chat | Help |
Bencher
Click to view all benchmark results
Bencher - Continuous Benchmarking View Public Perf Page Docs | Repo | Chat | Help |
98e89b6
to
a74665a
Compare
9e48228
to
4e98733
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lorbax did initial pass. Also, could you please tide up the commits so you have a couple of detailed commits explaining the problem and the solution you are proposing?
@@ -4,7 +4,7 @@ use core::convert::{TryFrom, TryInto}; | |||
use serde::{de::Visitor, ser, ser::SerializeTuple, Deserialize, Deserializer, Serialize}; | |||
|
|||
#[derive(Debug, Clone, Eq)] | |||
enum Inner<'a> { | |||
pub enum Inner<'a> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What the reason for making this public? I think having a variable called Inner
and making its visibility pub
is not great for readability
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually it is not even necessary to expose Inner, I removed pub
and seems to be compiling without issues ^^
seq.serialize_element(tuple.1)?; | ||
seq.end() | ||
if serializer.is_human_readable() { | ||
let data_ = self.data.clone().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use data
from the match result?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because I had to do this modification several times and I did past and copy, but you are right I should use the data
in the match branch!
Thank you!
let mut last = elem_len; | ||
while last <= self.data.len() { | ||
let slice = &self.data[first..last]; | ||
let elem = T::try_from_slice(slice).map_err(|_| ())?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add an error variant here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An crate::error::Error::PrimitiveConversionError
should be the right solution, what do you think?
BTW this part of code is used only in the message generator and not for production.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, we can leave as is then
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having second thoughts about this. As it is exposed through the public API, it might make more sense to handle errors properly here.
Also, I have a small question:
If self.size
is bigger than self.data.len
, is returning empty array with self.size
cap(the current behavior) makes sense or an error should be returned?
seq.serialize_element(&tuple.0)?; | ||
seq.serialize_element(tuple.1)?; | ||
seq.end() | ||
} | ||
} | ||
_ => panic!(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you handle this panic please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I understood, the type Sv2Option
can never have both fields of the same variants. We should ask @Fi3 for more details
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe add assert_debug!(false, "EXPLAIN_WHY_THIS_SHOULD_NOT_HAPPEN")
instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -227,7 +239,15 @@ impl<'s> Sv2Option<'s, U256<'s>> { | |||
data: Some(data), | |||
} | |||
} else { | |||
panic!() | |||
// this is an already valid seq should be safe to call the unwraps. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this unwrap safe?
@@ -242,7 +262,14 @@ impl<'s> Sv2Option<'s, u32> { | |||
data: Some(inner), | |||
} | |||
} else { | |||
panic!() | |||
// this is an already valid seq should be safe to call the unwraps. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this unwrap safe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes because if self.data
is None
then self.seq
is Some(Inner)
(it is the same as above!)
seq.serialize_element(tuple.1)?; | ||
seq.end() | ||
if serializer.is_human_readable() { | ||
let data_ = self.data.clone().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same, why not use data
from match
result?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my mistake!
// this is an already valid seq should be safe to call the unwraps. | ||
// also this library shouldn't be used for priduction envs so is ok do thigs like this | ||
// one | ||
let data = self.seq.unwrap().parse().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this unwrap safe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, if self.data
is None
then self.seq
is Some()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, that sounds risky. Here we also have two unwraps.
maybe something like this:
impl<'s> Seq0255<'s, u32> {
pub fn into_static(self) -> Seq0255<'static, u32> {
match (self.data, self.seq) {
(Some(data),_) => {
},
(_, Some(seq)) => {
},
_ => {
debug_assert!(false, "This is unreachable because `req` most be defined if `data` is `None`");
unreachable!();
}
}
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I noticed that in both scenarios you provide data
and never seq
, is that intentional? also could we provide both if they exist?
Seq0255 {
seq: None,
data: Some(data),
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe because this library is used only for the MessageGenerator and the seq variant is never used in that case, but we should ask @Fi3 for that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need data "variant" for it to be static we can't have a static seq
// this is an already valid seq should be safe to call the unwraps. | ||
// also this library shouldn't be used for priduction envs so is ok do thigs like this | ||
// one | ||
let data = self.seq.unwrap().parse().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this unwrap safe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
Do you suggest to have just 2 commits? I don't think that it would be better as each commit describe a precise small change (except for fmt) |
Tomorrow I will remove the fmt btw. |
Thanks @lorbax for the answers. You can add as many commits as you like as long as they are reasonable(not fmt or typo fixes) and informative. I prefer that you add |
Thank you! |
1b5bb89
to
836f6c7
Compare
@lorbax feel free to ping me when this is ready for another review |
@@ -1,5 +1,5 @@ | |||
upstreams = [ | |||
{ channel_kind = "Extended", address = "0.0.0.0", port = 34265, pub_key = "9auqWEzQDVyd2oe1JVGFLMLHZtCo2FFqZwtKA5gd9xbuEu7PH72"} | |||
{ channel_kind = "Extended", address = "0.0.0.0", port = 34254, pub_key = "9auqWEzQDVyd2oe1JVGFLMLHZtCo2FFqZwtKA5gd9xbuEu7PH72"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this being changed here? seems totally unrelated to this PR
836f6c7
to
e38f853
Compare
e38f853
to
3fca130
Compare
@jbesraa took me a while, but now I have a better understanding of |
@lorbax thanks for digging into this! Maybe its worth breaking this pr to smaller ones if possible so you can get things merged while you are looking into the serde stuff |
the PR is ready as it is, I won't dig any longer for this serde stuff if not needed. |
It would be nice to change the commits to describe how/what/why its fixed rather than |
3fca130
to
89e4360
Compare
Now I changed the commit history, let me see it does look fine to you |
89e4360
to
36da00e
Compare
some tests in main.rs of Message Generator are not passing or are commented. This is because serialization and/or deserialization of Sv2 primitives was broken. into_static for serde_sv2 primitives these functions were panicking if the seq field of sequences (Seq<T> or Sv2Option) were Some(...). most rust tests for MG are fixed, one is added
355d3b5
to
36da00e
Compare
sorry for the delay here @lorbax, Ill review this in a bit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lorbax Thanks for breaking this down.
I would appreciate if @plebhash can validate the MG part.
I wonder also if we could avoid some of the repeated code, for example this code (and a couple of others) is repeated across different files
if serializer.is_human_readable() {
let data_ = self.data.clone().unwrap();
let mut seq = serializer.serialize_seq(Some(data_.len()))?;
for item in data_ {
seq.serialize_element(&item)?;
}
seq.end()
} else {
let tuple = (data.len() as u16, &data[..]);
let mut seq = serializer.serialize_tuple(2)?;
seq.serialize_element(&tuple.0)?;
seq.serialize_element(tuple.1)?;
seq.end()
}
I understand that those changes intended for MG but they live in protocols
as public APIs, so I think we should probably handle all edge cases. Let me know if you think otherwise.
let mut last = elem_len; | ||
while last <= self.data.len() { | ||
let slice = &self.data[first..last]; | ||
let elem = T::try_from_slice(slice).map_err(|_| ())?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having second thoughts about this. As it is exposed through the public API, it might make more sense to handle errors properly here.
Also, I have a small question:
If self.size
is bigger than self.data.len
, is returning empty array with self.size
cap(the current behavior) makes sense or an error should be returned?
seq.serialize_element(tuple.1)?; | ||
seq.end() | ||
if serializer.is_human_readable() { | ||
let data_ = data.clone(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
u can use masking and do let data = data.clone();
. I think its more clear
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you might also be able to remove this clone
as serialize_element
takes a reference
_ => { | ||
debug_assert!( | ||
false, | ||
"sv2option can never have boh fields of the same type" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there an action expected from a user who hit this? regarding how to debug it? If is, its worth mentioning it IMO
data: Some(data), | ||
match (self.data, self.seq) { | ||
(None, Some(seq)) => { | ||
let data = seq.parse().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be useful to use .expect
and explain why this should be Some
//dont clean the following commented code | ||
/* | ||
let mut bitcoind = os_command( | ||
"./test/bin/bitcoind", | ||
vec!["--regtest", "--datadir=./test/appdata/bitcoin_data/"], | ||
ExternalCommandConditions::new_with_timer_secs(10) | ||
.continue_if_std_out_have("sv2 thread start") | ||
.fail_if_anything_on_std_err(), | ||
) | ||
.await; | ||
let mut child = os_command( | ||
"./test/bin/bitcoin-cli", | ||
vec![ | ||
"--regtest", | ||
"--datadir=./test/appdata/bitcoin_data/", | ||
"generatetoaddress", | ||
"16", | ||
"bcrt1qttuwhmpa7a0ls5kr3ye6pjc24ng685jvdrksxx", | ||
], | ||
ExternalCommandConditions::None, | ||
) | ||
.await; | ||
child.unwrap().wait().await.unwrap(); | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are we keeping these comments?
//dont clean the following commented code
doesn't give any context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because can still be useful in future
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe you want to change the:
//dont clean the following commented code
with: TODO fix the below tests
the first comment don't say anything about why you want to keep the below comment and people get confused.
// dont clean the following commented code | ||
/* | ||
let mut child = os_command( | ||
"rm", | ||
vec!["-rf", "./test/appdata/bitcoin_data/regtest"], | ||
ExternalCommandConditions::None, | ||
) | ||
.await; | ||
child.unwrap().wait().await.unwrap(); | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are we keeping these comments?
//dont clean the following commented code
doesn't give any context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because it_test_against_remote_endpoint
is a test that I want to make it pass and not just ignore it. It is also true that there is nothing against to uncomment it and have it as "non-passing test"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above. comments are not memo for you.
for me is ok also one PR |
Where is the second PR? Edit: chatted with @lorbax and we have only this pr to review, which is fine with me. |
I recently saw that we have decided to close PR1068 because we want to replace the MG with something else for the CI. I don't see why this does not apply to this PR too, which is needed only for the MG. The library |
I wanted to ask this question as well, cc @jbesraa @plebhash Could we add it to the list #1077 and just close for now? |
#1041 is already keeping track of this, #1077 is tracking issues of a different nature but yeah we can close for now |
Solves 1041
Unity tests in main.rs of MG are fixed. One is added. This required to fix the serialization the primitives in the serde case (/protocols/v2/binary_sv2/serde_sv2)
test.json fixed in src directory of MG
mining-proxy config file fixed
Add fix to an issue that @Fi3 pointed out
https://discord.com/channels/950687892169195530/1212660461569441822/1243211841652654151
the fix consisted in the into_static function for serde_sv2 sequences