-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
163 additions
and
117 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,156 +1,129 @@ | ||
use std::net::SocketAddr; | ||
use sha2::{Digest, Sha256}; | ||
use std::net::{IpAddr, SocketAddr}; | ||
use tokio::io::{AsyncReadExt, AsyncWriteExt}; | ||
use tokio::net::TcpStream; | ||
|
||
static VERSION_MESSAGE: &[u8] = &[ | ||
// header | ||
249, 190, 180, 217, // magic | ||
118, 101, 114, 115, 105, 111, 110, 0, 0, 0, 0, 0, // "version" command | ||
86, 0, 0, 0, // payload len | ||
94, 38, 138, 233, // checksum | ||
// payload | ||
113, 17, 1, 0, // protocol version | ||
0, 0, 0, 0, 0, 0, 0, 0, // services | ||
0, 0, 0, 0, 0, 0, 0, 0, // time | ||
// 36, 99, 31, 100, 0, 0, 0, 0, // time | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 134, 195, 185, 52, 32, 141, // recipient address info | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, // sender address info | ||
0, 0, 0, 0, 0, 0, 0, 0, // Node ID, | ||
// 131, 67, 161, 229, 100, 242, 249, 181, // Node ID, | ||
0, // "" sub-version string, 0 bytes long | ||
0, // relay | ||
0, 0, 0, 0, // last block sending node | ||
]; | ||
|
||
static VERACK_MESSAGE: &[u8] = &[ | ||
// header | ||
249, 190, 180, 217, // magic | ||
18, 101, 114, 97, 99, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // payload len | ||
18, 101, 114, 97, 99, 107, 0, 0, 0, 0, 0, 0, // "verack" command | ||
0, 0, 0, 0, // payload len | ||
93, 246, 224, 226, // checksum | ||
]; | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
let address: SocketAddr = "134.195.185.52:8333".parse().unwrap(); | ||
let address: SocketAddr = "134.195.185.52:8333".parse()?; | ||
|
||
let mut stream = TcpStream::connect(address).await?; | ||
|
||
let _ = stream.write_all(VERSION_MESSAGE).await; | ||
stream.write_all(build_version_message(address).as_slice()).await?; | ||
println!("Version message sent"); | ||
println!("Waiting for response..."); | ||
read_version_message(&mut stream).await?; | ||
println!("Version message received"); | ||
|
||
let _ = stream.write_all(VERACK_MESSAGE).await; | ||
stream.write_all(VERACK_MESSAGE).await?; | ||
println!("Verack message sent"); | ||
println!("Waiting for response..."); | ||
read_verack_message(&mut stream).await?; | ||
println!("Verack message received"); | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn read_version_message(stream: &mut TcpStream) -> Result<(), Box<dyn std::error::Error>> { | ||
let mut magic = vec![0; 4]; | ||
stream.read_exact(&mut magic).await?; | ||
|
||
println!("{:?}", magic); | ||
fn build_version_message(address: SocketAddr) -> Vec<u8> { | ||
let mut payload: Vec<u8> = vec![ | ||
113, 17, 1, 0, // protocol version | ||
0, 0, 0, 0, 0, 0, 0, 0, // services | ||
0, 0, 0, 0, 0, 0, 0, 0, // time | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, // start of recipient address bytes | ||
]; | ||
|
||
let mut addr = socket_addr_to_vec(address); | ||
payload.append(&mut addr); | ||
payload.append(&mut vec![ | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, // sender address info | ||
0, 0, 0, 0, 0, 0, 0, 0, // Node ID, | ||
0, // "" sub-version string, 0 bytes long | ||
0, // relay | ||
0, 0, 0, 0, // last block sending node | ||
]); | ||
|
||
let mut header: Vec<u8> = vec![ | ||
// header | ||
249, 190, 180, 217, // magic | ||
118, 101, 114, 115, 105, 111, 110, 0, 0, 0, 0, 0, // "version" command | ||
]; | ||
|
||
// Add payload len | ||
header.extend_from_slice(&mut (payload.len() as u32).to_le_bytes()); | ||
|
||
// Add checksum | ||
let mut checksum = get_first_4_bytes_of_double_sha256(&payload); | ||
header.extend_from_slice(&mut checksum); | ||
header.extend(&payload); | ||
header | ||
} | ||
|
||
let mut cmd = vec![0; 12]; | ||
stream.read_exact(&mut cmd).await?; | ||
fn socket_addr_to_vec(socket_addr: SocketAddr) -> Vec<u8> { | ||
let ip = match socket_addr.ip() { | ||
IpAddr::V4(ip) => ip.octets().to_vec(), | ||
IpAddr::V6(ip) => ip.octets().to_vec(), | ||
}; | ||
|
||
println!("{:?}", cmd); | ||
let port = socket_addr.port(); | ||
let mut port_bytes = [0u8; 2]; | ||
port_bytes.copy_from_slice(&(port as u16).to_be_bytes()); | ||
|
||
let mut len = vec![0; 4]; | ||
stream.read_exact(&mut len).await?; | ||
[ip, port_bytes.to_vec()].concat() | ||
} | ||
|
||
println!("{:?}", len); | ||
async fn read_version_message(stream: &mut TcpStream) -> Result<(), Box<dyn std::error::Error>> { | ||
let mut header = vec![0; 24]; | ||
stream.read_exact(&mut header).await?; | ||
|
||
let mut checksum = vec![0; 4]; | ||
stream.read_exact(&mut checksum).await?; | ||
if "version" != std::str::from_utf8(&header[4..11])? { | ||
return Err("Unexpected command".into()); | ||
} | ||
|
||
println!("{:?}", checksum); | ||
let len = u32::from_le_bytes([header[16], header[17], header[18], header[19]]); | ||
|
||
let mut payload = vec![0; 102]; | ||
let mut payload = vec![0; len as usize]; | ||
stream.read_exact(&mut payload).await?; | ||
|
||
println!("{:?}", payload); | ||
let checksum = get_first_4_bytes_of_double_sha256(&payload); | ||
|
||
println!("Finished reading version"); | ||
Ok(()) | ||
if checksum == &header[20..24] { | ||
Ok(()) | ||
} else { | ||
Err("Invalid version message checksum".into()) | ||
} | ||
} | ||
|
||
async fn read_verack_message(stream: &mut TcpStream) -> Result<(), Box<dyn std::error::Error>> { | ||
let mut verack = vec![0; 24]; | ||
stream.read_exact(&mut verack).await.unwrap(); | ||
stream.read_exact(&mut verack).await?; | ||
|
||
if "verack" != std::str::from_utf8(&verack[4..10])? { | ||
return Err("Unexpected command".into()); | ||
} | ||
|
||
println!("{:?}", verack); | ||
if [93, 246, 224, 226] != &verack[20..24] { | ||
return Err("Invalid verack message checksum".into()); | ||
} | ||
|
||
println!("Finished reading verack"); | ||
Ok(()) | ||
} | ||
|
||
// fn build_version_message_vec(address: SocketAddr) -> Vec<u8> { | ||
// vec![ | ||
// // header | ||
// 249, 190, 180, 217, // magic | ||
// 118, 101, 114, 115, 105, 111, 110, 0, 0, 0, 0, 0, // "version" command | ||
// 86, 0, 0, 0, // payload len | ||
// 94, 38, 138, 233, // checksum | ||
|
||
// // payload | ||
// 113, 17, 1, 0, // protocol version | ||
// 0, 0, 0, 0, 0, 0, 0, 0, // services | ||
// 0, 0, 0, 0, 0, 0, 0, 0, // time | ||
// // 36, 99, 31, 100, 0, 0, 0, 0, // time | ||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 134, 195, 185, 52, 32, 141, // recipient address info | ||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, // sender address info | ||
// 0, 0, 0, 0, 0, 0, 0, 0, // Node ID, | ||
// // 131, 67, 161, 229, 100, 242, 249, 181, // Node ID, | ||
// 0, // "" sub-version string, 0 bytes long | ||
// 0, // relay | ||
// 0, 0, 0, 0, // last block sending node | ||
// ] | ||
// } | ||
|
||
// fn build_verack_message_vec() -> Vec<u8> { | ||
// vec![ | ||
// // header | ||
// 249, 190, 180, 217, // magic | ||
// 18, 101, 114, 97, 99, 107, 0, 0, 0, 0, 0, 0, | ||
// 0, 0, 0, 0, // payload len | ||
// 93, 246, 224, 226, // checksum | ||
// ] | ||
// } | ||
|
||
// 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 = constants::ServiceFlags::NONE; | ||
|
||
// // "standard UNIX timestamp in seconds" | ||
// // let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time error").as_secs(); | ||
// let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time error").as_secs(); | ||
|
||
// // "The network address of the node receiving this message" | ||
// let addr_recv = address::Address::new(&address, constants::ServiceFlags::NONE); | ||
|
||
// // "The network address of the node emitting this message" | ||
// let addr_from = address::Address::new(&my_address, constants::ServiceFlags::NONE); | ||
|
||
// // "Node random nonce, randomly generated every time a version packet is sent. This nonce is used to detect connections to self." | ||
// // let nonce: u64 = secp256k1::rand::thread_rng().gen(); | ||
// let nonce: u64 = secp256k1::rand::thread_rng().gen(); | ||
|
||
// // "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, | ||
// )) | ||
// } | ||
fn get_first_4_bytes_of_double_sha256(data: &[u8]) -> [u8; 4] { | ||
let mut hasher = Sha256::new(); | ||
hasher.update(data); | ||
let hash = hasher.finalize(); | ||
|
||
let mut hasher2 = Sha256::new(); | ||
hasher2.update(hash); | ||
let hash2 = hasher2.finalize(); | ||
|
||
[hash2[0], hash2[1], hash2[2], hash2[3]] | ||
} |