Stop panicking when Zebra sends a reject without extra data

Also add round-trip unit tests for extra data and no extra data.
This commit is contained in:
teor 2021-04-15 20:34:21 +10:00 committed by Deirdre Connolly
parent 15843cfd6e
commit 59aa04c9b9
1 changed files with 77 additions and 2 deletions

View File

@ -251,7 +251,9 @@ impl Codec {
writer.write_string(&message)?; writer.write_string(&message)?;
writer.write_u8(*ccode as u8)?; writer.write_u8(*ccode as u8)?;
writer.write_string(&reason)?; writer.write_string(&reason)?;
writer.write_all(&data.unwrap())?; if let Some(data) = data {
writer.write_all(data)?;
}
} }
Message::Addr(addrs) => addrs.zcash_serialize(&mut writer)?, Message::Addr(addrs) => addrs.zcash_serialize(&mut writer)?,
Message::GetAddr => { /* Empty payload -- no-op */ } Message::GetAddr => { /* Empty payload -- no-op */ }
@ -511,7 +513,8 @@ impl Codec {
// data (hash identifying the rejected object) or none (and we model // data (hash identifying the rejected object) or none (and we model
// the Reject message that way), so instead of passing in the // the Reject message that way), so instead of passing in the
// body_len separately and calculating remaining bytes, just try to // body_len separately and calculating remaining bytes, just try to
// read 32 bytes and ignore any failures. // read 32 bytes and ignore any failures. (The caller will log and
// ignore any trailing bytes.)
data: reader.read_32_bytes().ok(), data: reader.read_32_bytes().ok(),
}) })
} }
@ -720,6 +723,78 @@ mod tests {
assert_eq!(v, v_parsed); assert_eq!(v, v_parsed);
} }
#[test]
fn reject_message_no_extra_data_round_trip() {
zebra_test::init();
let rt = Runtime::new().unwrap();
let v = Message::Reject {
message: "experimental".to_string(),
ccode: RejectReason::Malformed,
reason: "message could not be decoded".to_string(),
data: None,
};
use tokio_util::codec::{FramedRead, FramedWrite};
let v_bytes = rt.block_on(async {
let mut bytes = Vec::new();
{
let mut fw = FramedWrite::new(&mut bytes, Codec::builder().finish());
fw.send(v.clone())
.await
.expect("message should be serialized");
}
bytes
});
let v_parsed = rt.block_on(async {
let mut fr = FramedRead::new(Cursor::new(&v_bytes), Codec::builder().finish());
fr.next()
.await
.expect("a next message should be available")
.expect("that message should deserialize")
});
assert_eq!(v, v_parsed);
}
#[test]
fn reject_message_extra_data_round_trip() {
zebra_test::init();
let rt = Runtime::new().unwrap();
let v = Message::Reject {
message: "block".to_string(),
ccode: RejectReason::Invalid,
reason: "invalid block difficulty".to_string(),
data: Some([0xff; 32]),
};
use tokio_util::codec::{FramedRead, FramedWrite};
let v_bytes = rt.block_on(async {
let mut bytes = Vec::new();
{
let mut fw = FramedWrite::new(&mut bytes, Codec::builder().finish());
fw.send(v.clone())
.await
.expect("message should be serialized");
}
bytes
});
let v_parsed = rt.block_on(async {
let mut fr = FramedRead::new(Cursor::new(&v_bytes), Codec::builder().finish());
fr.next()
.await
.expect("a next message should be available")
.expect("that message should deserialize")
});
assert_eq!(v, v_parsed);
}
#[test] #[test]
fn filterload_message_too_large_round_trip() { fn filterload_message_too_large_round_trip() {
zebra_test::init(); zebra_test::init();