Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/1805 #2707

Merged
merged 135 commits into from
Nov 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
135 commits
Select commit Hold shift + click to select a range
0552a15
feat: add to_bitcoin_hash() method for BurnchainHeaderHash, which fli…
jcnelson Jun 14, 2021
5e45a94
refactoring: move reward cycle and block height converstion methods t…
jcnelson Jun 14, 2021
a25f1d0
fix: while testing, log the PoX bit vector and ancestor consensus has…
jcnelson Jun 14, 2021
411ab27
refactor: wrap PoxConstants methods for block height and reward cycle…
jcnelson Jun 14, 2021
0eb76b3
refactor: make write_block_headers() public
jcnelson Jun 14, 2021
7b6652c
feat: implement BurnchainHeaderReader trait for the BitcoinIndexer, s…
jcnelson Jun 14, 2021
8701eb7
feat: introduce the AffirmationMap data structure, which identifies a…
jcnelson Jun 14, 2021
3be408c
feat: expand the metadata we track for block-commit transactions to i…
jcnelson Jun 14, 2021
5d8b06b
feat: add a few more methods to the sortition DB to allow the chains …
jcnelson Jun 14, 2021
b1bfabd
refactoring: use ..BlockSnapshot::initial() to populate BlockSnapshot…
jcnelson Jun 14, 2021
365e10c
feat: make it so that previously-orphaned stacks block data can be fo…
jcnelson Jun 14, 2021
f5da764
feat: fix #1805 by implementing Nakamoto consensus on the history of …
jcnelson Jun 14, 2021
ae24b88
feat: add tests to cover the emergence of multiple anchor block histo…
jcnelson Jun 14, 2021
38c5039
feat: add unit_test_2_1() to StacksEpoch for instantiating a list of …
jcnelson Jun 14, 2021
f3f163d
refactor: synchronize burnchain API with main.rs
jcnelson Jun 14, 2021
f4c82f0
refactor: synchronize network tests with burnchain
jcnelson Jun 14, 2021
58eef6a
refactor: use a native sortition DB method for finding the parent sor…
jcnelson Jun 14, 2021
1ce9870
feat: add has_prefix() method to PoxId to see if a PoxId is a prefix …
jcnelson Jun 14, 2021
3a32889
feat: FromRow<bool> implementation
jcnelson Jun 14, 2021
186f1f7
refactor: synchronize Bitcoin sync logic in the Stacks node with the …
jcnelson Jun 14, 2021
64e20a7
refactor: sync neon integration tests with new burnchain API
jcnelson Jun 14, 2021
b104a74
Merge branch 'next' into fix/1805
jcnelson Jun 14, 2021
c77c3a6
fix: create the burnchain DB and its parent directory if they don't e…
jcnelson Jun 14, 2021
bfbf56e
fix: test coverage for forget_orphaned_epoch_data(); clarify behavior…
jcnelson Jun 15, 2021
0e2c6c8
fix: remove dead code, and comment on the behavior of affirmation map…
jcnelson Jun 18, 2021
bf8de60
fix: remove commented-out code, and document expected behavior for ha…
jcnelson Jun 18, 2021
cb47f44
fix: remove now-covered TODO
jcnelson Jun 18, 2021
993c124
fix: revert to original invalid block-processing code, since this new…
jcnelson Jul 6, 2021
5bc69e5
refactor/fix: put all burnchain tests into their own test directory, …
jcnelson Jul 6, 2021
3c8a9eb
refactor: implement get_burnchain_header() as a trait method for Burn…
jcnelson Jul 6, 2021
f7e52d9
refactor: Stacks epochs are comparable, so for changes that are meant…
jcnelson Jul 6, 2021
fb4d7f9
refactor: anchor block and anchor block descendant fields may be NULL
jcnelson Jul 7, 2021
1a6611e
refactor: helper method to convert Option<u64> into Option<i64> for d…
jcnelson Jul 7, 2021
a3718af
Merge branch 'next' into fix/1805
jcnelson Jul 7, 2021
3990b12
fix: use IS NULL instead of != NULL when appropriate -- don't just bl…
jcnelson Jul 7, 2021
ce59cce
fix: update test APIs from next merger
jcnelson Jul 7, 2021
9ff6f37
fix: cargo fmt update
jcnelson Jul 7, 2021
1a5db40
fix: tests: instantiate spv headers so unit tests continue to pass
jcnelson Jul 8, 2021
f80f240
cargo fmt
jcnelson Jul 8, 2021
bf3ca85
fix: more cargo fmt insanity
jcnelson Jul 8, 2021
9518d50
fix: more documentation
jcnelson Aug 19, 2021
711ab33
fix: more documentation
jcnelson Aug 19, 2021
ba937b7
fix: more test documentation
jcnelson Aug 19, 2021
458099b
refactor: remove dead code
jcnelson Aug 19, 2021
cd4d56d
fix: more documentation
jcnelson Aug 19, 2021
a4025e7
fix: remove dead documentation
jcnelson Aug 19, 2021
eb69fc9
Merge branch 'next' into fix/1805
jcnelson Aug 20, 2021
d325d01
fix: remove unused code paths (turn them into errors)
jcnelson Aug 20, 2021
2c7bbb7
fix: remove unused code
jcnelson Aug 20, 2021
05dc2a3
refactor: api sync
jcnelson Aug 20, 2021
cf20f1a
fix: add test coverage for getting, setting, and querying anchor bloc…
jcnelson Aug 20, 2021
066870c
feat: expose the means by which we create mocked SPV headers, so we c…
jcnelson Aug 23, 2021
79241f4
feat: optionally disable strict SPV header validation in testing -- n…
jcnelson Aug 23, 2021
d7972da
refactor: expose the means by which we process each reward cycle's af…
jcnelson Aug 23, 2021
0f0f5af
refactor: more debug output
jcnelson Aug 23, 2021
47a8e82
fix: when creating mocked sortitions, make it so the BlockSnapshot's …
jcnelson Aug 23, 2021
18f082b
fix: use the burnchain hash as the stubbed sortition ID when instanti…
jcnelson Aug 23, 2021
223fd43
refactor: debug the initial block the sortdb starts at
jcnelson Aug 23, 2021
78c64cd
fix: start all pox-based tests on the first bitcoin regtest block hash
jcnelson Aug 23, 2021
7dacc54
fix: start all pox tests on the first bitcoin regtest block
jcnelson Aug 23, 2021
3ae302c
fix: first regtest bitcoin block hash was wrong
jcnelson Aug 23, 2021
24a0216
fix: when generating block snapshots in network tests, use the SPV he…
jcnelson Aug 23, 2021
d6ebc65
fix: better debug log in expect() if there's a missing parent commit
jcnelson Aug 23, 2021
b083046
fix: make it so all SPV headers -- and by extension, all sortitions -…
jcnelson Aug 23, 2021
c26c90f
fix: calculate ibd status for the p2p state-machine when processing b…
jcnelson Aug 23, 2021
1716cdf
fix: remove now-unneeded test
jcnelson Aug 24, 2021
f94d0a8
fix: use expect() instead of unwrap() for panicking test failure
jcnelson Aug 24, 2021
0f058f6
fix: fix failing test due to changes in the way we handle mocked SPV …
jcnelson Aug 24, 2021
1e210dc
refactor: add way to directly query a test's directory
jcnelson Aug 24, 2021
362d126
fix: documentation -- we use burnchain header hashes in preambles
jcnelson Sep 30, 2021
bc5e2ac
Merge branch 'next' of https://github.com/blockstack/stacks-blockchai…
jcnelson Sep 30, 2021
e07afa4
Merge branch 'next' into fix/1805
jcnelson Sep 30, 2021
5abe1b1
refactor: put static_block_height_to_reward_cycle into PoxConstants w…
jcnelson Sep 30, 2021
4d81768
refactor: use the right static_block_height_to_reward_cycle
jcnelson Sep 30, 2021
895a753
refactor: remove compiler warning about ()
jcnelson Sep 30, 2021
7105b9a
fix: broken tests arising from not using the bitcoin regtest genesis …
jcnelson Oct 1, 2021
dd58e24
Merge branch 'chore/merge-develop-to-next' into fix/1805
jcnelson Apr 19, 2022
ba856ca
chore: cargo fmt
jcnelson Apr 19, 2022
b3f1e15
fix: add a .reader() trait method for BurnchainIndexer, which for the…
jcnelson Apr 19, 2022
c25b08e
fix: all block-commits in test framework have epoch marker for 2.1
jcnelson Apr 19, 2022
3ef4308
fix: use original unit_tests_2_05() function for generating mocked ep…
jcnelson Apr 19, 2022
333222c
chore: add epoch 2.1 boundary marker
jcnelson Apr 19, 2022
21cf7a8
Merge branch 'chore/merge-develop-to-next' into fix/1805
jcnelson Apr 19, 2022
d31dcc4
Merge branch 'chore/merge-develop-to-next' into fix/1805
jcnelson Apr 22, 2022
4832efe
Merge branch 'next' into fix/1805
jcnelson Apr 26, 2022
18e4e75
Merge branch 'next' into fix/1805
jcnelson Apr 29, 2022
5878313
chore: cargo fmt
jcnelson Apr 29, 2022
a122d38
Merge branch 'next' into fix/1805
jcnelson May 9, 2022
5f633af
Merge branch 'next' into fix/1805
jcnelson Jul 22, 2022
0cb8e4d
chore: cargo fmt
jcnelson Jul 22, 2022
c98ebb5
fix: tests need to use a genesis block hash for their first burnchain…
jcnelson Jul 24, 2022
2d78424
feat: make it so that the node operator can start using affirmation m…
jcnelson Jul 26, 2022
41602b3
feat: add [node].always_use_affirmation_maps (default false)
jcnelson Jul 26, 2022
2f256c8
chore: plumb through config.node.always_use_affirmation_maps to Chain…
jcnelson Jul 26, 2022
cc8714f
fix: add config field to test chainscoordinator instantiation
jcnelson Jul 26, 2022
f883aef
fix: retry burnchain block processing periodically if we're missing a…
jcnelson Jul 28, 2022
1e3408e
fix: explicitly set CARGO_MANIFEST_DIR in a bid to fix CI
jcnelson Jul 29, 2022
462dc63
feat: add a 100-block download test that enables a node to build up a…
jcnelson Oct 12, 2022
856da0b
fix: make it possible to make microblocks with an anchored block
jcnelson Oct 13, 2022
3a82813
fix: repair node download test so it produces chainstate that our dow…
jcnelson Oct 13, 2022
47c61f2
fix: update network test framework so we can mine with a missing PoX …
jcnelson Oct 13, 2022
28b14e9
chore: debug messages for bitcoind fork
jcnelson Oct 13, 2022
1813aba
Merge branch 'next' into fix/1805 and address PR feedback
jcnelson Oct 14, 2022
8a0e58d
chore: add affirmation map rustdocs and remove elided lifetime parame…
jcnelson Oct 14, 2022
afc5eaa
fix: add missing variable
jcnelson Oct 14, 2022
76b2c31
fix: consolidate static pox constant checks and have burnchain wrap them
jcnelson Oct 14, 2022
95e1ad7
fix: address PR feedback and remove merge artifact
jcnelson Oct 14, 2022
dd2163c
fix: use static_is_in_prepare_phase
jcnelson Oct 14, 2022
6131150
fix: use PoxAddress
jcnelson Oct 14, 2022
0443585
fix: address PR feedback
jcnelson Oct 14, 2022
12bc29e
fix: derive Clone for some structs that we need to be clonable
jcnelson Oct 14, 2022
1612728
fix: remove unneeded `mut`s
jcnelson Oct 14, 2022
7fa4ba2
fix: cargo fmt
jcnelson Oct 15, 2022
253de7c
fix: typo
jcnelson Oct 15, 2022
ebb3737
chore: cargo fmt
jcnelson Oct 15, 2022
4ed089e
fix: unit tests must use the regtest bitcoin genesis header hash, not…
jcnelson Oct 15, 2022
3c1a8f3
fix: correct nonce and rewards in bitcoind forking test
jcnelson Oct 16, 2022
14a10c8
Merge branch 'next' into fix/1805
jcnelson Oct 18, 2022
cced949
Merge branch 'next' into fix/1805
jcnelson Nov 7, 2022
1619fe9
docs: wordsmith some comments
jcnelson Nov 7, 2022
199d4c8
fix: failing unit tests brought on by the new way we instantiate burn…
jcnelson Nov 8, 2022
2bc1be4
Merge branch 'next' into fix/1805
jcnelson Nov 8, 2022
fd2819d
Merge branch 'next' into fix/1805
jcnelson Nov 8, 2022
0978eff
fix: set chains-coordinator thread stack size to the same as the mine…
jcnelson Nov 8, 2022
be0e3ff
Merge branch 'next' into fix/1805
jcnelson Nov 9, 2022
8f7983e
fix: multiple imports merge artifact
jcnelson Nov 9, 2022
f434ae6
Merge branch 'next' into fix/1805
jcnelson Nov 10, 2022
f4d10bc
refactor: put tests in the right place
jcnelson Nov 10, 2022
e887818
fix: use the right function name
jcnelson Nov 10, 2022
766627a
chore: API sync
jcnelson Nov 10, 2022
d9728bf
chore: API sync
jcnelson Nov 10, 2022
6752361
chore: choose consistent name for this function
jcnelson Nov 10, 2022
32d3799
fix: only instantiate indexes if we need to
jcnelson Nov 11, 2022
3b93a75
fix: new in 2.1: a reward cycle can be home to at most one anchor blo…
jcnelson Nov 11, 2022
69294d5
fix: burnchain regtest must now start with regtest header
jcnelson Nov 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,182 changes: 1,182 additions & 0 deletions src/burnchains/affirmation.rs

