1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::{
io::{Error, ErrorKind, Result},
net::IpAddr,
};
use crate::ids;
use crate::message::{self, Outbound};
#[derive(
std::clone::Clone,
std::cmp::Eq,
std::cmp::Ord,
std::cmp::PartialEq,
std::cmp::PartialOrd,
std::fmt::Debug,
std::hash::Hash,
)]
pub struct Message {
pub network_id: u32,
pub my_time: u64,
pub ip_addr: IpAddr,
pub ip_port: u16,
pub my_version: String,
pub my_version_time: u64,
pub sig: Vec<u8>,
pub tracked_subnets: Vec<ids::Id>,
}
pub fn create_outbound(msg: Message) -> impl Outbound {
msg
}
impl std::fmt::Display for Message {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "msg version (network ID {})", self.network_id)
}
}
impl Outbound for Message {
fn serialize_with_header(&self) -> Result<bytes::Bytes> {
let type_id = message::TYPES
.get("version")
.ok_or_else(|| Error::new(ErrorKind::InvalidInput, "unknown type name"))?;
let packer = message::default_packer_with_header();
packer.pack_byte(*type_id)?;
packer.pack_u32(self.network_id)?;
packer.pack_u32(0)?;
packer.pack_u64(self.my_time)?;
packer.pack_ip(self.ip_addr, self.ip_port)?;
packer.pack_str(&self.my_version)?;
packer.pack_u64(self.my_version_time)?;
packer.pack_bytes_with_header(self.sig.as_ref())?;
packer.pack_u32(self.tracked_subnets.len() as u32)?;
for id in self.tracked_subnets.iter() {
packer.pack_bytes(id.as_ref())?;
}
Ok(packer.take_bytes())
}
}
#[test]
fn test_message() {
use avalanche_utils::cmp;
use std::net::Ipv4Addr;
let msg = create_outbound(Message {
network_id: 100000,
my_time: 77777777,
ip_addr: IpAddr::V4(Ipv4Addr::LOCALHOST),
ip_port: 8080,
my_version: String::from("v1.2.3"),
my_version_time: 1234567,
sig: vec![0x01, 0x02, 0x03],
tracked_subnets: vec![crate::ids::Id::from_slice(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01,
])],
});
let data_with_header = msg.serialize_with_header().unwrap();
let expected_data: &[u8] = &[
0x00, 0x00, 0x00, 0x5e,
0x13,
0x00, 0x01, 0x86, 0xa0,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0xa2, 0xcb, 0x71,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00,
0x01,
0x1f, 0x90,
0x00, 0x06,
0x76, 0x31, 0x2e, 0x32, 0x2e, 0x33,
0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xd6, 0x87,
0x00, 0x00, 0x00, 0x03,
0x01, 0x02, 0x03,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01,
];
assert!(cmp::eq_vectors(&expected_data, &data_with_header));
}