diff --git a/Cargo.lock b/Cargo.lock index 52ad076..b0a5118 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -261,9 +261,8 @@ dependencies = [ [[package]] name = "bitcoinkernel" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abae2a8861228d4013da2a9e9c5249aa01539d92eb146696d87e636d83f9a4e" +version = "0.1.1" +source = "git+https://github.com/TheCharlatan/rust-bitcoinkernel?rev=cf9bae320fcec68a4cff54d3547c529a011a4c96#cf9bae320fcec68a4cff54d3547c529a011a4c96" dependencies = [ "libbitcoinkernel-sys", ] @@ -716,9 +715,8 @@ dependencies = [ [[package]] name = "libbitcoinkernel-sys" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a39c92eeb8b730cf95f182609f9b845fe292ad88adb37f635198ce88dcea959b" +version = "0.1.1" +source = "git+https://github.com/TheCharlatan/rust-bitcoinkernel?rev=cf9bae320fcec68a4cff54d3547c529a011a4c96#cf9bae320fcec68a4cff54d3547c529a011a4c96" dependencies = [ "bindgen", "cc", diff --git a/Cargo.toml b/Cargo.toml index 4ff86b6..be7795c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,9 @@ version = "0.1.0" edition = "2021" [dependencies] -# bitcoinkernel = { path = "../rust-bitcoinkernel", version = "0.0.15" } -bitcoinkernel = "0.1" +bitcoinkernel = { git = "https://github.com/TheCharlatan/rust-bitcoinkernel", rev = "cf9bae320fcec68a4cff54d3547c529a011a4c96" } +# bitcoinkernel = { path = "../rust-bitcoinkernel" } +# bitcoinkernel = "0.1" addrman = { package = "bitcoin-address-book", git = "https://github.com/rustaceanrob/bitcoin-address-book", rev = "4417e4c8f5d04245947c758b73fb0dc9e7e0bd15" } bitcoin = { git = "https://github.com/rust-bitcoin/rust-bitcoin", default-features = false, rev = "16cc257c3695dea0e7301a5fa9cab44b8ed60598" } p2p = { package = "bitcoin-p2p", git = "https://github.com/2140-dev/bitcoin-p2p.git", rev = "322c4abb2a947f3f2d85991a0cb450249c68c1ea" } diff --git a/src/kernel_util.rs b/src/kernel_util.rs index 999e3e4..e815c56 100644 --- a/src/kernel_util.rs +++ b/src/kernel_util.rs @@ -49,6 +49,11 @@ pub fn bitcoin_block_to_kernel_block(block: &bitcoin::Block) -> bitcoin bitcoinkernel::Block::try_from(ser_block.as_slice()).unwrap() } +pub fn bitcoin_header_to_kernel_header(header: &bitcoin::BlockHeader) -> bitcoinkernel::BlockHeader { + let ser_header = encode::serialize(header); + bitcoinkernel::BlockHeader::try_from(ser_header.as_slice()).unwrap() +} + pub fn get_block_hash(index: BlockTreeEntry) -> bitcoin::BlockHash { bitcoin::BlockHash::from_byte_array(index.block_hash().to_bytes()) } diff --git a/src/peer.rs b/src/peer.rs index ddaf331..c66adcd 100644 --- a/src/peer.rs +++ b/src/peer.rs @@ -6,20 +6,17 @@ use std::{ }; use bitcoin::{BlockHash, Network}; -use bitcoinkernel::{ChainstateManager, Context}; -use log::{debug, info}; +use bitcoinkernel::{ChainstateManager, Context, core::BlockHashExt, prelude::BlockValidationStateExt}; +use log::{debug, info, warn}; use p2p::{ handshake::ConnectionConfig, net::{ConnectionExt, ConnectionReader, ConnectionWriter, TimeoutParams}, p2p_message_types::{ - message::{AddrV2Payload, InventoryPayload, NetworkMessage}, - message_blockdata::{GetBlocksMessage, Inventory}, - message_network::UserAgent, - Address, ProtocolVersion, ServiceFlags, + Address, ProtocolVersion, ServiceFlags, message::{AddrV2Payload, InventoryPayload, NetworkMessage}, message_blockdata::{GetBlocksMessage, GetHeadersMessage, Inventory}, message_network::UserAgent }, }; -use crate::kernel_util::bitcoin_block_to_kernel_block; +use crate::kernel_util::{bitcoin_block_to_kernel_block, bitcoin_header_to_kernel_header}; const PROTOCOL_VERSION: ProtocolVersion = ProtocolVersion::INVALID_CB_NO_BAN_VERSION; @@ -60,6 +57,7 @@ impl NodeState { /// /// [*] /// │ +/// AwaitingHeaders /// ▼ /// AwaitingInv /// ▲ | @@ -73,6 +71,7 @@ impl NodeState { #[derive(Default)] pub enum PeerStateMachine { #[default] + AwaitingHeaders, AwaitingInv, AwaitingBlock(AwaitingBlock), } @@ -82,6 +81,14 @@ pub struct AwaitingBlock { pub block_buffer: HashMap, } +fn create_getheaders_message(known_block_hash: bitcoin::BlockHash) -> NetworkMessage { + NetworkMessage::GetHeaders(GetHeadersMessage { + version: PROTOCOL_VERSION, + locator_hashes: vec![known_block_hash], + stop_hash: bitcoin::BlockHash::GENESIS_PREVIOUS_BLOCK_HASH, + }) +} + fn create_getblocks_message(known_block_hash: bitcoin::BlockHash) -> NetworkMessage { NetworkMessage::GetBlocks(GetBlocksMessage { version: PROTOCOL_VERSION, @@ -118,6 +125,31 @@ pub fn process_message( } match state_machine { + PeerStateMachine::AwaitingHeaders => match event { + NetworkMessage::Headers(headers) => { + info!("Received headers message!"); + for header in &headers.0 { + let (accepted, state) = node_state.chainman.process_header(&bitcoin_header_to_kernel_header(&header)); + if !accepted { + warn!("Rejected header {}: {:?}", header.block_hash(), state.result()); + break; + } + } + + if headers.0.len() != 2000 { + let tip_hash = node_state.get_tip_state().block_hash; + return (PeerStateMachine::AwaitingInv, vec![create_getblocks_message(tip_hash)]); + } + + let best_hash = BlockHash::from_byte_array(node_state.chainman.best_entry().unwrap().block_hash().to_bytes()); + info!("Progressed to best known hash: {} at height: {}", best_hash, node_state.chainman.best_entry().unwrap().height()); + (PeerStateMachine::AwaitingHeaders, vec![create_getheaders_message(best_hash)]) + } + message => { + debug!("Ignoring message: {:?}", message); + (PeerStateMachine::AwaitingHeaders, vec![]) + } + } PeerStateMachine::AwaitingInv => match event { NetworkMessage::Inv(inventory) => { debug!("Received inventory with {} items", inventory.0.len()); @@ -220,10 +252,10 @@ impl BitcoinPeer { let addr = Address::new(&socket_addr, ServiceFlags::WITNESS); info!("Connected to {:?}", addr); - let state_machine = PeerStateMachine::AwaitingInv; - let our_best = node_state.get_tip_state().block_hash; - let getblocks = create_getblocks_message(our_best); - writer.send_message(getblocks)?; + let state_machine = PeerStateMachine::AwaitingHeaders; + let best_hash = BlockHash::from_byte_array(node_state.chainman.best_entry().unwrap().block_hash().to_bytes()); + let getheaders = create_getheaders_message(best_hash); + writer.send_message(getheaders)?; let peer = BitcoinPeer { addr, writer: Arc::new(writer),