Large diffs are not rendered by default.

129 changes: 126 additions & 3 deletions src/burnchains/bitcoin/indexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,27 @@ use crate::burnchains::bitcoin::blocks::BitcoinHeaderIPC;
use crate::burnchains::bitcoin::messages::BitcoinMessageHandler;
use crate::burnchains::bitcoin::spv::*;
use crate::burnchains::bitcoin::Error as btc_error;
use crate::burnchains::db::BurnchainHeaderReader;
use crate::burnchains::indexer::BurnchainIndexer;
use crate::burnchains::indexer::*;
use crate::burnchains::Burnchain;
use crate::util_lib::db::Error as DBError;

use crate::burnchains::bitcoin::blocks::{BitcoinBlockDownloader, BitcoinBlockParser};
use crate::burnchains::bitcoin::BitcoinNetworkType;

use crate::burnchains::BurnchainBlockHeader;
use crate::burnchains::Error as burnchain_error;
use crate::burnchains::MagicBytes;
use crate::burnchains::BLOCKSTACK_MAGIC_MAINNET;
use crate::types::chainstate::BurnchainHeaderHash;

use stacks_common::deps_common::bitcoin::blockdata::block::LoneBlockHeader;
use stacks_common::deps_common::bitcoin::blockdata::block::{BlockHeader, LoneBlockHeader};
use stacks_common::deps_common::bitcoin::network::encodable::VarInt;
use stacks_common::deps_common::bitcoin::network::message::NetworkMessage;
use stacks_common::deps_common::bitcoin::network::serialize::BitcoinHash;
use stacks_common::deps_common::bitcoin::network::serialize::Error as btc_serialization_err;
use stacks_common::deps_common::bitcoin::util::hash::Sha256dHash;
use stacks_common::util::get_epoch_time_secs;
use stacks_common::util::log;

