rust-bitcoin-unsafe-fast/bitcoin/examples/handshake.rs

108 lines
3.9 KiB
Rust
Raw Normal View History

2020-02-19 07:46:26 +00:00
extern crate bitcoin;
use std::io::{BufReader, Write};
2020-02-17 14:12:13 +00:00
use std::net::{IpAddr, Ipv4Addr, Shutdown, SocketAddr, TcpStream};
use std::time::{SystemTime, UNIX_EPOCH};
2020-03-03 11:18:37 +00:00
use std::{env, process};
2020-02-17 14:12:13 +00:00
use bitcoin::consensus::{encode, Decodable};
use bitcoin::p2p::{self, address, message, message_network};
2020-02-19 08:11:26 +00:00
use bitcoin::secp256k1::rand::Rng;
2020-02-17 14:12:13 +00:00
fn main() {
2024-01-18 06:06:23 +00:00
// This example establishes a connection to a Bitcoin node, sends the initial
2020-02-17 14:12:13 +00:00
// "version" message, waits for the reply, and finally closes the connection.
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
eprintln!("not enough arguments");
process::exit(1);
}
let str_address = &args[1];
2020-02-17 14:12:13 +00:00
let address: SocketAddr = str_address.parse().unwrap_or_else(|error| {
eprintln!("Error parsing address: {:?}", error);
process::exit(1);
});
2020-02-17 14:12:13 +00:00
2020-02-17 15:07:10 +00:00
let version_message = build_version_message(address);
2020-02-17 14:12:13 +00:00
let first_message =
message::RawNetworkMessage::new(bitcoin::Network::Bitcoin.magic(), version_message);
2020-02-17 14:12:13 +00:00
if let Ok(mut stream) = TcpStream::connect(address) {
// Send the message
2020-02-17 15:17:13 +00:00
let _ = stream.write_all(encode::serialize(&first_message).as_slice());
2020-02-17 14:12:13 +00:00
println!("Sent version message");
2020-02-28 15:28:25 +00:00
// Setup StreamReader
let read_stream = stream.try_clone().unwrap();
let mut stream_reader = BufReader::new(read_stream);
2020-02-17 14:12:13 +00:00
loop {
2020-02-28 15:28:25 +00:00
// Loop an retrieve new messages
let reply = message::RawNetworkMessage::consensus_decode(&mut stream_reader).unwrap();
match reply.payload() {
2020-02-17 14:12:13 +00:00
message::NetworkMessage::Version(_) => {
println!("Received version message: {:?}", reply.payload());
2020-02-17 14:12:13 +00:00
let second_message = message::RawNetworkMessage::new(
bitcoin::Network::Bitcoin.magic(),
message::NetworkMessage::Verack,
);
2020-02-17 14:12:13 +00:00
2020-02-17 15:17:13 +00:00
let _ = stream.write_all(encode::serialize(&second_message).as_slice());
2020-02-17 14:12:13 +00:00
println!("Sent verack message");
}
message::NetworkMessage::Verack => {
println!("Received verack message: {:?}", reply.payload());
2020-02-17 14:12:13 +00:00
break;
}
_ => {
println!("Received unknown message: {:?}", reply.payload());
2020-02-17 14:12:13 +00:00
break;
}
}
}
let _ = stream.shutdown(Shutdown::Both);
} else {
eprintln!("Failed to open connection");
}
}
fn build_version_message(address: SocketAddr) -> message::NetworkMessage {
// Building version message, see https://en.bitcoin.it/wiki/Protocol_documentation#version
let my_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
// "bitfield of features to be enabled for this connection"
let services = p2p::ServiceFlags::NONE;
2020-02-17 14:12:13 +00:00
// "standard UNIX timestamp in seconds"
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time error").as_secs();
2020-02-17 14:12:13 +00:00
// "The network address of the node receiving this message"
let addr_recv = address::Address::new(&address, p2p::ServiceFlags::NONE);
2020-02-17 14:12:13 +00:00
// "The network address of the node emitting this message"
let addr_from = address::Address::new(&my_address, p2p::ServiceFlags::NONE);
2020-02-17 14:12:13 +00:00
// "Node random nonce, randomly generated every time a version packet is sent. This nonce is used to detect connections to self."
2020-02-19 07:46:26 +00:00
let nonce: u64 = secp256k1::rand::thread_rng().gen();
2020-02-17 14:12:13 +00:00
// "User Agent (0x00 if string is 0 bytes long)"
let user_agent = String::from("rust-example");
// "The last block received by the emitting node"
let start_height: i32 = 0;
// Construct the message
message::NetworkMessage::Version(message_network::VersionMessage::new(
services,
timestamp as i64,
addr_recv,
addr_from,
nonce,
user_agent,
start_height,
))
}