2022-06-29 04:05:31 +00:00
|
|
|
// SPDX-License-Identifier: CC0-1.0
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2021-11-05 21:58:18 +00:00
|
|
|
//! Bitcoin network messages.
|
2014-07-18 13:56:17 +00:00
|
|
|
//!
|
2021-11-05 21:58:18 +00:00
|
|
|
//! This module defines the `NetworkMessage` and `RawNetworkMessage` types that
|
|
|
|
//! are used for (de)serializing Bitcoin objects for transmission on the network.
|
2014-07-18 13:56:17 +00:00
|
|
|
//!
|
|
|
|
|
2022-11-15 23:23:01 +00:00
|
|
|
use core::{fmt, iter};
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2023-07-25 14:24:44 +00:00
|
|
|
use hashes::{sha256d, Hash};
|
2022-11-15 23:23:01 +00:00
|
|
|
|
|
|
|
use crate::blockdata::{block, transaction};
|
2023-07-25 14:24:44 +00:00
|
|
|
use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, VarInt};
|
2022-11-15 00:18:09 +00:00
|
|
|
use crate::merkle_tree::MerkleBlock;
|
2023-05-24 23:14:42 +00:00
|
|
|
use crate::p2p::address::{AddrV2Message, Address};
|
|
|
|
use crate::p2p::{
|
2022-11-15 23:23:01 +00:00
|
|
|
message_blockdata, message_bloom, message_compact_blocks, message_filter, message_network,
|
2023-06-09 06:12:31 +00:00
|
|
|
Magic,
|
2022-11-15 23:23:01 +00:00
|
|
|
};
|
|
|
|
use crate::prelude::*;
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2021-05-03 09:41:58 +00:00
|
|
|
/// The maximum number of [super::message_blockdata::Inventory] items in an `inv` message.
|
2020-11-09 22:22:59 +00:00
|
|
|
///
|
|
|
|
/// This limit is not currently enforced by this implementation.
|
|
|
|
pub const MAX_INV_SIZE: usize = 50_000;
|
|
|
|
|
2022-05-29 03:58:43 +00:00
|
|
|
/// Maximum size, in bytes, of an encoded message
|
|
|
|
/// This by neccessity should be larger tham `MAX_VEC_SIZE`
|
|
|
|
pub const MAX_MSG_SIZE: usize = 5_000_000;
|
|
|
|
|
2014-07-18 13:56:17 +00:00
|
|
|
/// Serializer for command string
|
2015-03-26 15:35:31 +00:00
|
|
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
2019-12-03 22:44:42 +00:00
|
|
|
pub struct CommandString(Cow<'static, str>);
|
2019-12-03 21:22:19 +00:00
|
|
|
|
2020-10-09 15:03:43 +00:00
|
|
|
impl CommandString {
|
2022-12-19 08:32:52 +00:00
|
|
|
/// Converts `&'static str` to `CommandString`
|
2022-07-27 18:25:40 +00:00
|
|
|
///
|
|
|
|
/// This is more efficient for string literals than non-static conversions because it avoids
|
|
|
|
/// allocation.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
2022-12-19 08:32:52 +00:00
|
|
|
/// Returns an error if, and only if, the string is
|
2022-07-27 18:25:40 +00:00
|
|
|
/// larger than 12 characters in length.
|
|
|
|
pub fn try_from_static(s: &'static str) -> Result<CommandString, CommandStringError> {
|
|
|
|
Self::try_from_static_cow(s.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn try_from_static_cow(cow: Cow<'static, str>) -> Result<CommandString, CommandStringError> {
|
2021-11-03 09:20:34 +00:00
|
|
|
if cow.len() > 12 {
|
|
|
|
Err(CommandStringError { cow })
|
2020-10-09 15:03:43 +00:00
|
|
|
} else {
|
|
|
|
Ok(CommandString(cow))
|
|
|
|
}
|
2019-12-03 22:20:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-27 18:25:40 +00:00
|
|
|
impl TryFrom<String> for CommandString {
|
|
|
|
type Error = CommandStringError;
|
|
|
|
|
|
|
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
|
|
|
Self::try_from_static_cow(value.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<Box<str>> for CommandString {
|
|
|
|
type Error = CommandStringError;
|
|
|
|
|
|
|
|
fn try_from(value: Box<str>) -> Result<Self, Self::Error> {
|
|
|
|
Self::try_from_static_cow(String::from(value).into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> TryFrom<&'a str> for CommandString {
|
|
|
|
type Error = CommandStringError;
|
|
|
|
|
|
|
|
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
|
|
|
Self::try_from_static_cow(value.to_owned().into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl core::str::FromStr for CommandString {
|
|
|
|
type Err = CommandStringError;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
Self::try_from_static_cow(s.to_owned().into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-09 15:03:43 +00:00
|
|
|
impl fmt::Display for CommandString {
|
2022-11-15 23:23:01 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.0.as_ref()) }
|
2019-12-03 22:20:45 +00:00
|
|
|
}
|
|
|
|
|
2019-12-03 22:44:42 +00:00
|
|
|
impl AsRef<str> for CommandString {
|
2022-11-15 23:23:01 +00:00
|
|
|
fn as_ref(&self) -> &str { self.0.as_ref() }
|
2019-12-03 22:44:42 +00:00
|
|
|
}
|
|
|
|
|
2019-07-11 14:56:37 +00:00
|
|
|
impl Encodable for CommandString {
|
2015-04-07 01:51:11 +00:00
|
|
|
#[inline]
|
2022-06-29 01:22:12 +00:00
|
|
|
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
2015-12-18 04:45:11 +00:00
|
|
|
let mut rawbytes = [0u8; 12];
|
2019-12-03 22:39:04 +00:00
|
|
|
let strbytes = self.0.as_bytes();
|
2020-10-09 15:03:43 +00:00
|
|
|
debug_assert!(strbytes.len() <= 12);
|
2021-11-03 09:20:34 +00:00
|
|
|
rawbytes[..strbytes.len()].copy_from_slice(strbytes);
|
Take Writer/Reader by `&mut` in consensus en/decoding
Fix #1020 (see more relevant discussion there)
This definitely makes the amount of generics compiler
has to generate by avoding generating the same functions
for `R`, &mut R`, `&mut &mut R` and so on.
old:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9947832 Jun 2 22:42 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4463024 Jun 2 22:46 target/release/deps/bitcoin-07a9dabf1f3e0266
```
new:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9866800 Jun 2 22:44 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4393392 Jun 2 22:45 target/release/deps/bitcoin-07a9dabf1f3e0266
```
In the unit-test binary itself, it saves ~100KB of data.
I did not expect much performance gains, but turn out I was wrong(*):
old:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,072,710 ns/iter (+/- 21,871)
test blockdata::block::benches::bench_block_serialize ... bench: 191,223 ns/iter (+/- 5,833)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 37,543 ns/iter (+/- 732)
test blockdata::block::benches::bench_stream_reader ... bench: 1,872,455 ns/iter (+/- 149,519)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 136 ns/iter (+/- 3)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 51 ns/iter (+/- 8)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 3 ns/iter (+/- 0)
```
new:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,028,574 ns/iter (+/- 10,910)
test blockdata::block::benches::bench_block_serialize ... bench: 162,143 ns/iter (+/- 3,363)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 30,725 ns/iter (+/- 695)
test blockdata::block::benches::bench_stream_reader ... bench: 1,437,071 ns/iter (+/- 53,694)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 92 ns/iter (+/- 2)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 17 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 4 ns/iter (+/- 0)
```
(*) - I'm benchmarking on a noisy laptop. Take this with a grain of salt. But I think
at least it doesn't make anything slower.
While doing all this manual labor that will probably generate conflicts,
I took a liberty of changing generic type names and variable names to
`r` and `R` (reader) and `w` and `W` for writer.
2022-06-03 04:50:42 +00:00
|
|
|
rawbytes.consensus_encode(w)
|
2015-04-07 01:51:11 +00:00
|
|
|
}
|
2014-08-01 16:01:39 +00:00
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
|
2019-07-11 17:06:42 +00:00
|
|
|
impl Decodable for CommandString {
|
2015-04-07 01:51:11 +00:00
|
|
|
#[inline]
|
2022-06-29 01:22:12 +00:00
|
|
|
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
Take Writer/Reader by `&mut` in consensus en/decoding
Fix #1020 (see more relevant discussion there)
This definitely makes the amount of generics compiler
has to generate by avoding generating the same functions
for `R`, &mut R`, `&mut &mut R` and so on.
old:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9947832 Jun 2 22:42 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4463024 Jun 2 22:46 target/release/deps/bitcoin-07a9dabf1f3e0266
```
new:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9866800 Jun 2 22:44 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4393392 Jun 2 22:45 target/release/deps/bitcoin-07a9dabf1f3e0266
```
In the unit-test binary itself, it saves ~100KB of data.
I did not expect much performance gains, but turn out I was wrong(*):
old:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,072,710 ns/iter (+/- 21,871)
test blockdata::block::benches::bench_block_serialize ... bench: 191,223 ns/iter (+/- 5,833)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 37,543 ns/iter (+/- 732)
test blockdata::block::benches::bench_stream_reader ... bench: 1,872,455 ns/iter (+/- 149,519)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 136 ns/iter (+/- 3)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 51 ns/iter (+/- 8)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 3 ns/iter (+/- 0)
```
new:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,028,574 ns/iter (+/- 10,910)
test blockdata::block::benches::bench_block_serialize ... bench: 162,143 ns/iter (+/- 3,363)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 30,725 ns/iter (+/- 695)
test blockdata::block::benches::bench_stream_reader ... bench: 1,437,071 ns/iter (+/- 53,694)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 92 ns/iter (+/- 2)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 17 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 4 ns/iter (+/- 0)
```
(*) - I'm benchmarking on a noisy laptop. Take this with a grain of salt. But I think
at least it doesn't make anything slower.
While doing all this manual labor that will probably generate conflicts,
I took a liberty of changing generic type names and variable names to
`r` and `R` (reader) and `w` and `W` for writer.
2022-06-03 04:50:42 +00:00
|
|
|
let rawbytes: [u8; 12] = Decodable::consensus_decode(r)?;
|
2022-11-15 23:23:01 +00:00
|
|
|
let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| {
|
|
|
|
if u > 0 {
|
|
|
|
Some(u as char)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}));
|
2015-04-07 01:51:11 +00:00
|
|
|
Ok(CommandString(rv))
|
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
2021-11-03 09:20:34 +00:00
|
|
|
/// Error returned when a command string is invalid.
|
|
|
|
///
|
|
|
|
/// This is currently returned for command strings longer than 12.
|
2023-07-27 01:10:22 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
Make error types uniform
On our way to v1.0.0 we are defining a standard for our error types,
this includes:
- Uses the following derives (unless not possible, usually because of `io::Error`)
`#[derive(Debug, Clone, PartialEq, Eq)]`
- Has `non_exhaustive` unless we really know we can commit to not adding
anything.
Furthermore, we are trying to make the codebase easy to read. Error code
is write-once-read-many (well it should be) so if we make all the error
code super uniform the users can flick to an error and quickly see what
it includes. In an effort to achieve this I have made up a style and
over recent times have change much of the error code to that new style,
this PR audits _all_ error types in the code base and enforces the
style, specifically:
- Is layed out: definition, [impl block], Display impl, error::Error impl, From impls
- `error::Error` impl matches on enum even if it returns `None` for all variants
- Display/Error impls import enum variants locally
- match uses *self and `ref e`
- error::Error variants that return `Some` come first, `None` after
Re: non_exhaustive
To make dev and review easier I have added `non_exhaustive` to _every_
error type. We can then remove it error by error as we see fit. This is
because it takes a bit of thinking to do and review where as this patch
should not take much brain power to review.
2023-10-04 02:55:45 +00:00
|
|
|
#[non_exhaustive]
|
2021-11-03 09:20:34 +00:00
|
|
|
pub struct CommandStringError {
|
|
|
|
cow: Cow<'static, str>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for CommandStringError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2022-11-15 23:23:01 +00:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"the command string '{}' has length {} which is larger than 12",
|
|
|
|
self.cow,
|
|
|
|
self.cow.len()
|
|
|
|
)
|
2021-11-03 09:20:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-04 01:35:01 +00:00
|
|
|
#[cfg(feature = "std")]
|
|
|
|
impl std::error::Error for CommandStringError {
|
|
|
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
|
|
|
|
}
|
2021-11-03 09:20:34 +00:00
|
|
|
|
2014-07-18 13:56:17 +00:00
|
|
|
/// A Network message
|
2022-01-06 02:04:47 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
2014-07-18 13:56:17 +00:00
|
|
|
pub struct RawNetworkMessage {
|
2023-07-25 12:23:18 +00:00
|
|
|
magic: Magic,
|
|
|
|
payload: NetworkMessage,
|
2023-07-25 14:24:44 +00:00
|
|
|
payload_len: u32,
|
|
|
|
checksum: [u8; 4],
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
2016-06-21 14:35:27 +00:00
|
|
|
/// A Network message payload. Proper documentation is available on at
|
|
|
|
/// [Bitcoin Wiki: Protocol Specification](https://en.bitcoin.it/wiki/Protocol_specification)
|
2020-12-21 11:59:25 +00:00
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
2014-09-10 12:15:48 +00:00
|
|
|
pub enum NetworkMessage {
|
2015-04-07 01:51:11 +00:00
|
|
|
/// `version`
|
|
|
|
Version(message_network::VersionMessage),
|
|
|
|
/// `verack`
|
|
|
|
Verack,
|
|
|
|
/// `addr`
|
|
|
|
Addr(Vec<(u32, Address)>),
|
|
|
|
/// `inv`
|
|
|
|
Inv(Vec<message_blockdata::Inventory>),
|
|
|
|
/// `getdata`
|
|
|
|
GetData(Vec<message_blockdata::Inventory>),
|
|
|
|
/// `notfound`
|
|
|
|
NotFound(Vec<message_blockdata::Inventory>),
|
|
|
|
/// `getblocks`
|
|
|
|
GetBlocks(message_blockdata::GetBlocksMessage),
|
|
|
|
/// `getheaders`
|
|
|
|
GetHeaders(message_blockdata::GetHeadersMessage),
|
2015-11-22 23:28:49 +00:00
|
|
|
/// `mempool`
|
|
|
|
MemPool,
|
2015-04-07 01:51:11 +00:00
|
|
|
/// tx
|
|
|
|
Tx(transaction::Transaction),
|
|
|
|
/// `block`
|
|
|
|
Block(block::Block),
|
|
|
|
/// `headers`
|
2022-10-27 01:29:34 +00:00
|
|
|
Headers(Vec<block::Header>),
|
2019-05-17 18:09:27 +00:00
|
|
|
/// `sendheaders`
|
|
|
|
SendHeaders,
|
2016-10-10 15:14:12 +00:00
|
|
|
/// `getaddr`
|
|
|
|
GetAddr,
|
2015-04-07 01:51:11 +00:00
|
|
|
// TODO: checkorder,
|
|
|
|
// TODO: submitorder,
|
|
|
|
// TODO: reply,
|
|
|
|
/// `ping`
|
|
|
|
Ping(u64),
|
|
|
|
/// `pong`
|
2018-02-10 15:47:46 +00:00
|
|
|
Pong(u64),
|
2021-05-21 17:46:01 +00:00
|
|
|
/// `merkleblock`
|
|
|
|
MerkleBlock(MerkleBlock),
|
|
|
|
/// BIP 37 `filterload`
|
|
|
|
FilterLoad(message_bloom::FilterLoad),
|
|
|
|
/// BIP 37 `filteradd`
|
|
|
|
FilterAdd(message_bloom::FilterAdd),
|
|
|
|
/// BIP 37 `filterclear`
|
|
|
|
FilterClear,
|
2019-02-08 12:00:51 +00:00
|
|
|
/// BIP157 getcfilters
|
|
|
|
GetCFilters(message_filter::GetCFilters),
|
|
|
|
/// BIP157 cfilter
|
|
|
|
CFilter(message_filter::CFilter),
|
|
|
|
/// BIP157 getcfheaders
|
|
|
|
GetCFHeaders(message_filter::GetCFHeaders),
|
|
|
|
/// BIP157 cfheaders
|
|
|
|
CFHeaders(message_filter::CFHeaders),
|
|
|
|
/// BIP157 getcfcheckpt
|
|
|
|
GetCFCheckpt(message_filter::GetCFCheckpt),
|
|
|
|
/// BIP157 cfcheckpt
|
|
|
|
CFCheckpt(message_filter::CFCheckpt),
|
2019-03-24 15:21:44 +00:00
|
|
|
/// BIP152 sendcmpct
|
|
|
|
SendCmpct(message_compact_blocks::SendCmpct),
|
|
|
|
/// BIP152 cmpctblock
|
|
|
|
CmpctBlock(message_compact_blocks::CmpctBlock),
|
|
|
|
/// BIP152 getblocktxn
|
|
|
|
GetBlockTxn(message_compact_blocks::GetBlockTxn),
|
|
|
|
/// BIP152 blocktxn
|
|
|
|
BlockTxn(message_compact_blocks::BlockTxn),
|
2018-02-10 15:47:46 +00:00
|
|
|
/// `alert`
|
2019-08-27 11:01:21 +00:00
|
|
|
Alert(Vec<u8>),
|
|
|
|
/// `reject`
|
2020-07-30 16:25:21 +00:00
|
|
|
Reject(message_network::Reject),
|
|
|
|
/// `feefilter`
|
|
|
|
FeeFilter(i64),
|
2020-07-22 22:00:04 +00:00
|
|
|
/// `wtxidrelay`
|
|
|
|
WtxidRelay,
|
2020-10-11 18:40:29 +00:00
|
|
|
/// `addrv2`
|
|
|
|
AddrV2(Vec<AddrV2Message>),
|
|
|
|
/// `sendaddrv2`
|
|
|
|
SendAddrV2,
|
2020-12-21 11:59:25 +00:00
|
|
|
|
|
|
|
/// Any other message.
|
|
|
|
Unknown {
|
|
|
|
/// The command of this message.
|
|
|
|
command: CommandString,
|
|
|
|
/// The payload of this message.
|
|
|
|
payload: Vec<u8>,
|
2022-11-15 23:23:01 +00:00
|
|
|
},
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
2019-12-03 21:19:44 +00:00
|
|
|
impl NetworkMessage {
|
2020-12-21 11:59:25 +00:00
|
|
|
/// Return the message command as a static string reference.
|
|
|
|
///
|
|
|
|
/// This returns `"unknown"` for [NetworkMessage::Unknown],
|
|
|
|
/// regardless of the actual command in the unknown message.
|
2021-05-03 09:41:58 +00:00
|
|
|
/// Use the [Self::command] method to get the command for unknown messages.
|
2019-12-03 22:27:19 +00:00
|
|
|
pub fn cmd(&self) -> &'static str {
|
2019-12-03 21:19:44 +00:00
|
|
|
match *self {
|
2015-04-07 01:51:11 +00:00
|
|
|
NetworkMessage::Version(_) => "version",
|
2022-11-15 23:23:01 +00:00
|
|
|
NetworkMessage::Verack => "verack",
|
|
|
|
NetworkMessage::Addr(_) => "addr",
|
|
|
|
NetworkMessage::Inv(_) => "inv",
|
2015-04-07 01:51:11 +00:00
|
|
|
NetworkMessage::GetData(_) => "getdata",
|
|
|
|
NetworkMessage::NotFound(_) => "notfound",
|
|
|
|
NetworkMessage::GetBlocks(_) => "getblocks",
|
|
|
|
NetworkMessage::GetHeaders(_) => "getheaders",
|
2022-11-15 23:23:01 +00:00
|
|
|
NetworkMessage::MemPool => "mempool",
|
|
|
|
NetworkMessage::Tx(_) => "tx",
|
|
|
|
NetworkMessage::Block(_) => "block",
|
2015-04-07 01:51:11 +00:00
|
|
|
NetworkMessage::Headers(_) => "headers",
|
2019-05-17 18:09:27 +00:00
|
|
|
NetworkMessage::SendHeaders => "sendheaders",
|
2022-11-15 23:23:01 +00:00
|
|
|
NetworkMessage::GetAddr => "getaddr",
|
|
|
|
NetworkMessage::Ping(_) => "ping",
|
|
|
|
NetworkMessage::Pong(_) => "pong",
|
2021-05-21 17:46:01 +00:00
|
|
|
NetworkMessage::MerkleBlock(_) => "merkleblock",
|
|
|
|
NetworkMessage::FilterLoad(_) => "filterload",
|
2022-11-15 23:23:01 +00:00
|
|
|
NetworkMessage::FilterAdd(_) => "filteradd",
|
|
|
|
NetworkMessage::FilterClear => "filterclear",
|
2019-02-08 12:00:51 +00:00
|
|
|
NetworkMessage::GetCFilters(_) => "getcfilters",
|
|
|
|
NetworkMessage::CFilter(_) => "cfilter",
|
|
|
|
NetworkMessage::GetCFHeaders(_) => "getcfheaders",
|
|
|
|
NetworkMessage::CFHeaders(_) => "cfheaders",
|
2019-12-20 22:47:40 +00:00
|
|
|
NetworkMessage::GetCFCheckpt(_) => "getcfcheckpt",
|
2019-02-08 12:00:51 +00:00
|
|
|
NetworkMessage::CFCheckpt(_) => "cfcheckpt",
|
2019-03-24 15:21:44 +00:00
|
|
|
NetworkMessage::SendCmpct(_) => "sendcmpct",
|
|
|
|
NetworkMessage::CmpctBlock(_) => "cmpctblock",
|
|
|
|
NetworkMessage::GetBlockTxn(_) => "getblocktxn",
|
|
|
|
NetworkMessage::BlockTxn(_) => "blocktxn",
|
2022-11-15 23:23:01 +00:00
|
|
|
NetworkMessage::Alert(_) => "alert",
|
|
|
|
NetworkMessage::Reject(_) => "reject",
|
2020-07-30 16:25:21 +00:00
|
|
|
NetworkMessage::FeeFilter(_) => "feefilter",
|
2020-07-22 22:00:04 +00:00
|
|
|
NetworkMessage::WtxidRelay => "wtxidrelay",
|
2020-10-11 18:40:29 +00:00
|
|
|
NetworkMessage::AddrV2(_) => "addrv2",
|
|
|
|
NetworkMessage::SendAddrV2 => "sendaddrv2",
|
2020-12-21 11:59:25 +00:00
|
|
|
NetworkMessage::Unknown { .. } => "unknown",
|
2019-12-03 21:19:44 +00:00
|
|
|
}
|
|
|
|
}
|
2019-12-03 22:27:19 +00:00
|
|
|
|
|
|
|
/// Return the CommandString for the message command.
|
|
|
|
pub fn command(&self) -> CommandString {
|
2020-12-21 11:59:25 +00:00
|
|
|
match *self {
|
|
|
|
NetworkMessage::Unknown { command: ref c, .. } => c.clone(),
|
2022-11-15 23:23:01 +00:00
|
|
|
_ => CommandString::try_from_static(self.cmd()).expect("cmd returns valid commands"),
|
2020-12-21 11:59:25 +00:00
|
|
|
}
|
2019-12-03 22:27:19 +00:00
|
|
|
}
|
2019-12-03 21:19:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RawNetworkMessage {
|
2023-07-25 12:23:18 +00:00
|
|
|
/// Creates a [RawNetworkMessage]
|
|
|
|
pub fn new(magic: Magic, payload: NetworkMessage) -> Self {
|
2023-07-25 14:24:44 +00:00
|
|
|
let mut engine = sha256d::Hash::engine();
|
|
|
|
let payload_len = payload.consensus_encode(&mut engine).expect("engine doesn't error");
|
|
|
|
let payload_len = u32::try_from(payload_len).expect("network message use u32 as length");
|
|
|
|
let checksum = sha256d::Hash::from_engine(engine);
|
|
|
|
let checksum = [checksum[0], checksum[1], checksum[2], checksum[3]];
|
|
|
|
Self { magic, payload, payload_len, checksum }
|
2023-07-25 12:23:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The actual message data
|
2023-07-25 14:24:44 +00:00
|
|
|
pub fn payload(&self) -> &NetworkMessage { &self.payload }
|
2023-07-25 12:23:18 +00:00
|
|
|
|
|
|
|
/// Magic bytes to identify the network these messages are meant for
|
2023-07-25 14:24:44 +00:00
|
|
|
pub fn magic(&self) -> &Magic { &self.magic }
|
2023-07-25 12:23:18 +00:00
|
|
|
|
2020-12-21 11:59:25 +00:00
|
|
|
/// Return the message command as a static string reference.
|
|
|
|
///
|
|
|
|
/// This returns `"unknown"` for [NetworkMessage::Unknown],
|
|
|
|
/// regardless of the actual command in the unknown message.
|
2021-05-03 09:41:58 +00:00
|
|
|
/// Use the [Self::command] method to get the command for unknown messages.
|
2022-11-15 23:23:01 +00:00
|
|
|
pub fn cmd(&self) -> &'static str { self.payload.cmd() }
|
2019-12-03 22:27:19 +00:00
|
|
|
|
|
|
|
/// Return the CommandString for the message command.
|
2022-11-15 23:23:01 +00:00
|
|
|
pub fn command(&self) -> CommandString { self.payload.command() }
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
2022-10-27 01:29:34 +00:00
|
|
|
struct HeaderSerializationWrapper<'a>(&'a Vec<block::Header>);
|
2019-07-11 14:56:37 +00:00
|
|
|
|
|
|
|
impl<'a> Encodable for HeaderSerializationWrapper<'a> {
|
2019-05-17 21:53:38 +00:00
|
|
|
#[inline]
|
2022-06-29 01:22:12 +00:00
|
|
|
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
2019-05-23 20:28:10 +00:00
|
|
|
let mut len = 0;
|
2023-08-24 00:37:53 +00:00
|
|
|
len += VarInt::from(self.0.len()).consensus_encode(w)?;
|
2019-05-17 21:53:38 +00:00
|
|
|
for header in self.0.iter() {
|
Take Writer/Reader by `&mut` in consensus en/decoding
Fix #1020 (see more relevant discussion there)
This definitely makes the amount of generics compiler
has to generate by avoding generating the same functions
for `R`, &mut R`, `&mut &mut R` and so on.
old:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9947832 Jun 2 22:42 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4463024 Jun 2 22:46 target/release/deps/bitcoin-07a9dabf1f3e0266
```
new:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9866800 Jun 2 22:44 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4393392 Jun 2 22:45 target/release/deps/bitcoin-07a9dabf1f3e0266
```
In the unit-test binary itself, it saves ~100KB of data.
I did not expect much performance gains, but turn out I was wrong(*):
old:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,072,710 ns/iter (+/- 21,871)
test blockdata::block::benches::bench_block_serialize ... bench: 191,223 ns/iter (+/- 5,833)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 37,543 ns/iter (+/- 732)
test blockdata::block::benches::bench_stream_reader ... bench: 1,872,455 ns/iter (+/- 149,519)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 136 ns/iter (+/- 3)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 51 ns/iter (+/- 8)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 3 ns/iter (+/- 0)
```
new:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,028,574 ns/iter (+/- 10,910)
test blockdata::block::benches::bench_block_serialize ... bench: 162,143 ns/iter (+/- 3,363)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 30,725 ns/iter (+/- 695)
test blockdata::block::benches::bench_stream_reader ... bench: 1,437,071 ns/iter (+/- 53,694)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 92 ns/iter (+/- 2)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 17 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 4 ns/iter (+/- 0)
```
(*) - I'm benchmarking on a noisy laptop. Take this with a grain of salt. But I think
at least it doesn't make anything slower.
While doing all this manual labor that will probably generate conflicts,
I took a liberty of changing generic type names and variable names to
`r` and `R` (reader) and `w` and `W` for writer.
2022-06-03 04:50:42 +00:00
|
|
|
len += header.consensus_encode(w)?;
|
|
|
|
len += 0u8.consensus_encode(w)?;
|
2019-05-17 21:53:38 +00:00
|
|
|
}
|
2019-05-23 20:28:10 +00:00
|
|
|
Ok(len)
|
2019-05-17 21:53:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-25 12:43:47 +00:00
|
|
|
impl Encodable for NetworkMessage {
|
|
|
|
fn consensus_encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<usize, io::Error> {
|
|
|
|
match self {
|
|
|
|
NetworkMessage::Version(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::Addr(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::Inv(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::GetData(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::NotFound(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::GetBlocks(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::GetHeaders(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::Tx(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::Block(ref dat) => dat.consensus_encode(writer),
|
2023-07-25 14:24:44 +00:00
|
|
|
NetworkMessage::Headers(ref dat) =>
|
|
|
|
HeaderSerializationWrapper(dat).consensus_encode(writer),
|
2023-07-25 12:43:47 +00:00
|
|
|
NetworkMessage::Ping(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::Pong(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::MerkleBlock(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::FilterLoad(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::FilterAdd(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::GetCFilters(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::CFilter(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::GetCFHeaders(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::CFHeaders(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::GetCFCheckpt(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::CFCheckpt(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::SendCmpct(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::CmpctBlock(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::GetBlockTxn(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::BlockTxn(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::Alert(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::Reject(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::FeeFilter(ref dat) => dat.consensus_encode(writer),
|
|
|
|
NetworkMessage::AddrV2(ref dat) => dat.consensus_encode(writer),
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
NetworkMessage::Verack
|
2019-05-17 18:09:27 +00:00
|
|
|
| NetworkMessage::SendHeaders
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
| NetworkMessage::MemPool
|
2020-07-22 22:00:04 +00:00
|
|
|
| NetworkMessage::GetAddr
|
2020-12-21 11:59:25 +00:00
|
|
|
| NetworkMessage::WtxidRelay
|
2021-05-21 17:46:01 +00:00
|
|
|
| NetworkMessage::FilterClear
|
2023-07-25 12:43:47 +00:00
|
|
|
| NetworkMessage::SendAddrV2 => Ok(0),
|
|
|
|
NetworkMessage::Unknown { payload: ref data, .. } => data.consensus_encode(writer),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Encodable for RawNetworkMessage {
|
|
|
|
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
|
|
|
let mut len = 0;
|
|
|
|
len += self.magic.consensus_encode(w)?;
|
|
|
|
len += self.command().consensus_encode(w)?;
|
2023-07-25 14:24:44 +00:00
|
|
|
len += self.payload_len.consensus_encode(w)?;
|
|
|
|
len += self.checksum.consensus_encode(w)?;
|
|
|
|
len += self.payload().consensus_encode(w)?;
|
2019-05-23 20:28:10 +00:00
|
|
|
Ok(len)
|
2015-04-07 01:51:11 +00:00
|
|
|
}
|
2014-08-01 16:01:39 +00:00
|
|
|
}
|
|
|
|
|
2022-10-27 01:29:34 +00:00
|
|
|
struct HeaderDeserializationWrapper(Vec<block::Header>);
|
2019-07-11 17:06:42 +00:00
|
|
|
|
|
|
|
impl Decodable for HeaderDeserializationWrapper {
|
2019-05-17 21:53:38 +00:00
|
|
|
#[inline]
|
2022-11-15 23:23:01 +00:00
|
|
|
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(
|
|
|
|
r: &mut R,
|
|
|
|
) -> Result<Self, encode::Error> {
|
Take Writer/Reader by `&mut` in consensus en/decoding
Fix #1020 (see more relevant discussion there)
This definitely makes the amount of generics compiler
has to generate by avoding generating the same functions
for `R`, &mut R`, `&mut &mut R` and so on.
old:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9947832 Jun 2 22:42 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4463024 Jun 2 22:46 target/release/deps/bitcoin-07a9dabf1f3e0266
```
new:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9866800 Jun 2 22:44 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4393392 Jun 2 22:45 target/release/deps/bitcoin-07a9dabf1f3e0266
```
In the unit-test binary itself, it saves ~100KB of data.
I did not expect much performance gains, but turn out I was wrong(*):
old:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,072,710 ns/iter (+/- 21,871)
test blockdata::block::benches::bench_block_serialize ... bench: 191,223 ns/iter (+/- 5,833)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 37,543 ns/iter (+/- 732)
test blockdata::block::benches::bench_stream_reader ... bench: 1,872,455 ns/iter (+/- 149,519)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 136 ns/iter (+/- 3)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 51 ns/iter (+/- 8)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 3 ns/iter (+/- 0)
```
new:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,028,574 ns/iter (+/- 10,910)
test blockdata::block::benches::bench_block_serialize ... bench: 162,143 ns/iter (+/- 3,363)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 30,725 ns/iter (+/- 695)
test blockdata::block::benches::bench_stream_reader ... bench: 1,437,071 ns/iter (+/- 53,694)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 92 ns/iter (+/- 2)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 17 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 4 ns/iter (+/- 0)
```
(*) - I'm benchmarking on a noisy laptop. Take this with a grain of salt. But I think
at least it doesn't make anything slower.
While doing all this manual labor that will probably generate conflicts,
I took a liberty of changing generic type names and variable names to
`r` and `R` (reader) and `w` and `W` for writer.
2022-06-03 04:50:42 +00:00
|
|
|
let len = VarInt::consensus_decode(r)?.0;
|
2022-05-29 03:58:43 +00:00
|
|
|
// should be above usual number of items to avoid
|
|
|
|
// allocation
|
|
|
|
let mut ret = Vec::with_capacity(core::cmp::min(1024 * 16, len as usize));
|
2019-05-17 21:53:38 +00:00
|
|
|
for _ in 0..len {
|
Take Writer/Reader by `&mut` in consensus en/decoding
Fix #1020 (see more relevant discussion there)
This definitely makes the amount of generics compiler
has to generate by avoding generating the same functions
for `R`, &mut R`, `&mut &mut R` and so on.
old:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9947832 Jun 2 22:42 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4463024 Jun 2 22:46 target/release/deps/bitcoin-07a9dabf1f3e0266
```
new:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9866800 Jun 2 22:44 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4393392 Jun 2 22:45 target/release/deps/bitcoin-07a9dabf1f3e0266
```
In the unit-test binary itself, it saves ~100KB of data.
I did not expect much performance gains, but turn out I was wrong(*):
old:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,072,710 ns/iter (+/- 21,871)
test blockdata::block::benches::bench_block_serialize ... bench: 191,223 ns/iter (+/- 5,833)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 37,543 ns/iter (+/- 732)
test blockdata::block::benches::bench_stream_reader ... bench: 1,872,455 ns/iter (+/- 149,519)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 136 ns/iter (+/- 3)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 51 ns/iter (+/- 8)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 3 ns/iter (+/- 0)
```
new:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,028,574 ns/iter (+/- 10,910)
test blockdata::block::benches::bench_block_serialize ... bench: 162,143 ns/iter (+/- 3,363)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 30,725 ns/iter (+/- 695)
test blockdata::block::benches::bench_stream_reader ... bench: 1,437,071 ns/iter (+/- 53,694)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 92 ns/iter (+/- 2)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 17 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 4 ns/iter (+/- 0)
```
(*) - I'm benchmarking on a noisy laptop. Take this with a grain of salt. But I think
at least it doesn't make anything slower.
While doing all this manual labor that will probably generate conflicts,
I took a liberty of changing generic type names and variable names to
`r` and `R` (reader) and `w` and `W` for writer.
2022-06-03 04:50:42 +00:00
|
|
|
ret.push(Decodable::consensus_decode(r)?);
|
|
|
|
if u8::consensus_decode(r)? != 0u8 {
|
2022-11-15 23:23:01 +00:00
|
|
|
return Err(encode::Error::ParseFailed(
|
|
|
|
"Headers message should not contain transactions",
|
|
|
|
));
|
2019-05-17 21:53:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(HeaderDeserializationWrapper(ret))
|
|
|
|
}
|
2022-05-29 03:58:43 +00:00
|
|
|
|
|
|
|
#[inline]
|
2022-06-29 01:22:12 +00:00
|
|
|
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
2023-09-11 17:56:57 +00:00
|
|
|
Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64))
|
2022-05-29 03:58:43 +00:00
|
|
|
}
|
2019-05-17 21:53:38 +00:00
|
|
|
}
|
|
|
|
|
2019-07-11 17:06:42 +00:00
|
|
|
impl Decodable for RawNetworkMessage {
|
2022-11-15 23:23:01 +00:00
|
|
|
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(
|
|
|
|
r: &mut R,
|
|
|
|
) -> Result<Self, encode::Error> {
|
Take Writer/Reader by `&mut` in consensus en/decoding
Fix #1020 (see more relevant discussion there)
This definitely makes the amount of generics compiler
has to generate by avoding generating the same functions
for `R`, &mut R`, `&mut &mut R` and so on.
old:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9947832 Jun 2 22:42 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4463024 Jun 2 22:46 target/release/deps/bitcoin-07a9dabf1f3e0266
```
new:
```
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 9866800 Jun 2 22:44 target/release/deps/bitcoin-07a9dabf1f3e0266
> strip target/release/deps/bitcoin-07a9dabf1f3e0266
> ls -al target/release/deps/bitcoin-07a9dabf1f3e0266
-rwxrwxr-x 1 dpc dpc 4393392 Jun 2 22:45 target/release/deps/bitcoin-07a9dabf1f3e0266
```
In the unit-test binary itself, it saves ~100KB of data.
I did not expect much performance gains, but turn out I was wrong(*):
old:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,072,710 ns/iter (+/- 21,871)
test blockdata::block::benches::bench_block_serialize ... bench: 191,223 ns/iter (+/- 5,833)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 37,543 ns/iter (+/- 732)
test blockdata::block::benches::bench_stream_reader ... bench: 1,872,455 ns/iter (+/- 149,519)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 136 ns/iter (+/- 3)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 51 ns/iter (+/- 8)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 3 ns/iter (+/- 0)
```
new:
```
test blockdata::block::benches::bench_block_deserialize ... bench: 1,028,574 ns/iter (+/- 10,910)
test blockdata::block::benches::bench_block_serialize ... bench: 162,143 ns/iter (+/- 3,363)
test blockdata::block::benches::bench_block_serialize_logic ... bench: 30,725 ns/iter (+/- 695)
test blockdata::block::benches::bench_stream_reader ... bench: 1,437,071 ns/iter (+/- 53,694)
test blockdata::transaction::benches::bench_transaction_deserialize ... bench: 92 ns/iter (+/- 2)
test blockdata::transaction::benches::bench_transaction_serialize ... bench: 17 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_serialize_logic ... bench: 5 ns/iter (+/- 0)
test blockdata::transaction::benches::bench_transaction_size ... bench: 4 ns/iter (+/- 0)
```
(*) - I'm benchmarking on a noisy laptop. Take this with a grain of salt. But I think
at least it doesn't make anything slower.
While doing all this manual labor that will probably generate conflicts,
I took a liberty of changing generic type names and variable names to
`r` and `R` (reader) and `w` and `W` for writer.
2022-06-03 04:50:42 +00:00
|
|
|
let magic = Decodable::consensus_decode_from_finite_reader(r)?;
|
|
|
|
let cmd = CommandString::consensus_decode_from_finite_reader(r)?;
|
2023-07-25 14:24:44 +00:00
|
|
|
let checked_data = CheckedData::consensus_decode_from_finite_reader(r)?;
|
|
|
|
let checksum = checked_data.checksum();
|
|
|
|
let raw_payload = checked_data.into_data();
|
|
|
|
let payload_len = raw_payload.len() as u32;
|
2015-04-07 01:51:11 +00:00
|
|
|
|
2021-06-09 10:40:41 +00:00
|
|
|
let mut mem_d = io::Cursor::new(raw_payload);
|
2020-12-21 11:59:25 +00:00
|
|
|
let payload = match &cmd.0[..] {
|
2022-11-15 23:23:01 +00:00
|
|
|
"version" =>
|
|
|
|
NetworkMessage::Version(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
|
|
|
|
"verack" => NetworkMessage::Verack,
|
|
|
|
"addr" =>
|
|
|
|
NetworkMessage::Addr(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
|
|
|
|
"inv" =>
|
|
|
|
NetworkMessage::Inv(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
|
|
|
|
"getdata" =>
|
|
|
|
NetworkMessage::GetData(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
|
|
|
|
"notfound" => NetworkMessage::NotFound(Decodable::consensus_decode_from_finite_reader(
|
|
|
|
&mut mem_d,
|
|
|
|
)?),
|
|
|
|
"getblocks" => NetworkMessage::GetBlocks(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
|
|
|
"getheaders" => NetworkMessage::GetHeaders(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
2015-11-22 23:28:49 +00:00
|
|
|
"mempool" => NetworkMessage::MemPool,
|
2022-11-15 23:23:01 +00:00
|
|
|
"block" =>
|
|
|
|
NetworkMessage::Block(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
|
2019-07-11 17:06:42 +00:00
|
|
|
"headers" => NetworkMessage::Headers(
|
2022-11-15 23:23:01 +00:00
|
|
|
HeaderDeserializationWrapper::consensus_decode_from_finite_reader(&mut mem_d)?.0,
|
2019-07-11 17:06:42 +00:00
|
|
|
),
|
2019-05-17 18:09:27 +00:00
|
|
|
"sendheaders" => NetworkMessage::SendHeaders,
|
2016-10-10 15:14:12 +00:00
|
|
|
"getaddr" => NetworkMessage::GetAddr,
|
2022-11-15 23:23:01 +00:00
|
|
|
"ping" =>
|
|
|
|
NetworkMessage::Ping(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
|
|
|
|
"pong" =>
|
|
|
|
NetworkMessage::Pong(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
|
|
|
|
"merkleblock" => NetworkMessage::MerkleBlock(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
|
|
|
"filterload" => NetworkMessage::FilterLoad(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
|
|
|
"filteradd" => NetworkMessage::FilterAdd(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
2021-05-21 17:46:01 +00:00
|
|
|
"filterclear" => NetworkMessage::FilterClear,
|
2022-11-15 23:23:01 +00:00
|
|
|
"tx" => NetworkMessage::Tx(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
|
|
|
|
"getcfilters" => NetworkMessage::GetCFilters(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
|
|
|
"cfilter" =>
|
|
|
|
NetworkMessage::CFilter(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
|
|
|
|
"getcfheaders" => NetworkMessage::GetCFHeaders(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
|
|
|
"cfheaders" => NetworkMessage::CFHeaders(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
|
|
|
"getcfcheckpt" => NetworkMessage::GetCFCheckpt(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
|
|
|
"cfcheckpt" => NetworkMessage::CFCheckpt(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
|
|
|
"reject" =>
|
|
|
|
NetworkMessage::Reject(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
|
|
|
|
"alert" =>
|
|
|
|
NetworkMessage::Alert(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
|
|
|
|
"feefilter" => NetworkMessage::FeeFilter(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
|
|
|
"sendcmpct" => NetworkMessage::SendCmpct(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
|
|
|
"cmpctblock" => NetworkMessage::CmpctBlock(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
|
|
|
"getblocktxn" => NetworkMessage::GetBlockTxn(
|
|
|
|
Decodable::consensus_decode_from_finite_reader(&mut mem_d)?,
|
|
|
|
),
|
|
|
|
"blocktxn" => NetworkMessage::BlockTxn(Decodable::consensus_decode_from_finite_reader(
|
|
|
|
&mut mem_d,
|
|
|
|
)?),
|
2020-07-22 22:00:04 +00:00
|
|
|
"wtxidrelay" => NetworkMessage::WtxidRelay,
|
2022-11-15 23:23:01 +00:00
|
|
|
"addrv2" =>
|
|
|
|
NetworkMessage::AddrV2(Decodable::consensus_decode_from_finite_reader(&mut mem_d)?),
|
2020-10-11 18:40:29 +00:00
|
|
|
"sendaddrv2" => NetworkMessage::SendAddrV2,
|
2022-11-15 23:23:01 +00:00
|
|
|
_ => NetworkMessage::Unknown { command: cmd, payload: mem_d.into_inner() },
|
2015-04-07 01:51:11 +00:00
|
|
|
};
|
2023-07-25 14:24:44 +00:00
|
|
|
Ok(RawNetworkMessage { magic, payload, payload_len, checksum })
|
2015-04-07 01:51:11 +00:00
|
|
|
}
|
2022-05-29 03:58:43 +00:00
|
|
|
|
|
|
|
#[inline]
|
2022-06-29 01:22:12 +00:00
|
|
|
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
2023-09-11 17:56:57 +00:00
|
|
|
Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64))
|
2022-05-29 03:58:43 +00:00
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2020-10-11 18:40:29 +00:00
|
|
|
use std::net::Ipv4Addr;
|
2022-11-15 23:23:01 +00:00
|
|
|
|
2023-03-22 03:09:58 +00:00
|
|
|
use hashes::sha256d::Hash;
|
|
|
|
use hashes::Hash as HashTrait;
|
2023-08-10 22:44:58 +00:00
|
|
|
use hex::test_hex_unwrap as hex;
|
2023-03-22 03:09:58 +00:00
|
|
|
|
2022-11-15 23:23:01 +00:00
|
|
|
use super::message_network::{Reject, RejectReason, VersionMessage};
|
|
|
|
use super::{CommandString, NetworkMessage, RawNetworkMessage, *};
|
|
|
|
use crate::bip152::BlockTransactionsRequest;
|
|
|
|
use crate::blockdata::block::{self, Block};
|
2022-07-30 12:22:18 +00:00
|
|
|
use crate::blockdata::script::ScriptBuf;
|
2022-11-15 23:23:01 +00:00
|
|
|
use crate::blockdata::transaction::Transaction;
|
2022-05-02 22:13:57 +00:00
|
|
|
use crate::consensus::encode::{deserialize, deserialize_partial, serialize};
|
2023-06-09 06:18:39 +00:00
|
|
|
use crate::network::Network;
|
2023-05-24 23:14:42 +00:00
|
|
|
use crate::p2p::address::{AddrV2, AddrV2Message, Address};
|
|
|
|
use crate::p2p::message_blockdata::{GetBlocksMessage, GetHeadersMessage, Inventory};
|
|
|
|
use crate::p2p::message_bloom::{BloomFlags, FilterAdd, FilterLoad};
|
|
|
|
use crate::p2p::message_compact_blocks::{GetBlockTxn, SendCmpct};
|
|
|
|
use crate::p2p::message_filter::{
|
2022-11-15 23:23:01 +00:00
|
|
|
CFCheckpt, CFHeaders, CFilter, GetCFCheckpt, GetCFHeaders, GetCFilters,
|
|
|
|
};
|
2023-06-09 06:12:31 +00:00
|
|
|
use crate::p2p::{Magic, ServiceFlags};
|
2019-12-22 12:00:31 +00:00
|
|
|
|
2022-11-15 23:23:01 +00:00
|
|
|
fn hash(slice: [u8; 32]) -> Hash { Hash::from_slice(&slice).unwrap() }
|
2019-12-22 12:00:31 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn full_round_ser_der_raw_network_message_test() {
|
|
|
|
// TODO: Impl Rand traits here to easily generate random values.
|
2022-12-03 19:57:18 +00:00
|
|
|
let version_msg: VersionMessage = deserialize(&hex!("721101000100000000000000e6e0845300000000010000000000000000000000000000000000ffff0000000000000100000000000000fd87d87eeb4364f22cf54dca59412db7208d47d920cffce83ee8102f5361746f7368693a302e392e39392f2c9f040001")).unwrap();
|
|
|
|
let tx: Transaction = deserialize(&hex!("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000")).unwrap();
|
2022-01-12 03:22:45 +00:00
|
|
|
let block: Block = deserialize(&include_bytes!("../../tests/data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw")[..]).unwrap();
|
2022-12-03 19:57:18 +00:00
|
|
|
let header: block::Header = deserialize(&hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b")).unwrap();
|
2022-11-02 22:36:37 +00:00
|
|
|
let script: ScriptBuf =
|
|
|
|
deserialize(&hex!("1976a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac")).unwrap();
|
2022-12-03 19:57:18 +00:00
|
|
|
let merkle_block: MerkleBlock = deserialize(&hex!("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101")).unwrap();
|
|
|
|
let cmptblock = deserialize(&hex!("00000030d923ad36ff2d955abab07f8a0a6e813bc6e066b973e780c5e36674cad5d1cd1f6e265f2a17a0d35cbe701fe9d06e2c6324cfe135f6233e8b767bfa3fb4479b71115dc562ffff7f2006000000000000000000000000010002000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0302ee00ffffffff0100f9029500000000015100000000")).unwrap();
|
|
|
|
let blocktxn = deserialize(&hex!("2e93c0cff39ff605020072d96bc3a8d20b8447e294d08092351c8583e08d9b5a01020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0402dc0000ffffffff0200f90295000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000")).unwrap();
|
2022-07-06 15:05:45 +00:00
|
|
|
|
2019-12-22 12:00:31 +00:00
|
|
|
let msgs = vec![
|
|
|
|
NetworkMessage::Version(version_msg),
|
|
|
|
NetworkMessage::Verack,
|
2022-11-15 23:23:01 +00:00
|
|
|
NetworkMessage::Addr(vec![(
|
|
|
|
45,
|
|
|
|
Address::new(&([123, 255, 000, 100], 833).into(), ServiceFlags::NETWORK),
|
|
|
|
)]),
|
2019-12-18 11:40:46 +00:00
|
|
|
NetworkMessage::Inv(vec![Inventory::Block(hash([8u8; 32]).into())]),
|
|
|
|
NetworkMessage::GetData(vec![Inventory::Transaction(hash([45u8; 32]).into())]),
|
|
|
|
NetworkMessage::NotFound(vec![Inventory::Error]),
|
2022-11-15 23:23:01 +00:00
|
|
|
NetworkMessage::GetBlocks(GetBlocksMessage::new(
|
|
|
|
vec![hash([1u8; 32]).into(), hash([4u8; 32]).into()],
|
|
|
|
hash([5u8; 32]).into(),
|
|
|
|
)),
|
|
|
|
NetworkMessage::GetHeaders(GetHeadersMessage::new(
|
|
|
|
vec![hash([10u8; 32]).into(), hash([40u8; 32]).into()],
|
|
|
|
hash([50u8; 32]).into(),
|
|
|
|
)),
|
2019-12-22 12:00:31 +00:00
|
|
|
NetworkMessage::MemPool,
|
|
|
|
NetworkMessage::Tx(tx),
|
|
|
|
NetworkMessage::Block(block),
|
|
|
|
NetworkMessage::Headers(vec![header]),
|
|
|
|
NetworkMessage::SendHeaders,
|
|
|
|
NetworkMessage::GetAddr,
|
|
|
|
NetworkMessage::Ping(15),
|
|
|
|
NetworkMessage::Pong(23),
|
2021-05-21 17:46:01 +00:00
|
|
|
NetworkMessage::MerkleBlock(merkle_block),
|
2022-11-15 23:23:01 +00:00
|
|
|
NetworkMessage::FilterLoad(FilterLoad {
|
2022-12-03 19:57:18 +00:00
|
|
|
filter: hex!("03614e9b050000000000000001"),
|
2022-11-15 23:23:01 +00:00
|
|
|
hash_funcs: 1,
|
|
|
|
tweak: 2,
|
|
|
|
flags: BloomFlags::All,
|
|
|
|
}),
|
|
|
|
NetworkMessage::FilterAdd(FilterAdd { data: script.as_bytes().to_vec() }),
|
2022-11-02 22:36:37 +00:00
|
|
|
NetworkMessage::FilterAdd(FilterAdd {
|
|
|
|
data: hash([29u8; 32]).as_byte_array().to_vec(),
|
|
|
|
}),
|
2021-05-21 17:46:01 +00:00
|
|
|
NetworkMessage::FilterClear,
|
2022-11-15 23:23:01 +00:00
|
|
|
NetworkMessage::GetCFilters(GetCFilters {
|
|
|
|
filter_type: 2,
|
|
|
|
start_height: 52,
|
|
|
|
stop_hash: hash([42u8; 32]).into(),
|
|
|
|
}),
|
|
|
|
NetworkMessage::CFilter(CFilter {
|
|
|
|
filter_type: 7,
|
|
|
|
block_hash: hash([25u8; 32]).into(),
|
|
|
|
filter: vec![1, 2, 3],
|
|
|
|
}),
|
|
|
|
NetworkMessage::GetCFHeaders(GetCFHeaders {
|
|
|
|
filter_type: 4,
|
|
|
|
start_height: 102,
|
|
|
|
stop_hash: hash([47u8; 32]).into(),
|
|
|
|
}),
|
|
|
|
NetworkMessage::CFHeaders(CFHeaders {
|
|
|
|
filter_type: 13,
|
|
|
|
stop_hash: hash([53u8; 32]).into(),
|
|
|
|
previous_filter_header: hash([12u8; 32]).into(),
|
|
|
|
filter_hashes: vec![hash([4u8; 32]).into(), hash([12u8; 32]).into()],
|
|
|
|
}),
|
|
|
|
NetworkMessage::GetCFCheckpt(GetCFCheckpt {
|
|
|
|
filter_type: 17,
|
|
|
|
stop_hash: hash([25u8; 32]).into(),
|
|
|
|
}),
|
|
|
|
NetworkMessage::CFCheckpt(CFCheckpt {
|
|
|
|
filter_type: 27,
|
|
|
|
stop_hash: hash([77u8; 32]).into(),
|
|
|
|
filter_headers: vec![hash([3u8; 32]).into(), hash([99u8; 32]).into()],
|
|
|
|
}),
|
|
|
|
NetworkMessage::Alert(vec![45, 66, 3, 2, 6, 8, 9, 12, 3, 130]),
|
|
|
|
NetworkMessage::Reject(Reject {
|
|
|
|
message: "Test reject".into(),
|
|
|
|
ccode: RejectReason::Duplicate,
|
|
|
|
reason: "Cause".into(),
|
|
|
|
hash: hash([255u8; 32]),
|
|
|
|
}),
|
2020-07-30 16:25:21 +00:00
|
|
|
NetworkMessage::FeeFilter(1000),
|
2020-07-22 22:00:04 +00:00
|
|
|
NetworkMessage::WtxidRelay,
|
2022-11-15 23:23:01 +00:00
|
|
|
NetworkMessage::AddrV2(vec![AddrV2Message {
|
|
|
|
addr: AddrV2::Ipv4(Ipv4Addr::new(127, 0, 0, 1)),
|
|
|
|
port: 0,
|
|
|
|
services: ServiceFlags::NONE,
|
|
|
|
time: 0,
|
|
|
|
}]),
|
2020-10-11 18:40:29 +00:00
|
|
|
NetworkMessage::SendAddrV2,
|
2022-07-06 15:05:45 +00:00
|
|
|
NetworkMessage::CmpctBlock(cmptblock),
|
2022-11-15 23:23:01 +00:00
|
|
|
NetworkMessage::GetBlockTxn(GetBlockTxn {
|
|
|
|
txs_request: BlockTransactionsRequest {
|
|
|
|
block_hash: hash([11u8; 32]).into(),
|
|
|
|
indexes: vec![0, 1, 2, 3, 10, 3002],
|
|
|
|
},
|
|
|
|
}),
|
2022-07-06 15:05:45 +00:00
|
|
|
NetworkMessage::BlockTxn(blocktxn),
|
2022-11-15 23:23:01 +00:00
|
|
|
NetworkMessage::SendCmpct(SendCmpct { send_compact: true, version: 8333 }),
|
2019-12-22 12:00:31 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
for msg in msgs {
|
2023-07-25 14:24:44 +00:00
|
|
|
let raw_msg = RawNetworkMessage::new(Magic::from_bytes([57, 0, 0, 0]), msg);
|
2019-12-22 12:00:31 +00:00
|
|
|
assert_eq!(deserialize::<RawNetworkMessage>(&serialize(&raw_msg)).unwrap(), raw_msg);
|
|
|
|
}
|
|
|
|
}
|
2015-04-07 01:51:11 +00:00
|
|
|
|
|
|
|
#[test]
|
2020-10-09 15:03:43 +00:00
|
|
|
fn commandstring_test() {
|
|
|
|
// Test converting.
|
2022-11-15 23:23:01 +00:00
|
|
|
assert_eq!(
|
|
|
|
CommandString::try_from_static("AndrewAndrew").unwrap().as_ref(),
|
|
|
|
"AndrewAndrew"
|
|
|
|
);
|
2022-07-27 18:25:40 +00:00
|
|
|
assert!(CommandString::try_from_static("AndrewAndrewA").is_err());
|
2020-10-09 15:03:43 +00:00
|
|
|
|
|
|
|
// Test serializing.
|
2019-12-03 21:22:19 +00:00
|
|
|
let cs = CommandString("Andrew".into());
|
Move relevant names into consensus::encode
- Move network::encodable::* to consensus::encode::*
- Rename Consensus{En,De}codable to {En,De}codable (now under
consensus::encode)
- Move network::serialize::Error to consensus::encode::Error
- Remove Raw{En,De}coder, implement {En,De}coder for T: {Write,Read}
instead
- Move network::serialize::Simple{En,De}coder to
consensus::encode::{En,De}coder
- Rename util::Error::Serialize to util::Error::Encode
- Modify comments to refer to new names
- Modify files to refer to new names
- Expose {En,De}cod{able,er}, {de,}serialize, Params
- Do not return Result for serialize{,_hex} as serializing to a Vec
should never fail
2018-09-20 10:15:45 +00:00
|
|
|
assert_eq!(serialize(&cs), vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
|
2019-12-10 17:22:55 +00:00
|
|
|
|
2020-10-09 15:03:43 +00:00
|
|
|
// Test deserializing
|
2022-11-15 23:23:01 +00:00
|
|
|
let cs: Result<CommandString, _> =
|
|
|
|
deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
|
2015-04-07 01:51:11 +00:00
|
|
|
assert!(cs.is_ok());
|
2019-12-03 21:22:19 +00:00
|
|
|
assert_eq!(cs.as_ref().unwrap().to_string(), "Andrew".to_owned());
|
2022-07-27 18:25:40 +00:00
|
|
|
assert_eq!(cs.unwrap(), CommandString::try_from_static("Andrew").unwrap());
|
2015-04-07 01:51:11 +00:00
|
|
|
|
2022-11-15 23:23:01 +00:00
|
|
|
let short_cs: Result<CommandString, _> =
|
|
|
|
deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]);
|
2015-04-07 01:51:11 +00:00
|
|
|
assert!(short_cs.is_err());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-10-27 02:31:55 +00:00
|
|
|
#[rustfmt::skip]
|
2015-04-07 01:51:11 +00:00
|
|
|
fn serialize_verack_test() {
|
2023-07-25 14:24:44 +00:00
|
|
|
assert_eq!(serialize(&RawNetworkMessage::new(Magic::from(Network::Bitcoin), NetworkMessage::Verack)),
|
2022-10-27 02:31:55 +00:00
|
|
|
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61,
|
|
|
|
0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
|
2015-04-07 01:51:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-10-27 02:31:55 +00:00
|
|
|
#[rustfmt::skip]
|
2015-04-07 01:51:11 +00:00
|
|
|
fn serialize_ping_test() {
|
2023-07-25 14:24:44 +00:00
|
|
|
assert_eq!(serialize(&RawNetworkMessage::new(Magic::from(Network::Bitcoin), NetworkMessage::Ping(100))),
|
2022-10-27 02:31:55 +00:00
|
|
|
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d,
|
|
|
|
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
2015-04-07 01:51:11 +00:00
|
|
|
}
|
2015-11-22 23:28:49 +00:00
|
|
|
|
|
|
|
#[test]
|
2022-10-27 02:31:55 +00:00
|
|
|
#[rustfmt::skip]
|
2015-11-22 23:28:49 +00:00
|
|
|
fn serialize_mempool_test() {
|
2023-07-25 14:24:44 +00:00
|
|
|
assert_eq!(serialize(&RawNetworkMessage::new(Magic::from(Network::Bitcoin), NetworkMessage::MemPool)),
|
2022-10-27 02:31:55 +00:00
|
|
|
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70,
|
|
|
|
0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
|
2015-11-22 23:28:49 +00:00
|
|
|
}
|
|
|
|
|
2016-10-10 15:14:12 +00:00
|
|
|
#[test]
|
2022-10-27 02:31:55 +00:00
|
|
|
#[rustfmt::skip]
|
2016-10-10 15:14:12 +00:00
|
|
|
fn serialize_getaddr_test() {
|
2023-07-25 14:24:44 +00:00
|
|
|
assert_eq!(serialize(&RawNetworkMessage::new(Magic::from(Network::Bitcoin), NetworkMessage::GetAddr)),
|
2022-10-27 02:31:55 +00:00
|
|
|
vec![0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61,
|
|
|
|
0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]);
|
2016-10-10 15:14:12 +00:00
|
|
|
}
|
|
|
|
|
Better RawNewtorkMessage deserealization from IO stream (#231)
Follow-up to https://github.com/rust-bitcoin/rust-bitcoin/pull/229
While working with remote peers over the network it is required to deserealize RawNetworkMessage from `TCPStream` to read the incoming messages. These messages can be partial – or one TCP packet can contain few of them. To make the library usable for such use cases, I have implemented the required functionality and covered it with unit tests.
Sample usage:
```rust
fn run() -> Result<(), Error> {
// Opening stream to the remote bitcoind peer
let mut stream = TcpStream::connect(SocketAddr::from(([37, 187, 0, 47], 8333));
let start = SystemTime::now();
// Constructing and sending `version` message to get some messages back from the remote peer
let since_the_epoch = start.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let version_msg = message::RawNetworkMessage {
magic: constants::Network::Bitcoin.magic(),
payload: message::NetworkMessage::Version(message_network::VersionMessage::new(
0,
since_the_epoch.as_secs() as i64,
address::Address::new(receiver, 0),
address::Address::new(receiver, 0),
0,
String::from("macx0r"),
0
))
};
stream.write(encode::serialize(&version_msg).as_slice())?;
// Receiving incoming messages
let mut buffer = vec![];
loop {
let result = StreamReader::new(&mut stream, None).read_messages();
if let Err(err) = result {
stream.shutdown(Shutdown::Both)?;
return Err(Error::DataError(err))
}
for msg in result.unwrap() {
println!("Received message: {:?}", msg.payload);
}
}
}
```
Sample output is the following:
```
Received message: Version(VersionMessage { version: 70015, services: 1037, timestamp: 1548637162, receiver: Address {services: 0, address: [0, 0, 0, 0, 0, 65535, 23536, 35968], port: 33716}, sender: Address {services: 1037, address: [0, 0, 0, 0, 0, 0, 0, 0], port: 0}, nonce: 1370726880972892633, user_agent: "/Satoshi:0.17.99/", start_height: 560412, relay: true })
Received message: Verack
Received message: Alert([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0])
```
Working sample code can be found here: https://github.com/dr-orlovsky/bitcoinbigdata-netlistener
2019-02-27 21:41:28 +00:00
|
|
|
#[test]
|
|
|
|
fn deserialize_getaddr_test() {
|
2022-10-27 02:31:55 +00:00
|
|
|
#[rustfmt::skip]
|
|
|
|
let msg = deserialize(&[
|
|
|
|
0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61,
|
|
|
|
0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2
|
|
|
|
]);
|
2023-07-25 14:24:44 +00:00
|
|
|
let preimage =
|
|
|
|
RawNetworkMessage::new(Magic::from(Network::Bitcoin), NetworkMessage::GetAddr);
|
Better RawNewtorkMessage deserealization from IO stream (#231)
Follow-up to https://github.com/rust-bitcoin/rust-bitcoin/pull/229
While working with remote peers over the network it is required to deserealize RawNetworkMessage from `TCPStream` to read the incoming messages. These messages can be partial – or one TCP packet can contain few of them. To make the library usable for such use cases, I have implemented the required functionality and covered it with unit tests.
Sample usage:
```rust
fn run() -> Result<(), Error> {
// Opening stream to the remote bitcoind peer
let mut stream = TcpStream::connect(SocketAddr::from(([37, 187, 0, 47], 8333));
let start = SystemTime::now();
// Constructing and sending `version` message to get some messages back from the remote peer
let since_the_epoch = start.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let version_msg = message::RawNetworkMessage {
magic: constants::Network::Bitcoin.magic(),
payload: message::NetworkMessage::Version(message_network::VersionMessage::new(
0,
since_the_epoch.as_secs() as i64,
address::Address::new(receiver, 0),
address::Address::new(receiver, 0),
0,
String::from("macx0r"),
0
))
};
stream.write(encode::serialize(&version_msg).as_slice())?;
// Receiving incoming messages
let mut buffer = vec![];
loop {
let result = StreamReader::new(&mut stream, None).read_messages();
if let Err(err) = result {
stream.shutdown(Shutdown::Both)?;
return Err(Error::DataError(err))
}
for msg in result.unwrap() {
println!("Received message: {:?}", msg.payload);
}
}
}
```
Sample output is the following:
```
Received message: Version(VersionMessage { version: 70015, services: 1037, timestamp: 1548637162, receiver: Address {services: 0, address: [0, 0, 0, 0, 0, 65535, 23536, 35968], port: 33716}, sender: Address {services: 1037, address: [0, 0, 0, 0, 0, 0, 0, 0], port: 0}, nonce: 1370726880972892633, user_agent: "/Satoshi:0.17.99/", start_height: 560412, relay: true })
Received message: Verack
Received message: Alert([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0])
```
Working sample code can be found here: https://github.com/dr-orlovsky/bitcoinbigdata-netlistener
2019-02-27 21:41:28 +00:00
|
|
|
assert!(msg.is_ok());
|
2022-11-15 23:23:01 +00:00
|
|
|
let msg: RawNetworkMessage = msg.unwrap();
|
Better RawNewtorkMessage deserealization from IO stream (#231)
Follow-up to https://github.com/rust-bitcoin/rust-bitcoin/pull/229
While working with remote peers over the network it is required to deserealize RawNetworkMessage from `TCPStream` to read the incoming messages. These messages can be partial – or one TCP packet can contain few of them. To make the library usable for such use cases, I have implemented the required functionality and covered it with unit tests.
Sample usage:
```rust
fn run() -> Result<(), Error> {
// Opening stream to the remote bitcoind peer
let mut stream = TcpStream::connect(SocketAddr::from(([37, 187, 0, 47], 8333));
let start = SystemTime::now();
// Constructing and sending `version` message to get some messages back from the remote peer
let since_the_epoch = start.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let version_msg = message::RawNetworkMessage {
magic: constants::Network::Bitcoin.magic(),
payload: message::NetworkMessage::Version(message_network::VersionMessage::new(
0,
since_the_epoch.as_secs() as i64,
address::Address::new(receiver, 0),
address::Address::new(receiver, 0),
0,
String::from("macx0r"),
0
))
};
stream.write(encode::serialize(&version_msg).as_slice())?;
// Receiving incoming messages
let mut buffer = vec![];
loop {
let result = StreamReader::new(&mut stream, None).read_messages();
if let Err(err) = result {
stream.shutdown(Shutdown::Both)?;
return Err(Error::DataError(err))
}
for msg in result.unwrap() {
println!("Received message: {:?}", msg.payload);
}
}
}
```
Sample output is the following:
```
Received message: Version(VersionMessage { version: 70015, services: 1037, timestamp: 1548637162, receiver: Address {services: 0, address: [0, 0, 0, 0, 0, 65535, 23536, 35968], port: 33716}, sender: Address {services: 1037, address: [0, 0, 0, 0, 0, 0, 0, 0], port: 0}, nonce: 1370726880972892633, user_agent: "/Satoshi:0.17.99/", start_height: 560412, relay: true })
Received message: Verack
Received message: Alert([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0])
```
Working sample code can be found here: https://github.com/dr-orlovsky/bitcoinbigdata-netlistener
2019-02-27 21:41:28 +00:00
|
|
|
assert_eq!(preimage.magic, msg.magic);
|
|
|
|
assert_eq!(preimage.payload, msg.payload);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn deserialize_version_test() {
|
2022-10-27 02:31:55 +00:00
|
|
|
#[rustfmt::skip]
|
|
|
|
let msg = deserialize::<RawNetworkMessage>(&[
|
|
|
|
0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x73,
|
|
|
|
0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x66, 0x00, 0x00, 0x00, 0xbe, 0x61, 0xb8, 0x27,
|
|
|
|
0x7f, 0x11, 0x01, 0x00, 0x0d, 0x04, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x4d, 0x5c,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
|
|
|
0x5b, 0xf0, 0x8c, 0x80, 0xb4, 0xbd, 0x0d, 0x04,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0xfa, 0xa9, 0x95, 0x59, 0xcc, 0x68, 0xa1, 0xc1,
|
|
|
|
0x10, 0x2f, 0x53, 0x61, 0x74, 0x6f, 0x73, 0x68,
|
|
|
|
0x69, 0x3a, 0x30, 0x2e, 0x31, 0x37, 0x2e, 0x31,
|
|
|
|
0x2f, 0x93, 0x8c, 0x08, 0x00, 0x01
|
|
|
|
]);
|
Better RawNewtorkMessage deserealization from IO stream (#231)
Follow-up to https://github.com/rust-bitcoin/rust-bitcoin/pull/229
While working with remote peers over the network it is required to deserealize RawNetworkMessage from `TCPStream` to read the incoming messages. These messages can be partial – or one TCP packet can contain few of them. To make the library usable for such use cases, I have implemented the required functionality and covered it with unit tests.
Sample usage:
```rust
fn run() -> Result<(), Error> {
// Opening stream to the remote bitcoind peer
let mut stream = TcpStream::connect(SocketAddr::from(([37, 187, 0, 47], 8333));
let start = SystemTime::now();
// Constructing and sending `version` message to get some messages back from the remote peer
let since_the_epoch = start.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let version_msg = message::RawNetworkMessage {
magic: constants::Network::Bitcoin.magic(),
payload: message::NetworkMessage::Version(message_network::VersionMessage::new(
0,
since_the_epoch.as_secs() as i64,
address::Address::new(receiver, 0),
address::Address::new(receiver, 0),
0,
String::from("macx0r"),
0
))
};
stream.write(encode::serialize(&version_msg).as_slice())?;
// Receiving incoming messages
let mut buffer = vec![];
loop {
let result = StreamReader::new(&mut stream, None).read_messages();
if let Err(err) = result {
stream.shutdown(Shutdown::Both)?;
return Err(Error::DataError(err))
}
for msg in result.unwrap() {
println!("Received message: {:?}", msg.payload);
}
}
}
```
Sample output is the following:
```
Received message: Version(VersionMessage { version: 70015, services: 1037, timestamp: 1548637162, receiver: Address {services: 0, address: [0, 0, 0, 0, 0, 65535, 23536, 35968], port: 33716}, sender: Address {services: 1037, address: [0, 0, 0, 0, 0, 0, 0, 0], port: 0}, nonce: 1370726880972892633, user_agent: "/Satoshi:0.17.99/", start_height: 560412, relay: true })
Received message: Verack
Received message: Alert([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0])
```
Working sample code can be found here: https://github.com/dr-orlovsky/bitcoinbigdata-netlistener
2019-02-27 21:41:28 +00:00
|
|
|
|
|
|
|
assert!(msg.is_ok());
|
|
|
|
let msg = msg.unwrap();
|
2022-09-28 00:32:47 +00:00
|
|
|
assert_eq!(msg.magic, Magic::from(Network::Bitcoin));
|
Better RawNewtorkMessage deserealization from IO stream (#231)
Follow-up to https://github.com/rust-bitcoin/rust-bitcoin/pull/229
While working with remote peers over the network it is required to deserealize RawNetworkMessage from `TCPStream` to read the incoming messages. These messages can be partial – or one TCP packet can contain few of them. To make the library usable for such use cases, I have implemented the required functionality and covered it with unit tests.
Sample usage:
```rust
fn run() -> Result<(), Error> {
// Opening stream to the remote bitcoind peer
let mut stream = TcpStream::connect(SocketAddr::from(([37, 187, 0, 47], 8333));
let start = SystemTime::now();
// Constructing and sending `version` message to get some messages back from the remote peer
let since_the_epoch = start.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let version_msg = message::RawNetworkMessage {
magic: constants::Network::Bitcoin.magic(),
payload: message::NetworkMessage::Version(message_network::VersionMessage::new(
0,
since_the_epoch.as_secs() as i64,
address::Address::new(receiver, 0),
address::Address::new(receiver, 0),
0,
String::from("macx0r"),
0
))
};
stream.write(encode::serialize(&version_msg).as_slice())?;
// Receiving incoming messages
let mut buffer = vec![];
loop {
let result = StreamReader::new(&mut stream, None).read_messages();
if let Err(err) = result {
stream.shutdown(Shutdown::Both)?;
return Err(Error::DataError(err))
}
for msg in result.unwrap() {
println!("Received message: {:?}", msg.payload);
}
}
}
```
Sample output is the following:
```
Received message: Version(VersionMessage { version: 70015, services: 1037, timestamp: 1548637162, receiver: Address {services: 0, address: [0, 0, 0, 0, 0, 65535, 23536, 35968], port: 33716}, sender: Address {services: 1037, address: [0, 0, 0, 0, 0, 0, 0, 0], port: 0}, nonce: 1370726880972892633, user_agent: "/Satoshi:0.17.99/", start_height: 560412, relay: true })
Received message: Verack
Received message: Alert([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0])
```
Working sample code can be found here: https://github.com/dr-orlovsky/bitcoinbigdata-netlistener
2019-02-27 21:41:28 +00:00
|
|
|
if let NetworkMessage::Version(version_msg) = msg.payload {
|
|
|
|
assert_eq!(version_msg.version, 70015);
|
2022-11-15 23:23:01 +00:00
|
|
|
assert_eq!(
|
|
|
|
version_msg.services,
|
|
|
|
ServiceFlags::NETWORK
|
|
|
|
| ServiceFlags::BLOOM
|
|
|
|
| ServiceFlags::WITNESS
|
|
|
|
| ServiceFlags::NETWORK_LIMITED
|
|
|
|
);
|
Better RawNewtorkMessage deserealization from IO stream (#231)
Follow-up to https://github.com/rust-bitcoin/rust-bitcoin/pull/229
While working with remote peers over the network it is required to deserealize RawNetworkMessage from `TCPStream` to read the incoming messages. These messages can be partial – or one TCP packet can contain few of them. To make the library usable for such use cases, I have implemented the required functionality and covered it with unit tests.
Sample usage:
```rust
fn run() -> Result<(), Error> {
// Opening stream to the remote bitcoind peer
let mut stream = TcpStream::connect(SocketAddr::from(([37, 187, 0, 47], 8333));
let start = SystemTime::now();
// Constructing and sending `version` message to get some messages back from the remote peer
let since_the_epoch = start.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let version_msg = message::RawNetworkMessage {
magic: constants::Network::Bitcoin.magic(),
payload: message::NetworkMessage::Version(message_network::VersionMessage::new(
0,
since_the_epoch.as_secs() as i64,
address::Address::new(receiver, 0),
address::Address::new(receiver, 0),
0,
String::from("macx0r"),
0
))
};
stream.write(encode::serialize(&version_msg).as_slice())?;
// Receiving incoming messages
let mut buffer = vec![];
loop {
let result = StreamReader::new(&mut stream, None).read_messages();
if let Err(err) = result {
stream.shutdown(Shutdown::Both)?;
return Err(Error::DataError(err))
}
for msg in result.unwrap() {
println!("Received message: {:?}", msg.payload);
}
}
}
```
Sample output is the following:
```
Received message: Version(VersionMessage { version: 70015, services: 1037, timestamp: 1548637162, receiver: Address {services: 0, address: [0, 0, 0, 0, 0, 65535, 23536, 35968], port: 33716}, sender: Address {services: 1037, address: [0, 0, 0, 0, 0, 0, 0, 0], port: 0}, nonce: 1370726880972892633, user_agent: "/Satoshi:0.17.99/", start_height: 560412, relay: true })
Received message: Verack
Received message: Alert([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0])
```
Working sample code can be found here: https://github.com/dr-orlovsky/bitcoinbigdata-netlistener
2019-02-27 21:41:28 +00:00
|
|
|
assert_eq!(version_msg.timestamp, 1548554224);
|
|
|
|
assert_eq!(version_msg.nonce, 13952548347456104954);
|
|
|
|
assert_eq!(version_msg.user_agent, "/Satoshi:0.17.1/");
|
|
|
|
assert_eq!(version_msg.start_height, 560275);
|
2022-06-07 04:31:03 +00:00
|
|
|
assert!(version_msg.relay);
|
Better RawNewtorkMessage deserealization from IO stream (#231)
Follow-up to https://github.com/rust-bitcoin/rust-bitcoin/pull/229
While working with remote peers over the network it is required to deserealize RawNetworkMessage from `TCPStream` to read the incoming messages. These messages can be partial – or one TCP packet can contain few of them. To make the library usable for such use cases, I have implemented the required functionality and covered it with unit tests.
Sample usage:
```rust
fn run() -> Result<(), Error> {
// Opening stream to the remote bitcoind peer
let mut stream = TcpStream::connect(SocketAddr::from(([37, 187, 0, 47], 8333));
let start = SystemTime::now();
// Constructing and sending `version` message to get some messages back from the remote peer
let since_the_epoch = start.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let version_msg = message::RawNetworkMessage {
magic: constants::Network::Bitcoin.magic(),
payload: message::NetworkMessage::Version(message_network::VersionMessage::new(
0,
since_the_epoch.as_secs() as i64,
address::Address::new(receiver, 0),
address::Address::new(receiver, 0),
0,
String::from("macx0r"),
0
))
};
stream.write(encode::serialize(&version_msg).as_slice())?;
// Receiving incoming messages
let mut buffer = vec![];
loop {
let result = StreamReader::new(&mut stream, None).read_messages();
if let Err(err) = result {
stream.shutdown(Shutdown::Both)?;
return Err(Error::DataError(err))
}
for msg in result.unwrap() {
println!("Received message: {:?}", msg.payload);
}
}
}
```
Sample output is the following:
```
Received message: Version(VersionMessage { version: 70015, services: 1037, timestamp: 1548637162, receiver: Address {services: 0, address: [0, 0, 0, 0, 0, 65535, 23536, 35968], port: 33716}, sender: Address {services: 1037, address: [0, 0, 0, 0, 0, 0, 0, 0], port: 0}, nonce: 1370726880972892633, user_agent: "/Satoshi:0.17.99/", start_height: 560412, relay: true })
Received message: Verack
Received message: Alert([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0])
```
Working sample code can be found here: https://github.com/dr-orlovsky/bitcoinbigdata-netlistener
2019-02-27 21:41:28 +00:00
|
|
|
} else {
|
|
|
|
panic!("Wrong message type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn deserialize_partial_message_test() {
|
2022-10-27 02:31:55 +00:00
|
|
|
#[rustfmt::skip]
|
|
|
|
let data = [
|
|
|
|
0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x73,
|
Better RawNewtorkMessage deserealization from IO stream (#231)
Follow-up to https://github.com/rust-bitcoin/rust-bitcoin/pull/229
While working with remote peers over the network it is required to deserealize RawNetworkMessage from `TCPStream` to read the incoming messages. These messages can be partial – or one TCP packet can contain few of them. To make the library usable for such use cases, I have implemented the required functionality and covered it with unit tests.
Sample usage:
```rust
fn run() -> Result<(), Error> {
// Opening stream to the remote bitcoind peer
let mut stream = TcpStream::connect(SocketAddr::from(([37, 187, 0, 47], 8333));
let start = SystemTime::now();
// Constructing and sending `version` message to get some messages back from the remote peer
let since_the_epoch = start.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let version_msg = message::RawNetworkMessage {
magic: constants::Network::Bitcoin.magic(),
payload: message::NetworkMessage::Version(message_network::VersionMessage::new(
0,
since_the_epoch.as_secs() as i64,
address::Address::new(receiver, 0),
address::Address::new(receiver, 0),
0,
String::from("macx0r"),
0
))
};
stream.write(encode::serialize(&version_msg).as_slice())?;
// Receiving incoming messages
let mut buffer = vec![];
loop {
let result = StreamReader::new(&mut stream, None).read_messages();
if let Err(err) = result {
stream.shutdown(Shutdown::Both)?;
return Err(Error::DataError(err))
}
for msg in result.unwrap() {
println!("Received message: {:?}", msg.payload);
}
}
}
```
Sample output is the following:
```
Received message: Version(VersionMessage { version: 70015, services: 1037, timestamp: 1548637162, receiver: Address {services: 0, address: [0, 0, 0, 0, 0, 65535, 23536, 35968], port: 33716}, sender: Address {services: 1037, address: [0, 0, 0, 0, 0, 0, 0, 0], port: 0}, nonce: 1370726880972892633, user_agent: "/Satoshi:0.17.99/", start_height: 560412, relay: true })
Received message: Verack
Received message: Alert([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0])
```
Working sample code can be found here: https://github.com/dr-orlovsky/bitcoinbigdata-netlistener
2019-02-27 21:41:28 +00:00
|
|
|
0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x66, 0x00, 0x00, 0x00, 0xbe, 0x61, 0xb8, 0x27,
|
|
|
|
0x7f, 0x11, 0x01, 0x00, 0x0d, 0x04, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x4d, 0x5c,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
|
|
|
0x5b, 0xf0, 0x8c, 0x80, 0xb4, 0xbd, 0x0d, 0x04,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0xfa, 0xa9, 0x95, 0x59, 0xcc, 0x68, 0xa1, 0xc1,
|
|
|
|
0x10, 0x2f, 0x53, 0x61, 0x74, 0x6f, 0x73, 0x68,
|
|
|
|
0x69, 0x3a, 0x30, 0x2e, 0x31, 0x37, 0x2e, 0x31,
|
2022-10-27 02:31:55 +00:00
|
|
|
0x2f, 0x93, 0x8c, 0x08, 0x00, 0x01, 0x00, 0x00
|
|
|
|
];
|
Better RawNewtorkMessage deserealization from IO stream (#231)
Follow-up to https://github.com/rust-bitcoin/rust-bitcoin/pull/229
While working with remote peers over the network it is required to deserealize RawNetworkMessage from `TCPStream` to read the incoming messages. These messages can be partial – or one TCP packet can contain few of them. To make the library usable for such use cases, I have implemented the required functionality and covered it with unit tests.
Sample usage:
```rust
fn run() -> Result<(), Error> {
// Opening stream to the remote bitcoind peer
let mut stream = TcpStream::connect(SocketAddr::from(([37, 187, 0, 47], 8333));
let start = SystemTime::now();
// Constructing and sending `version` message to get some messages back from the remote peer
let since_the_epoch = start.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let version_msg = message::RawNetworkMessage {
magic: constants::Network::Bitcoin.magic(),
payload: message::NetworkMessage::Version(message_network::VersionMessage::new(
0,
since_the_epoch.as_secs() as i64,
address::Address::new(receiver, 0),
address::Address::new(receiver, 0),
0,
String::from("macx0r"),
0
))
};
stream.write(encode::serialize(&version_msg).as_slice())?;
// Receiving incoming messages
let mut buffer = vec![];
loop {
let result = StreamReader::new(&mut stream, None).read_messages();
if let Err(err) = result {
stream.shutdown(Shutdown::Both)?;
return Err(Error::DataError(err))
}
for msg in result.unwrap() {
println!("Received message: {:?}", msg.payload);
}
}
}
```
Sample output is the following:
```
Received message: Version(VersionMessage { version: 70015, services: 1037, timestamp: 1548637162, receiver: Address {services: 0, address: [0, 0, 0, 0, 0, 65535, 23536, 35968], port: 33716}, sender: Address {services: 1037, address: [0, 0, 0, 0, 0, 0, 0, 0], port: 0}, nonce: 1370726880972892633, user_agent: "/Satoshi:0.17.99/", start_height: 560412, relay: true })
Received message: Verack
Received message: Alert([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0])
```
Working sample code can be found here: https://github.com/dr-orlovsky/bitcoinbigdata-netlistener
2019-02-27 21:41:28 +00:00
|
|
|
let msg = deserialize_partial::<RawNetworkMessage>(&data);
|
|
|
|
assert!(msg.is_ok());
|
|
|
|
|
|
|
|
let (msg, consumed) = msg.unwrap();
|
|
|
|
assert_eq!(consumed, data.to_vec().len() - 2);
|
2022-09-28 00:32:47 +00:00
|
|
|
assert_eq!(msg.magic, Magic::from(Network::Bitcoin));
|
Better RawNewtorkMessage deserealization from IO stream (#231)
Follow-up to https://github.com/rust-bitcoin/rust-bitcoin/pull/229
While working with remote peers over the network it is required to deserealize RawNetworkMessage from `TCPStream` to read the incoming messages. These messages can be partial – or one TCP packet can contain few of them. To make the library usable for such use cases, I have implemented the required functionality and covered it with unit tests.
Sample usage:
```rust
fn run() -> Result<(), Error> {
// Opening stream to the remote bitcoind peer
let mut stream = TcpStream::connect(SocketAddr::from(([37, 187, 0, 47], 8333));
let start = SystemTime::now();
// Constructing and sending `version` message to get some messages back from the remote peer
let since_the_epoch = start.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let version_msg = message::RawNetworkMessage {
magic: constants::Network::Bitcoin.magic(),
payload: message::NetworkMessage::Version(message_network::VersionMessage::new(
0,
since_the_epoch.as_secs() as i64,
address::Address::new(receiver, 0),
address::Address::new(receiver, 0),
0,
String::from("macx0r"),
0
))
};
stream.write(encode::serialize(&version_msg).as_slice())?;
// Receiving incoming messages
let mut buffer = vec![];
loop {
let result = StreamReader::new(&mut stream, None).read_messages();
if let Err(err) = result {
stream.shutdown(Shutdown::Both)?;
return Err(Error::DataError(err))
}
for msg in result.unwrap() {
println!("Received message: {:?}", msg.payload);
}
}
}
```
Sample output is the following:
```
Received message: Version(VersionMessage { version: 70015, services: 1037, timestamp: 1548637162, receiver: Address {services: 0, address: [0, 0, 0, 0, 0, 65535, 23536, 35968], port: 33716}, sender: Address {services: 1037, address: [0, 0, 0, 0, 0, 0, 0, 0], port: 0}, nonce: 1370726880972892633, user_agent: "/Satoshi:0.17.99/", start_height: 560412, relay: true })
Received message: Verack
Received message: Alert([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0])
```
Working sample code can be found here: https://github.com/dr-orlovsky/bitcoinbigdata-netlistener
2019-02-27 21:41:28 +00:00
|
|
|
if let NetworkMessage::Version(version_msg) = msg.payload {
|
|
|
|
assert_eq!(version_msg.version, 70015);
|
2022-11-15 23:23:01 +00:00
|
|
|
assert_eq!(
|
|
|
|
version_msg.services,
|
|
|
|
ServiceFlags::NETWORK
|
|
|
|
| ServiceFlags::BLOOM
|
|
|
|
| ServiceFlags::WITNESS
|
|
|
|
| ServiceFlags::NETWORK_LIMITED
|
|
|
|
);
|
Better RawNewtorkMessage deserealization from IO stream (#231)
Follow-up to https://github.com/rust-bitcoin/rust-bitcoin/pull/229
While working with remote peers over the network it is required to deserealize RawNetworkMessage from `TCPStream` to read the incoming messages. These messages can be partial – or one TCP packet can contain few of them. To make the library usable for such use cases, I have implemented the required functionality and covered it with unit tests.
Sample usage:
```rust
fn run() -> Result<(), Error> {
// Opening stream to the remote bitcoind peer
let mut stream = TcpStream::connect(SocketAddr::from(([37, 187, 0, 47], 8333));
let start = SystemTime::now();
// Constructing and sending `version` message to get some messages back from the remote peer
let since_the_epoch = start.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let version_msg = message::RawNetworkMessage {
magic: constants::Network::Bitcoin.magic(),
payload: message::NetworkMessage::Version(message_network::VersionMessage::new(
0,
since_the_epoch.as_secs() as i64,
address::Address::new(receiver, 0),
address::Address::new(receiver, 0),
0,
String::from("macx0r"),
0
))
};
stream.write(encode::serialize(&version_msg).as_slice())?;
// Receiving incoming messages
let mut buffer = vec![];
loop {
let result = StreamReader::new(&mut stream, None).read_messages();
if let Err(err) = result {
stream.shutdown(Shutdown::Both)?;
return Err(Error::DataError(err))
}
for msg in result.unwrap() {
println!("Received message: {:?}", msg.payload);
}
}
}
```
Sample output is the following:
```
Received message: Version(VersionMessage { version: 70015, services: 1037, timestamp: 1548637162, receiver: Address {services: 0, address: [0, 0, 0, 0, 0, 65535, 23536, 35968], port: 33716}, sender: Address {services: 1037, address: [0, 0, 0, 0, 0, 0, 0, 0], port: 0}, nonce: 1370726880972892633, user_agent: "/Satoshi:0.17.99/", start_height: 560412, relay: true })
Received message: Verack
Received message: Alert([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0])
```
Working sample code can be found here: https://github.com/dr-orlovsky/bitcoinbigdata-netlistener
2019-02-27 21:41:28 +00:00
|
|
|
assert_eq!(version_msg.timestamp, 1548554224);
|
|
|
|
assert_eq!(version_msg.nonce, 13952548347456104954);
|
|
|
|
assert_eq!(version_msg.user_agent, "/Satoshi:0.17.1/");
|
|
|
|
assert_eq!(version_msg.start_height, 560275);
|
2022-06-07 04:31:03 +00:00
|
|
|
assert!(version_msg.relay);
|
Better RawNewtorkMessage deserealization from IO stream (#231)
Follow-up to https://github.com/rust-bitcoin/rust-bitcoin/pull/229
While working with remote peers over the network it is required to deserealize RawNetworkMessage from `TCPStream` to read the incoming messages. These messages can be partial – or one TCP packet can contain few of them. To make the library usable for such use cases, I have implemented the required functionality and covered it with unit tests.
Sample usage:
```rust
fn run() -> Result<(), Error> {
// Opening stream to the remote bitcoind peer
let mut stream = TcpStream::connect(SocketAddr::from(([37, 187, 0, 47], 8333));
let start = SystemTime::now();
// Constructing and sending `version` message to get some messages back from the remote peer
let since_the_epoch = start.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let version_msg = message::RawNetworkMessage {
magic: constants::Network::Bitcoin.magic(),
payload: message::NetworkMessage::Version(message_network::VersionMessage::new(
0,
since_the_epoch.as_secs() as i64,
address::Address::new(receiver, 0),
address::Address::new(receiver, 0),
0,
String::from("macx0r"),
0
))
};
stream.write(encode::serialize(&version_msg).as_slice())?;
// Receiving incoming messages
let mut buffer = vec![];
loop {
let result = StreamReader::new(&mut stream, None).read_messages();
if let Err(err) = result {
stream.shutdown(Shutdown::Both)?;
return Err(Error::DataError(err))
}
for msg in result.unwrap() {
println!("Received message: {:?}", msg.payload);
}
}
}
```
Sample output is the following:
```
Received message: Version(VersionMessage { version: 70015, services: 1037, timestamp: 1548637162, receiver: Address {services: 0, address: [0, 0, 0, 0, 0, 65535, 23536, 35968], port: 33716}, sender: Address {services: 1037, address: [0, 0, 0, 0, 0, 0, 0, 0], port: 0}, nonce: 1370726880972892633, user_agent: "/Satoshi:0.17.99/", start_height: 560412, relay: true })
Received message: Verack
Received message: Alert([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 254, 255, 255, 127, 1, 255, 255, 255, 127, 0, 0, 0, 0, 255, 255, 255, 127, 0, 255, 255, 255, 127, 0, 47, 85, 82, 71, 69, 78, 84, 58, 32, 65, 108, 101, 114, 116, 32, 107, 101, 121, 32, 99, 111, 109, 112, 114, 111, 109, 105, 115, 101, 100, 44, 32, 117, 112, 103, 114, 97, 100, 101, 32, 114, 101, 113, 117, 105, 114, 101, 100, 0])
```
Working sample code can be found here: https://github.com/dr-orlovsky/bitcoinbigdata-netlistener
2019-02-27 21:41:28 +00:00
|
|
|
} else {
|
|
|
|
panic!("Wrong message type");
|
|
|
|
}
|
|
|
|
}
|
2014-07-18 13:56:17 +00:00
|
|
|
}
|