Expand All @@ -54,7 +59,7 @@ use crate::core::{
};
use std::convert::TryFrom;

pub const USER_AGENT: &'static str = "Stacks/2.0";
pub const USER_AGENT: &'static str = "Stacks/2.1";

pub const BITCOIN_MAINNET: u32 = 0xD9B4BEF9;
pub const BITCOIN_TESTNET: u32 = 0x0709110B;
Expand Down Expand Up @@ -154,6 +159,22 @@ impl BitcoinIndexerConfig {
}
}

pub fn default_regtest(spv_headers_path: String) -> BitcoinIndexerConfig {
BitcoinIndexerConfig {
peer_host: "127.0.0.1".to_string(),
peer_port: 18444,
rpc_port: 18443,
rpc_ssl: false,
username: Some("blockstack".to_string()),
password: Some("blockstacksystem".to_string()),
timeout: 30,
spv_headers_path: spv_headers_path,
first_block: 0,
magic_bytes: BLOCKSTACK_MAGIC_MAINNET.clone(),
epochs: None,
}
}

#[cfg(test)]
pub fn test_default(spv_headers_path: String) -> BitcoinIndexerConfig {
BitcoinIndexerConfig {
Expand Down Expand Up @@ -197,6 +218,34 @@ impl BitcoinIndexer {
}
}

#[cfg(test)]
pub fn new_unit_test(working_dir: &str) -> BitcoinIndexer {
let mut working_dir_path = PathBuf::from(working_dir);
if fs::metadata(&working_dir_path).is_err() {
fs::create_dir_all(&working_dir_path).unwrap();
}

working_dir_path.push("headers.sqlite");

// instantiate headers DB
let _ = SpvClient::new(
&working_dir_path.to_str().unwrap().to_string(),
0,
None,
BitcoinNetworkType::Regtest,
true,
false,
)
.unwrap();

BitcoinIndexer {
config: BitcoinIndexerConfig::default_regtest(
working_dir_path.to_str().unwrap().to_string(),
),
runtime: BitcoinIndexerRuntime::new(BitcoinNetworkType::Regtest),
}
}

pub fn dup(&self) -> BitcoinIndexer {
BitcoinIndexer {
config: self.config.clone(),
Expand Down Expand Up @@ -797,6 +846,47 @@ impl BitcoinIndexer {
Ok(new_tip)
}

#[cfg(test)]
pub fn raw_store_header(&mut self, header: BurnchainBlockHeader) -> Result<(), btc_error> {
let mut spv_client = SpvClient::new(
&self.config.spv_headers_path,
self.config.first_block,
None,
self.runtime.network_id,
true,
false,
)?;
spv_client.disable_check_txcount();

let hdr = LoneBlockHeader {
header: BitcoinIndexer::mock_bitcoin_header(
&header.parent_block_hash,
header.timestamp as u32,
),
tx_count: VarInt(header.num_txs),
};

assert!(header.block_height > 0);
let start_height = header.block_height - 1;
spv_client.insert_block_headers_after(start_height, vec![hdr])?;
Ok(())
}

#[cfg(test)]
pub fn mock_bitcoin_header(
parent_block_hash: &BurnchainHeaderHash,
timestamp: u32,
) -> BlockHeader {
BlockHeader {
bits: 0,
merkle_root: Sha256dHash([0u8; 32]),
nonce: 0,
prev_blockhash: parent_block_hash.to_bitcoin_hash(),
time: timestamp,
version: 0x20000000,
}
}

/// Verify that the last block header we have is within 2 hours of now.
/// Return burnchain_error::TrySyncAgain if not, and delete the offending header
pub fn check_chain_tip_timestamp(&mut self) -> Result<(), burnchain_error> {
Expand Down Expand Up @@ -843,7 +933,7 @@ impl BurnchainIndexer for BitcoinIndexer {

/// Connect to the Bitcoin peer network.
/// Use the peer host and peer port given in the config file,
/// and loaded in on setup. Don't call this before init().
/// and loaded in on setup.
fn connect(&mut self) -> Result<(), burnchain_error> {
self.reconnect_peer().map_err(burnchain_error::Bitcoin)
}
Expand Down Expand Up @@ -1042,6 +1132,39 @@ impl BurnchainIndexer for BitcoinIndexer {
fn parser(&self) -> BitcoinBlockParser {
BitcoinBlockParser::new(self.runtime.network_id, self.config.magic_bytes)
}

fn reader(&self) -> BitcoinIndexer {
self.dup()
}
}

impl BurnchainHeaderReader for BitcoinIndexer {
fn read_burnchain_headers(
&self,
start_height: u64,
end_height: u64,
) -> Result<Vec<BurnchainBlockHeader>, DBError> {
let hdrs = self
.read_headers(start_height, end_height)
.map_err(|e| DBError::Other(format!("Burnchain error: {:?}", &e)))?;
jcnelson marked this conversation as resolved.
Show resolved Hide resolved

Ok(hdrs
.into_iter()
.map(|hdr| BurnchainBlockHeader {
block_height: hdr.block_height,
block_hash: BurnchainHeaderHash::from_bitcoin_hash(&Sha256dHash(hdr.header_hash())),
parent_block_hash: BurnchainHeaderHash::from_bitcoin_hash(
&hdr.block_header.header.prev_blockhash,
),
num_txs: hdr.block_header.tx_count.0,
timestamp: hdr.block_header.header.time as u64,
})
.collect())
}
fn get_burnchain_headers_height(&self) -> Result<u64, DBError> {
jcnelson marked this conversation as resolved.
Show resolved Hide resolved
self.get_headers_height()
.map_err(|e| DBError::Other(format!("Burnchain error: {:?}", &e)))
}
}

#[cfg(test)]
Expand Down
62 changes: 44 additions & 18 deletions src/burnchains/bitcoin/spv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ use crate::burnchains::bitcoin::BitcoinNetworkType;
use crate::burnchains::bitcoin::Error as btc_error;
use crate::burnchains::bitcoin::PeerMessage;

use stacks_common::types::chainstate::BurnchainHeaderHash;

use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
use rusqlite::OptionalExtension;
use rusqlite::Row;
Expand All @@ -54,15 +56,15 @@ use stacks_common::util::log;

const BLOCK_HEADER_SIZE: u64 = 81;

const BITCOIN_GENESIS_BLOCK_HASH_MAINNET: &'static str =
pub const BITCOIN_GENESIS_BLOCK_HASH_MAINNET: &'static str =
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f";
const BITCOIN_GENESIS_BLOCK_MERKLE_ROOT_MAINNET: &'static str =
pub const BITCOIN_GENESIS_BLOCK_MERKLE_ROOT_MAINNET: &'static str =
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b";

const BITCOIN_GENESIS_BLOCK_HASH_TESTNET: &'static str =
pub const BITCOIN_GENESIS_BLOCK_HASH_TESTNET: &'static str =
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943";

const BITCOIN_GENESIS_BLOCK_HASH_REGTEST: &'static str =
pub const BITCOIN_GENESIS_BLOCK_HASH_REGTEST: &'static str =
"0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206";

pub const BLOCK_DIFFICULTY_CHUNK_SIZE: u64 = 2016;
Expand Down Expand Up @@ -105,6 +107,7 @@ pub struct SpvClient {
readwrite: bool,
reverse_order: bool,
headers_db: DBConn,
check_txcount: bool,
}

impl FromColumn<Sha256dHash> for Sha256dHash {
Expand Down Expand Up @@ -142,6 +145,7 @@ impl SpvClient {
readwrite: bool,
reverse_order: bool,
) -> Result<SpvClient, btc_error> {
let exists = fs::metadata(headers_path).is_ok();
let conn = SpvClient::db_open(headers_path, readwrite, true)?;
let mut client = SpvClient {
headers_path: headers_path.to_owned(),
Expand All @@ -152,9 +156,10 @@ impl SpvClient {
readwrite: readwrite,
reverse_order: reverse_order,
headers_db: conn,
check_txcount: true,
};

if readwrite {
if readwrite && !exists {
client.init_block_headers(true)?;
}

Expand All @@ -180,6 +185,7 @@ impl SpvClient {
readwrite: readwrite,
reverse_order: reverse_order,
headers_db: conn,
check_txcount: true,
};

if readwrite {
Expand All @@ -189,6 +195,11 @@ impl SpvClient {
Ok(client)
}

#[cfg(test)]
pub fn disable_check_txcount(&mut self) {
self.check_txcount = false;
}

pub fn conn(&self) -> &DBConn {
&self.headers_db
}
Expand Down Expand Up @@ -487,15 +498,21 @@ impl SpvClient {
fn validate_header_integrity(
start_height: u64,
headers: &Vec<LoneBlockHeader>,
check_txcount: bool,
) -> Result<(), btc_error> {
if headers.len() == 0 {
return Ok(());
}

for i in 0..headers.len() {
if headers[i].tx_count != VarInt(0) {
warn!("Non-zero tx count on header offset {}", i);
return Err(btc_error::InvalidReply);
if check_txcount {
for i in 0..headers.len() {
if headers[i].tx_count != VarInt(0) {
warn!(
"Non-zero tx count on header offset {}: {:?}",
i, &headers[i].tx_count
);
return Err(btc_error::InvalidReply);
}
}
}

Expand Down Expand Up @@ -694,6 +711,13 @@ impl SpvClient {
&header.nonce,
&u64_to_sql(height)?,
];

test_debug!(
"SPV: insert header {} {}: {:?}",
height,
&header.bitcoin_hash(),
&header
);
tx.execute(sql, args)
.map_err(|e| btc_error::DBError(db_error::SqliteError(e)))
.and_then(|_x| Ok(()))
Expand Down Expand Up @@ -833,7 +857,7 @@ impl SpvClient {

/// Write a run of continuous headers to a particular location.
/// Does _not_ check for continuity!
fn write_block_headers(
pub fn write_block_headers(
&mut self,
height: u64,
headers: Vec<LoneBlockHeader>,
Expand Down Expand Up @@ -886,10 +910,11 @@ impl SpvClient {
start_height
);

SpvClient::validate_header_integrity(start_height, &block_headers).map_err(|e| {
error!("Received invalid headers: {:?}", &e);
e
})?;
SpvClient::validate_header_integrity(start_height, &block_headers, self.check_txcount)
.map_err(|e| {
error!("Received invalid headers: {:?}", &e);
e
})?;

let parent_header = match self.read_block_header(start_height)? {
Some(header) => header,
Expand Down Expand Up @@ -939,10 +964,11 @@ impl SpvClient {
end_height
);

SpvClient::validate_header_integrity(start_height, &block_headers).map_err(|e| {
error!("Received invalid headers: {:?}", &e);
e
})?;
SpvClient::validate_header_integrity(start_height, &block_headers, self.check_txcount)
.map_err(|e| {
error!("Received invalid headers: {:?}", &e);
e
})?;

match self.read_block_header(end_height)? {
Some(child_header) => {
Expand Down
Loading