mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-05-24 16:19:50 +08:00
the check() method for operations returns a CheckResult enum now to encode specific kinds of errors (instead of a catch-all bool). Add tests for each check() method and make sure they all fail in the right way.
This commit is contained in:
@@ -21,6 +21,7 @@ use std::marker::PhantomData;
|
||||
|
||||
use chainstate::burn::operations::BlockstackOperation;
|
||||
use chainstate::burn::operations::Error as op_error;
|
||||
use chainstate::burn::operations::CheckResult;
|
||||
use chainstate::burn::{BlockHeaderHash, VRFSeed};
|
||||
|
||||
use chainstate::burn::db::DBConn;
|
||||
@@ -30,6 +31,7 @@ use burnchains::{BurnchainTransaction, BurnchainTxInput, PublicKey};
|
||||
use burnchains::Txid;
|
||||
use burnchains::Address;
|
||||
use burnchains::BurnchainHeaderHash;
|
||||
use burnchains::Burnchain;
|
||||
|
||||
use util::log;
|
||||
use util::hash::to_hex;
|
||||
@@ -179,11 +181,21 @@ where
|
||||
let data = parse_data_opt.unwrap();
|
||||
|
||||
// basic sanity checks
|
||||
if data.parent_block_backptr == 0 {
|
||||
warn!("Invalid tx: parent block back-pointer must be positive");
|
||||
return Err(op_error::ParseError);
|
||||
}
|
||||
|
||||
if data.parent_block_backptr as u64 >= block_height {
|
||||
warn!("Invalid tx: parent block back-pointer {} exceeds block height {}", data.parent_block_backptr, block_height);
|
||||
return Err(op_error::ParseError);
|
||||
}
|
||||
|
||||
if data.key_block_backptr == 0 {
|
||||
warn!("Invalid tx: key block back-pointer must be positive");
|
||||
return Err(op_error::ParseError);
|
||||
}
|
||||
|
||||
if data.key_block_backptr as u64 >= block_height {
|
||||
warn!("Invalid tx: key block back-pointer {} exceeds block height {}", data.key_block_backptr, block_height);
|
||||
return Err(op_error::ParseError);
|
||||
@@ -227,7 +239,7 @@ where
|
||||
LeaderBlockCommitOp::<A, K>::parse_from_tx(block_height, block_hash, tx)
|
||||
}
|
||||
|
||||
fn check(&self, conn: &DBConn) -> Result<bool, op_error> {
|
||||
fn check(&self, burnchain: &Burnchain, conn: &DBConn) -> Result<CheckResult, op_error> {
|
||||
let leader_key_block_height = self.block_number - (self.key_block_backptr as u64);
|
||||
let parent_block_height = self.block_number - (self.parent_block_backptr as u64);
|
||||
|
||||
@@ -240,47 +252,47 @@ where
|
||||
|
||||
if self.block_number < first_block_snapshot.block_height {
|
||||
warn!("Invalid block commit: predates genesis height {}", first_block_snapshot.block_height);
|
||||
return Ok(false);
|
||||
return Ok(CheckResult::BlockCommitPredatesGenesis);
|
||||
}
|
||||
|
||||
let target_epoch = self.block_number - first_block_snapshot.block_height;
|
||||
if (self.epoch_num as u64) != target_epoch {
|
||||
warn!("Invalid block commit: current epoch is {}; got {}", target_epoch, self.epoch_num);
|
||||
return Ok(false);
|
||||
return Ok(CheckResult::BlockCommitBadEpoch);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// There must exist a previously-accepted *unused* key from a LeaderKeyRegister
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
let register_key_opt = BurnDB::<A, K>::get_leader_key(conn, leader_key_block_height, self.key_vtxindex.into())
|
||||
let register_key_opt = BurnDB::<A, K>::get_leader_key_at(conn, leader_key_block_height, self.key_vtxindex.into())
|
||||
.map_err(op_error::DBError)?;
|
||||
|
||||
if register_key_opt.is_none() {
|
||||
warn!("Invalid block commit: no corresponding leader key");
|
||||
return Ok(false);
|
||||
return Ok(CheckResult::BlockCommitNoLeaderKey);
|
||||
}
|
||||
|
||||
let register_key = register_key_opt.unwrap();
|
||||
|
||||
let is_key_available = BurnDB::<A, K>::is_leader_key_available(conn, ®ister_key)
|
||||
let is_key_consumed = BurnDB::<A, K>::is_leader_key_consumed(conn, ®ister_key)
|
||||
.map_err(op_error::DBError)?;
|
||||
|
||||
if !is_key_available {
|
||||
warn!("Invalid block commit: leader key at {},{} is already used", register_key.block_number, register_key.vtxindex);
|
||||
return Ok(false);
|
||||
if is_key_consumed {
|
||||
warn!("Invalid block commit: leader key at ({},{}) is already used", register_key.block_number, register_key.vtxindex);
|
||||
return Ok(CheckResult::BlockCommitLeaderKeyAlreadyUsed);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// There must exist a previously-accepted block from a LeaderBlockCommit
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
let parent_block_opt = BurnDB::<A, K>::get_block_commit(conn, parent_block_height, self.parent_vtxindex.into())
|
||||
let parent_block_opt = BurnDB::<A, K>::get_block_commit_at(conn, parent_block_height, self.parent_vtxindex.into())
|
||||
.map_err(op_error::DBError)?;
|
||||
|
||||
if parent_block_opt.is_none() {
|
||||
warn!("Invalid block commit: no corresponding parent block");
|
||||
return Ok(false);
|
||||
return Ok(CheckResult::BlockCommitNoParent);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -299,12 +311,12 @@ where
|
||||
let addr_bytes = register_key.address.to_bytes();
|
||||
|
||||
if input_address_bytes != addr_bytes {
|
||||
warn!("Invalid block commit: leader key at {},{} has address bytes {}, but this tx input has address bytes {}",
|
||||
warn!("Invalid block commit: leader key at ({},{}) has address bytes {}, but this tx input has address bytes {}",
|
||||
register_key.block_number, register_key.vtxindex, &to_hex(&input_address_bytes[..]), &to_hex(&addr_bytes[..]));
|
||||
return Ok(false);
|
||||
return Ok(CheckResult::BlockCommitBadInput);
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
Ok(CheckResult::BlockCommitOk)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,22 +329,34 @@ mod tests {
|
||||
use burnchains::bitcoin::blocks::BitcoinBlockParser;
|
||||
use burnchains::Txid;
|
||||
use burnchains::BLOCKSTACK_MAGIC_MAINNET;
|
||||
use burnchains::burnchain::get_burn_quota_config;
|
||||
|
||||
use burnchains::bitcoin::BitcoinNetworkType;
|
||||
|
||||
use bitcoin::network::serialize::deserialize;
|
||||
use bitcoin::blockdata::transaction::Transaction;
|
||||
|
||||
use chainstate::burn::{BlockHeaderHash, VRFSeed};
|
||||
use chainstate::burn::{BlockHeaderHash, ConsensusHash, VRFSeed};
|
||||
use chainstate::burn::operations::leader_key_register::LeaderKeyRegisterOp;
|
||||
use chainstate::burn::operations::leader_key_register::OPCODE as LeaderKeyRegisterOpcode;
|
||||
|
||||
use ed25519_dalek::PublicKey as VRFPublicKey;
|
||||
|
||||
use util::hash::hex_bytes;
|
||||
use util::log;
|
||||
|
||||
use super::OPCODE as LeaderBlockCommitOpcode;
|
||||
|
||||
struct OpFixture {
|
||||
txstr: String,
|
||||
result: Option<LeaderBlockCommitOp<BitcoinAddress, BitcoinPublicKey>>
|
||||
}
|
||||
|
||||
struct CheckFixture {
|
||||
op: LeaderBlockCommitOp<BitcoinAddress, BitcoinPublicKey>,
|
||||
res: CheckResult
|
||||
}
|
||||
|
||||
fn make_tx(hex_str: &str) -> Result<Transaction, &'static str> {
|
||||
let tx_bin = hex_bytes(hex_str)?;
|
||||
let tx = deserialize(&tx_bin.to_vec())
|
||||
@@ -418,5 +442,318 @@ mod tests {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check() {
|
||||
let first_block_height = 120;
|
||||
let first_burn_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000123").unwrap();
|
||||
|
||||
let block_122_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000001220").unwrap();
|
||||
let block_123_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000001230").unwrap();
|
||||
let block_124_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000001240").unwrap();
|
||||
let block_125_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000001250").unwrap();
|
||||
|
||||
let burnchain = Burnchain {
|
||||
chain_name: "bitcoin".to_string(),
|
||||
network_name: "testnet".to_string(),
|
||||
working_dir: "/nope".to_string(),
|
||||
burn_quota: get_burn_quota_config(&"bitcoin".to_string()).unwrap(),
|
||||
consensus_hash_lifetime: 24
|
||||
};
|
||||
|
||||
let mut db : BurnDB<BitcoinAddress, BitcoinPublicKey> = BurnDB::connect_memory(first_block_height, &first_burn_hash).unwrap();
|
||||
|
||||
let leader_key_1 : LeaderKeyRegisterOp<BitcoinAddress, BitcoinPublicKey> = LeaderKeyRegisterOp {
|
||||
consensus_hash: ConsensusHash::from_bytes(&hex_bytes("2222222222222222222222222222222222222222").unwrap()).unwrap(),
|
||||
public_key: VRFPublicKey::from_bytes(&hex_bytes("a366b51292bef4edd64063d9145c617fec373bceb0758e98cd72becd84d54c7a").unwrap()).unwrap(),
|
||||
memo: vec![01, 02, 03, 04, 05],
|
||||
address: BitcoinAddress::from_scriptpubkey(BitcoinNetworkType::Testnet, &hex_bytes("76a914306231b2782b5f80d944bf69f9d46a1453a0a0eb88ac").unwrap()).unwrap(),
|
||||
|
||||
op: LeaderKeyRegisterOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("1bfa831b5fc56c858198acb8e77e5863c1e9d8ac26d49ddb914e24d8d4083562").unwrap()).unwrap(),
|
||||
vtxindex: 456,
|
||||
block_number: 123,
|
||||
burn_header_hash: block_123_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
};
|
||||
|
||||
let leader_key_2 : LeaderKeyRegisterOp<BitcoinAddress, BitcoinPublicKey> = LeaderKeyRegisterOp {
|
||||
consensus_hash: ConsensusHash::from_bytes(&hex_bytes("3333333333333333333333333333333333333333").unwrap()).unwrap(),
|
||||
public_key: VRFPublicKey::from_bytes(&hex_bytes("bb519494643f79f1dea0350e6fb9a1da88dfdb6137117fc2523824a8aa44fe1c").unwrap()).unwrap(),
|
||||
memo: vec![01, 02, 03, 04, 05],
|
||||
address: BitcoinAddress::from_scriptpubkey(BitcoinNetworkType::Testnet, &hex_bytes("76a914306231b2782b5f80d944bf69f9d46a1453a0a0eb88ac").unwrap()).unwrap(),
|
||||
|
||||
op: LeaderKeyRegisterOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("9410df84e2b440055c33acb075a0687752df63fe8fe84aeec61abe469f0448c7").unwrap()).unwrap(),
|
||||
vtxindex: 457,
|
||||
block_number: 122,
|
||||
burn_header_hash: block_122_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
};
|
||||
|
||||
let block_commit_1 : LeaderBlockCommitOp<BitcoinAddress, BitcoinPublicKey> = LeaderBlockCommitOp {
|
||||
block_header_hash: BlockHeaderHash::from_bytes(&hex_bytes("2222222222222222222222222222222222222222222222222222222222222222").unwrap()).unwrap(),
|
||||
new_seed: VRFSeed::from_bytes(&hex_bytes("3333333333333333333333333333333333333333333333333333333333333333").unwrap()).unwrap(),
|
||||
parent_block_backptr: 1,
|
||||
parent_vtxindex: 1,
|
||||
key_block_backptr: 1,
|
||||
key_vtxindex: 456,
|
||||
epoch_num: 50,
|
||||
memo: vec![0x80],
|
||||
|
||||
burn_fee: 12345,
|
||||
input: BurnchainTxInput {
|
||||
keys: vec![
|
||||
BitcoinPublicKey::from_hex("02d8015134d9db8178ac93acbc43170a2f20febba5087a5b0437058765ad5133d0").unwrap(),
|
||||
],
|
||||
num_required: 1,
|
||||
in_type: BurnchainInputType::BitcoinInput,
|
||||
},
|
||||
|
||||
op: LeaderBlockCommitOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("3c07a0a93360bc85047bbaadd49e30c8af770f73a37e10fec400174d2e5f27cf").unwrap()).unwrap(),
|
||||
vtxindex: 444,
|
||||
block_number: 124,
|
||||
burn_header_hash: block_124_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
};
|
||||
|
||||
{
|
||||
let mut tx = db.tx_begin().unwrap();
|
||||
BurnDB::<BitcoinAddress, BitcoinPublicKey>::insert_leader_key(&mut tx, &leader_key_1);
|
||||
BurnDB::<BitcoinAddress, BitcoinPublicKey>::insert_leader_key(&mut tx, &leader_key_2);
|
||||
BurnDB::<BitcoinAddress, BitcoinPublicKey>::insert_block_commit(&mut tx, &block_commit_1);
|
||||
tx.commit().unwrap();
|
||||
}
|
||||
|
||||
let block_height = 124;
|
||||
|
||||
let fixtures = vec![
|
||||
CheckFixture {
|
||||
// reject -- predates start block
|
||||
op: LeaderBlockCommitOp {
|
||||
block_header_hash: BlockHeaderHash::from_bytes(&hex_bytes("2222222222222222222222222222222222222222222222222222222222222222").unwrap()).unwrap(),
|
||||
new_seed: VRFSeed::from_bytes(&hex_bytes("3333333333333333333333333333333333333333333333333333333333333333").unwrap()).unwrap(),
|
||||
parent_block_backptr: 50,
|
||||
parent_vtxindex: 456,
|
||||
key_block_backptr: 1,
|
||||
key_vtxindex: 456,
|
||||
epoch_num: 50,
|
||||
memo: vec![0x80],
|
||||
|
||||
burn_fee: 12345,
|
||||
input: BurnchainTxInput {
|
||||
keys: vec![
|
||||
BitcoinPublicKey::from_hex("02d8015134d9db8178ac93acbc43170a2f20febba5087a5b0437058765ad5133d0").unwrap(),
|
||||
],
|
||||
num_required: 1,
|
||||
in_type: BurnchainInputType::BitcoinInput,
|
||||
},
|
||||
|
||||
op: LeaderBlockCommitOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("3c07a0a93360bc85047bbaadd49e30c8af770f73a37e10fec400174d2e5f27cf").unwrap()).unwrap(),
|
||||
vtxindex: 444,
|
||||
block_number: 80,
|
||||
burn_header_hash: block_124_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
},
|
||||
res: CheckResult::BlockCommitPredatesGenesis,
|
||||
},
|
||||
CheckFixture {
|
||||
// reject -- epoch does not match block height
|
||||
op: LeaderBlockCommitOp {
|
||||
block_header_hash: BlockHeaderHash::from_bytes(&hex_bytes("2222222222222222222222222222222222222222222222222222222222222222").unwrap()).unwrap(),
|
||||
new_seed: VRFSeed::from_bytes(&hex_bytes("3333333333333333333333333333333333333333333333333333333333333333").unwrap()).unwrap(),
|
||||
parent_block_backptr: 50,
|
||||
parent_vtxindex: 456,
|
||||
key_block_backptr: 1,
|
||||
key_vtxindex: 456,
|
||||
epoch_num: 50,
|
||||
memo: vec![0x80],
|
||||
|
||||
burn_fee: 12345,
|
||||
input: BurnchainTxInput {
|
||||
keys: vec![
|
||||
BitcoinPublicKey::from_hex("02d8015134d9db8178ac93acbc43170a2f20febba5087a5b0437058765ad5133d0").unwrap(),
|
||||
],
|
||||
num_required: 1,
|
||||
in_type: BurnchainInputType::BitcoinInput,
|
||||
},
|
||||
|
||||
op: LeaderBlockCommitOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("3c07a0a93360bc85047bbaadd49e30c8af770f73a37e10fec400174d2e5f27cf").unwrap()).unwrap(),
|
||||
vtxindex: 444,
|
||||
block_number: 124,
|
||||
burn_header_hash: block_124_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
},
|
||||
res: CheckResult::BlockCommitBadEpoch,
|
||||
},
|
||||
CheckFixture {
|
||||
// reject -- no such leader key
|
||||
op: LeaderBlockCommitOp {
|
||||
block_header_hash: BlockHeaderHash::from_bytes(&hex_bytes("2222222222222222222222222222222222222222222222222222222222222222").unwrap()).unwrap(),
|
||||
new_seed: VRFSeed::from_bytes(&hex_bytes("3333333333333333333333333333333333333333333333333333333333333333").unwrap()).unwrap(),
|
||||
parent_block_backptr: 50,
|
||||
parent_vtxindex: 456,
|
||||
key_block_backptr: 2,
|
||||
key_vtxindex: 456,
|
||||
epoch_num: (124 - first_block_height) as u32,
|
||||
memo: vec![0x80],
|
||||
|
||||
burn_fee: 12345,
|
||||
input: BurnchainTxInput {
|
||||
keys: vec![
|
||||
BitcoinPublicKey::from_hex("02d8015134d9db8178ac93acbc43170a2f20febba5087a5b0437058765ad5133d0").unwrap(),
|
||||
],
|
||||
num_required: 1,
|
||||
in_type: BurnchainInputType::BitcoinInput,
|
||||
},
|
||||
|
||||
op: LeaderBlockCommitOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("3c07a0a93360bc85047bbaadd49e30c8af770f73a37e10fec400174d2e5f27cf").unwrap()).unwrap(),
|
||||
vtxindex: 444,
|
||||
block_number: 124,
|
||||
burn_header_hash: block_124_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
},
|
||||
res: CheckResult::BlockCommitNoLeaderKey,
|
||||
},
|
||||
CheckFixture {
|
||||
// reject -- leader key consumed
|
||||
op: LeaderBlockCommitOp {
|
||||
block_header_hash: BlockHeaderHash::from_bytes(&hex_bytes("2222222222222222222222222222222222222222222222222222222222222222").unwrap()).unwrap(),
|
||||
new_seed: VRFSeed::from_bytes(&hex_bytes("3333333333333333333333333333333333333333333333333333333333333333").unwrap()).unwrap(),
|
||||
parent_block_backptr: 50,
|
||||
parent_vtxindex: 456,
|
||||
key_block_backptr: 1,
|
||||
key_vtxindex: 456,
|
||||
epoch_num: (124 - first_block_height) as u32,
|
||||
memo: vec![0x80],
|
||||
|
||||
burn_fee: 12345,
|
||||
input: BurnchainTxInput {
|
||||
keys: vec![
|
||||
BitcoinPublicKey::from_hex("02d8015134d9db8178ac93acbc43170a2f20febba5087a5b0437058765ad5133d0").unwrap(),
|
||||
],
|
||||
num_required: 1,
|
||||
in_type: BurnchainInputType::BitcoinInput,
|
||||
},
|
||||
|
||||
op: LeaderBlockCommitOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("3c07a0a93360bc85047bbaadd49e30c8af770f73a37e10fec400174d2e5f27cf").unwrap()).unwrap(),
|
||||
vtxindex: 445,
|
||||
block_number: 124,
|
||||
burn_header_hash: block_124_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
},
|
||||
res: CheckResult::BlockCommitLeaderKeyAlreadyUsed,
|
||||
},
|
||||
CheckFixture {
|
||||
// reject -- previous block must exist
|
||||
op: LeaderBlockCommitOp {
|
||||
block_header_hash: BlockHeaderHash::from_bytes(&hex_bytes("2222222222222222222222222222222222222222222222222222222222222222").unwrap()).unwrap(),
|
||||
new_seed: VRFSeed::from_bytes(&hex_bytes("3333333333333333333333333333333333333333333333333333333333333333").unwrap()).unwrap(),
|
||||
parent_block_backptr: 50,
|
||||
parent_vtxindex: 456,
|
||||
key_block_backptr: 2,
|
||||
key_vtxindex: 457,
|
||||
epoch_num: (124 - first_block_height) as u32,
|
||||
memo: vec![0x80],
|
||||
|
||||
burn_fee: 12345,
|
||||
input: BurnchainTxInput {
|
||||
keys: vec![
|
||||
BitcoinPublicKey::from_hex("02d8015134d9db8178ac93acbc43170a2f20febba5087a5b0437058765ad5133d0").unwrap(),
|
||||
],
|
||||
num_required: 1,
|
||||
in_type: BurnchainInputType::BitcoinInput,
|
||||
},
|
||||
|
||||
op: LeaderBlockCommitOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("3c07a0a93360bc85047bbaadd49e30c8af770f73a37e10fec400174d2e5f27cf").unwrap()).unwrap(),
|
||||
vtxindex: 445,
|
||||
block_number: 124,
|
||||
burn_header_hash: block_124_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
},
|
||||
res: CheckResult::BlockCommitNoParent,
|
||||
},
|
||||
CheckFixture {
|
||||
// reject -- bad tx input
|
||||
op: LeaderBlockCommitOp {
|
||||
block_header_hash: BlockHeaderHash::from_bytes(&hex_bytes("2222222222222222222222222222222222222222222222222222222222222222").unwrap()).unwrap(),
|
||||
new_seed: VRFSeed::from_bytes(&hex_bytes("3333333333333333333333333333333333333333333333333333333333333333").unwrap()).unwrap(),
|
||||
parent_block_backptr: 1,
|
||||
parent_vtxindex: 444,
|
||||
key_block_backptr: 3,
|
||||
key_vtxindex: 457,
|
||||
epoch_num: (125 - first_block_height) as u32,
|
||||
memo: vec![0x80],
|
||||
|
||||
burn_fee: 12345,
|
||||
input: BurnchainTxInput {
|
||||
keys: vec![
|
||||
BitcoinPublicKey::from_hex("02b3a05c80babc78e1566ebd41d43ff10030a3e19a9cc660e5c0e18b5b392a1d16").unwrap(),
|
||||
],
|
||||
num_required: 1,
|
||||
in_type: BurnchainInputType::BitcoinInput,
|
||||
},
|
||||
|
||||
op: LeaderBlockCommitOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("3c07a0a93360bc85047bbaadd49e30c8af770f73a37e10fec400174d2e5f27cf").unwrap()).unwrap(),
|
||||
vtxindex: 445,
|
||||
block_number: 125,
|
||||
burn_header_hash: block_125_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
},
|
||||
res: CheckResult::BlockCommitBadInput
|
||||
},
|
||||
CheckFixture {
|
||||
// accept
|
||||
op: LeaderBlockCommitOp {
|
||||
block_header_hash: BlockHeaderHash::from_bytes(&hex_bytes("2222222222222222222222222222222222222222222222222222222222222222").unwrap()).unwrap(),
|
||||
new_seed: VRFSeed::from_bytes(&hex_bytes("3333333333333333333333333333333333333333333333333333333333333333").unwrap()).unwrap(),
|
||||
parent_block_backptr: 1,
|
||||
parent_vtxindex: 444,
|
||||
key_block_backptr: 3,
|
||||
key_vtxindex: 457,
|
||||
epoch_num: (125 - first_block_height) as u32,
|
||||
memo: vec![0x80],
|
||||
|
||||
burn_fee: 12345,
|
||||
input: BurnchainTxInput {
|
||||
keys: vec![
|
||||
BitcoinPublicKey::from_hex("02d8015134d9db8178ac93acbc43170a2f20febba5087a5b0437058765ad5133d0").unwrap(),
|
||||
],
|
||||
num_required: 1,
|
||||
in_type: BurnchainInputType::BitcoinInput,
|
||||
},
|
||||
|
||||
op: LeaderBlockCommitOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("3c07a0a93360bc85047bbaadd49e30c8af770f73a37e10fec400174d2e5f27cf").unwrap()).unwrap(),
|
||||
vtxindex: 445,
|
||||
block_number: 125,
|
||||
burn_header_hash: block_125_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
},
|
||||
res: CheckResult::BlockCommitOk
|
||||
}
|
||||
];
|
||||
|
||||
for fixture in fixtures {
|
||||
assert_eq!(fixture.res, fixture.op.check(&burnchain, &db.conn()).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ use std::marker::PhantomData;
|
||||
|
||||
use chainstate::burn::operations::BlockstackOperation;
|
||||
use chainstate::burn::operations::Error as op_error;
|
||||
use chainstate::burn::operations::CheckResult;
|
||||
use chainstate::burn::ConsensusHash;
|
||||
|
||||
use chainstate::burn::db::burndb::BurnDB;
|
||||
@@ -31,6 +32,7 @@ use burnchains::Txid;
|
||||
use burnchains::Address;
|
||||
use burnchains::PublicKey;
|
||||
use burnchains::BurnchainHeaderHash;
|
||||
use burnchains::Burnchain;
|
||||
|
||||
use util::vrf::{ECVRF_check_public_key, ECVRF_public_key_to_hex};
|
||||
|
||||
@@ -161,7 +163,7 @@ where
|
||||
LeaderKeyRegisterOp::<A, K>::parse_from_tx(block_height, block_hash, tx)
|
||||
}
|
||||
|
||||
fn check(&self, conn: &DBConn) -> Result<bool, op_error> {
|
||||
fn check(&self, burnchain: &Burnchain, conn: &DBConn) -> Result<CheckResult, op_error> {
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Keys must be unique -- no one can register the same key twice
|
||||
/////////////////////////////////////////////////////////////////
|
||||
@@ -172,22 +174,22 @@ where
|
||||
|
||||
if has_key_already {
|
||||
warn!("Invalid leader key registration: public key {} previously used", ECVRF_public_key_to_hex(&self.public_key));
|
||||
return Ok(false);
|
||||
return Ok(CheckResult::LeaderKeyAlreadyRegistered);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Consensus hash must be recent and valid
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
let consensus_hash_recent = BurnDB::<A, K>::is_fresh_consensus_hash(conn, self.block_number, &self.consensus_hash)
|
||||
let consensus_hash_recent = BurnDB::<A, K>::is_fresh_consensus_hash(conn, self.block_number, burnchain.consensus_hash_lifetime, &self.consensus_hash)
|
||||
.map_err(op_error::DBError)?;
|
||||
|
||||
if !consensus_hash_recent {
|
||||
warn!("Invalid consensus hash {}", &self.consensus_hash.to_hex());
|
||||
return Ok(false);
|
||||
warn!("Invalid leader key registration: invalid consensus hash {}", &self.consensus_hash.to_hex());
|
||||
return Ok(CheckResult::LeaderKeyBadConsensusHash);
|
||||
}
|
||||
|
||||
return Ok(true);
|
||||
return Ok(CheckResult::LeaderKeyOk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,20 +202,29 @@ mod tests {
|
||||
use burnchains::bitcoin::BitcoinNetworkType;
|
||||
use burnchains::Txid;
|
||||
use burnchains::BLOCKSTACK_MAGIC_MAINNET;
|
||||
use burnchains::burnchain::get_burn_quota_config;
|
||||
|
||||
use bitcoin::network::serialize::deserialize;
|
||||
use bitcoin::blockdata::transaction::Transaction;
|
||||
|
||||
use chainstate::burn::ConsensusHash;
|
||||
use chainstate::burn::{ConsensusHash, OpsHash, SortitionHash, BlockSnapshot};
|
||||
use chainstate::burn::operations::CheckResult;
|
||||
|
||||
use util::hash::hex_bytes;
|
||||
use util::log;
|
||||
|
||||
use super::OPCODE as LeaderKeyRegisterOpcode;
|
||||
|
||||
struct OpFixture {
|
||||
txstr: String,
|
||||
result: Option<LeaderKeyRegisterOp<BitcoinAddress, BitcoinPublicKey>>
|
||||
}
|
||||
|
||||
struct CheckFixture {
|
||||
op: LeaderKeyRegisterOp<BitcoinAddress, BitcoinPublicKey>,
|
||||
res: CheckResult
|
||||
}
|
||||
|
||||
fn make_tx(hex_str: &str) -> Result<Transaction, &'static str> {
|
||||
let tx_bin = hex_bytes(hex_str)?;
|
||||
let tx = deserialize(&tx_bin.to_vec())
|
||||
@@ -307,5 +318,132 @@ mod tests {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check() {
|
||||
|
||||
let first_block_height = 120;
|
||||
let first_burn_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000123").unwrap();
|
||||
|
||||
let block_122_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000002").unwrap();
|
||||
let block_123_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000003").unwrap();
|
||||
let block_124_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000004").unwrap();
|
||||
let block_125_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000005").unwrap();
|
||||
|
||||
let burnchain = Burnchain {
|
||||
chain_name: "bitcoin".to_string(),
|
||||
network_name: "testnet".to_string(),
|
||||
working_dir: "/nope".to_string(),
|
||||
burn_quota: get_burn_quota_config(&"bitcoin".to_string()).unwrap(),
|
||||
consensus_hash_lifetime: 24
|
||||
};
|
||||
|
||||
let mut db : BurnDB<BitcoinAddress, BitcoinPublicKey> = BurnDB::connect_memory(first_block_height, &first_burn_hash).unwrap();
|
||||
|
||||
let leader_key_1 : LeaderKeyRegisterOp<BitcoinAddress, BitcoinPublicKey> = LeaderKeyRegisterOp {
|
||||
consensus_hash: ConsensusHash::from_bytes(&hex_bytes("0000000000000000000000000000000000000000").unwrap()).unwrap(),
|
||||
public_key: VRFPublicKey::from_bytes(&hex_bytes("a366b51292bef4edd64063d9145c617fec373bceb0758e98cd72becd84d54c7a").unwrap()).unwrap(),
|
||||
memo: vec![01, 02, 03, 04, 05],
|
||||
address: BitcoinAddress::from_scriptpubkey(BitcoinNetworkType::Testnet, &hex_bytes("76a9140be3e286a15ea85882761618e366586b5574100d88ac").unwrap()).unwrap(),
|
||||
|
||||
op: LeaderKeyRegisterOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("1bfa831b5fc56c858198acb8e77e5863c1e9d8ac26d49ddb914e24d8d4083562").unwrap()).unwrap(),
|
||||
vtxindex: 456,
|
||||
block_number: 123,
|
||||
burn_header_hash: block_123_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
};
|
||||
|
||||
// populate consensus hashes
|
||||
{
|
||||
let mut tx = db.tx_begin().unwrap();
|
||||
for i in 0..10 {
|
||||
let snapshot_row = BlockSnapshot {
|
||||
block_height: i + first_block_height,
|
||||
burn_header_hash: BurnchainHeaderHash::from_bytes(&[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,i as u8]).unwrap(),
|
||||
consensus_hash: ConsensusHash::from_bytes(&[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,i as u8]).unwrap(),
|
||||
ops_hash: OpsHash::from_bytes(&[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,i as u8]).unwrap(),
|
||||
total_burn: i,
|
||||
burn_quota: 0,
|
||||
sortition: true,
|
||||
sortition_hash: SortitionHash::initial(),
|
||||
winning_block_txid: Txid::from_hex("0000000000000000000000000000000000000000000000000000000000000000").unwrap(),
|
||||
winning_block_burn_hash: BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000000").unwrap(),
|
||||
canonical: true
|
||||
};
|
||||
BurnDB::<BitcoinAddress, BitcoinPublicKey>::insert_block_snapshot(&mut tx, &snapshot_row).unwrap();
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
}
|
||||
|
||||
{
|
||||
let mut tx = db.tx_begin().unwrap();
|
||||
BurnDB::<BitcoinAddress, BitcoinPublicKey>::insert_leader_key(&mut tx, &leader_key_1).unwrap();
|
||||
tx.commit().unwrap();
|
||||
}
|
||||
|
||||
let check_fixtures = vec![
|
||||
CheckFixture {
|
||||
// reject -- key already registered
|
||||
op: LeaderKeyRegisterOp {
|
||||
consensus_hash: ConsensusHash::from_bytes(&hex_bytes("0000000000000000000000000000000000000000").unwrap()).unwrap(),
|
||||
public_key: VRFPublicKey::from_bytes(&hex_bytes("a366b51292bef4edd64063d9145c617fec373bceb0758e98cd72becd84d54c7a").unwrap()).unwrap(),
|
||||
memo: vec![01, 02, 03, 04, 05],
|
||||
address: BitcoinAddress::from_scriptpubkey(BitcoinNetworkType::Testnet, &hex_bytes("76a9140be3e286a15ea85882761618e366586b5574100d88ac").unwrap()).unwrap(),
|
||||
|
||||
op: LeaderKeyRegisterOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("1bfa831b5fc56c858198acb8e77e5863c1e9d8ac26d49ddb914e24d8d4083562").unwrap()).unwrap(),
|
||||
vtxindex: 455,
|
||||
block_number: 122,
|
||||
burn_header_hash: block_123_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
},
|
||||
res: CheckResult::LeaderKeyAlreadyRegistered
|
||||
},
|
||||
CheckFixture {
|
||||
// reject -- invalid consensus hash
|
||||
op: LeaderKeyRegisterOp {
|
||||
consensus_hash: ConsensusHash::from_bytes(&hex_bytes("1000000000000000000000000000000000000000").unwrap()).unwrap(),
|
||||
public_key: VRFPublicKey::from_bytes(&hex_bytes("bb519494643f79f1dea0350e6fb9a1da88dfdb6137117fc2523824a8aa44fe1c").unwrap()).unwrap(),
|
||||
memo: vec![01, 02, 03, 04, 05],
|
||||
address: BitcoinAddress::from_scriptpubkey(BitcoinNetworkType::Testnet, &hex_bytes("76a9140be3e286a15ea85882761618e366586b5574100d88ac").unwrap()).unwrap(),
|
||||
|
||||
op: LeaderKeyRegisterOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("1bfa831b5fc56c858198acb8e77e5863c1e9d8ac26d49ddb914e24d8d4083562").unwrap()).unwrap(),
|
||||
vtxindex: 456,
|
||||
block_number: 123,
|
||||
burn_header_hash: block_123_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
},
|
||||
res: CheckResult::LeaderKeyBadConsensusHash,
|
||||
},
|
||||
CheckFixture {
|
||||
// accept
|
||||
op: LeaderKeyRegisterOp {
|
||||
consensus_hash: ConsensusHash::from_bytes(&hex_bytes("0000000000000000000000000000000000000000").unwrap()).unwrap(),
|
||||
public_key: VRFPublicKey::from_bytes(&hex_bytes("bb519494643f79f1dea0350e6fb9a1da88dfdb6137117fc2523824a8aa44fe1c").unwrap()).unwrap(),
|
||||
memo: vec![01, 02, 03, 04, 05],
|
||||
address: BitcoinAddress::from_scriptpubkey(BitcoinNetworkType::Testnet, &hex_bytes("76a9140be3e286a15ea85882761618e366586b5574100d88ac").unwrap()).unwrap(),
|
||||
|
||||
op: LeaderKeyRegisterOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("1bfa831b5fc56c858198acb8e77e5863c1e9d8ac26d49ddb914e24d8d4083562").unwrap()).unwrap(),
|
||||
vtxindex: 456,
|
||||
block_number: 123,
|
||||
burn_header_hash: block_123_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
},
|
||||
res: CheckResult::LeaderKeyOk
|
||||
}
|
||||
];
|
||||
|
||||
for fixture in check_fixtures {
|
||||
assert_eq!(fixture.res, fixture.op.check(&burnchain, db.conn()).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ use chainstate::burn::db::Error as db_error;
|
||||
use chainstate::burn::db::DBConn;
|
||||
|
||||
use burnchains::{Address, PublicKey, BurnchainHeaderHash, BurnchainTransaction};
|
||||
use burnchains::Burnchain;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
@@ -73,17 +74,58 @@ impl error::Error for Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum CheckResult {
|
||||
BlockCommitOk,
|
||||
BlockCommitPredatesGenesis,
|
||||
BlockCommitBadEpoch,
|
||||
BlockCommitNoLeaderKey,
|
||||
BlockCommitLeaderKeyAlreadyUsed,
|
||||
BlockCommitNoParent,
|
||||
BlockCommitBadInput,
|
||||
|
||||
LeaderKeyOk,
|
||||
LeaderKeyAlreadyRegistered,
|
||||
LeaderKeyBadConsensusHash,
|
||||
|
||||
UserBurnSupportOk,
|
||||
UserBurnSupportBadConsensusHash,
|
||||
UserBurnSupportNoLeaderKey,
|
||||
}
|
||||
|
||||
impl fmt::Display for CheckResult {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
CheckResult::BlockCommitOk => f.write_str("Block commit OK"),
|
||||
CheckResult::BlockCommitPredatesGenesis => f.write_str("Block commit predates genesis block"),
|
||||
CheckResult::BlockCommitBadEpoch => f.write_str("Block commit has a bad epoch value"),
|
||||
CheckResult::BlockCommitNoLeaderKey => f.write_str("Block commit has no matching register key"),
|
||||
CheckResult::BlockCommitLeaderKeyAlreadyUsed => f.write_str("Block commit register key already used"),
|
||||
CheckResult::BlockCommitNoParent => f.write_str("Block commit parent does not exist"),
|
||||
CheckResult::BlockCommitBadInput => f.write_str("Block commit tx input does not match register key tx output"),
|
||||
|
||||
CheckResult::LeaderKeyOk => f.write_str("Leader key OK"),
|
||||
CheckResult::LeaderKeyAlreadyRegistered => f.write_str("Leader key has already been registered"),
|
||||
CheckResult::LeaderKeyBadConsensusHash => f.write_str("Leader key has an invalid consensus hash"),
|
||||
|
||||
CheckResult::UserBurnSupportOk => f.write_str("User burn support OK"),
|
||||
CheckResult::UserBurnSupportBadConsensusHash => f.write_str("User burn support has an invalid consensus hash"),
|
||||
CheckResult::UserBurnSupportNoLeaderKey => f.write_str("User burn support does not match a registered leader key"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BlockstackOperation<A, K>
|
||||
where
|
||||
A: Address,
|
||||
K: PublicKey
|
||||
{
|
||||
fn check(&self, conn: &DBConn) -> Result<bool, Error>;
|
||||
fn check(&self, burnchain: &Burnchain, conn: &DBConn) -> Result<CheckResult, Error>;
|
||||
fn from_tx(block_height: u64, block_hash: &BurnchainHeaderHash, tx: &BurnchainTransaction<A, K>) -> Result<Self, Error>
|
||||
where Self: Sized;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum BlockstackOperationType<A, K>
|
||||
where
|
||||
A: Address,
|
||||
|
||||
@@ -20,6 +20,7 @@ use std::marker::PhantomData;
|
||||
|
||||
use chainstate::burn::operations::BlockstackOperation;
|
||||
use chainstate::burn::operations::Error as op_error;
|
||||
use chainstate::burn::operations::CheckResult;
|
||||
use chainstate::burn::ConsensusHash;
|
||||
|
||||
use chainstate::burn::db::DBConn;
|
||||
@@ -30,6 +31,7 @@ use burnchains::Txid;
|
||||
use burnchains::Address;
|
||||
use burnchains::PublicKey;
|
||||
use burnchains::BurnchainHeaderHash;
|
||||
use burnchains::Burnchain;
|
||||
|
||||
use util::hash::Hash160;
|
||||
use util::vrf::{ECVRF_check_public_key, ECVRF_public_key_to_hex};
|
||||
@@ -168,11 +170,23 @@ where
|
||||
UserBurnSupportOp::<A, K>::parse_from_tx(block_height, block_hash, tx)
|
||||
}
|
||||
|
||||
fn check(&self, conn: &DBConn) -> Result<bool, op_error> {
|
||||
fn check(&self, burnchain: &Burnchain, conn: &DBConn) -> Result<CheckResult, op_error> {
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Consensus hash must be recent and valid
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
let consensus_hash_recent = BurnDB::<A, K>::is_fresh_consensus_hash(conn, self.block_number, burnchain.consensus_hash_lifetime, &self.consensus_hash)
|
||||
.map_err(op_error::DBError)?;
|
||||
|
||||
if !consensus_hash_recent {
|
||||
warn!("Invalid user burn: invalid consensus hash {}", &self.consensus_hash.to_hex());
|
||||
return Ok(CheckResult::UserBurnSupportBadConsensusHash);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// There must exist a previously-accepted LeaderKeyRegisterOp. It may already be
|
||||
// consumed by a LeaderBlockCommitOp by the time this transaction is processed,
|
||||
// so we only check for the key's existence.
|
||||
// There must exist a previously-accepted LeaderKeyRegisterOp that matches this
|
||||
// user support burn's VRF public key.
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
let register_key_opt = BurnDB::<A, K>::get_leader_key_by_VRF_key(conn, &self.public_key)
|
||||
@@ -180,10 +194,17 @@ where
|
||||
|
||||
if register_key_opt.is_none() {
|
||||
warn!("Invalid user burn: no such leader VRF key {}", &ECVRF_public_key_to_hex(&self.public_key));
|
||||
return Ok(false);
|
||||
return Ok(CheckResult::UserBurnSupportNoLeaderKey);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// The block hash can't be checked here -- the corresponding LeaderBlockCommitOp may
|
||||
// not have been checked yet, so we don't know yet if it exists. The sortition
|
||||
// algorithm will carry out this check, and only consider user burns if they match
|
||||
// a block commit and the commit's corresponding leader key.
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Ok(true)
|
||||
Ok(CheckResult::UserBurnSupportOk)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,20 +218,32 @@ mod tests {
|
||||
|
||||
use burnchains::bitcoin::keys::BitcoinPublicKey;
|
||||
use burnchains::bitcoin::address::BitcoinAddress;
|
||||
use burnchains::burnchain::get_burn_quota_config;
|
||||
|
||||
use chainstate::burn::operations::leader_key_register::LeaderKeyRegisterOp;
|
||||
use chainstate::burn::operations::leader_key_register::OPCODE as LeaderKeyRegisterOpcode;
|
||||
|
||||
use chainstate::burn::{ConsensusHash, OpsHash, SortitionHash, BlockSnapshot};
|
||||
use chainstate::burn::operations::CheckResult;
|
||||
|
||||
use bitcoin::network::serialize::deserialize;
|
||||
use bitcoin::blockdata::transaction::Transaction;
|
||||
|
||||
use chainstate::burn::ConsensusHash;
|
||||
|
||||
use util::hash::{hex_bytes, Hash160};
|
||||
use util::log;
|
||||
|
||||
use super::OPCODE as UserBurnSupportOpcode;
|
||||
|
||||
struct OpFixture {
|
||||
txstr: String,
|
||||
result: Option<UserBurnSupportOp<BitcoinAddress, BitcoinPublicKey>>
|
||||
}
|
||||
|
||||
struct CheckFixture {
|
||||
op: UserBurnSupportOp<BitcoinAddress, BitcoinPublicKey>,
|
||||
res: CheckResult
|
||||
}
|
||||
|
||||
fn make_tx(hex_str: &str) -> Result<Transaction, &'static str> {
|
||||
let tx_bin = hex_bytes(hex_str)?;
|
||||
let tx = deserialize(&tx_bin.to_vec())
|
||||
@@ -289,5 +322,137 @@ mod tests {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check() {
|
||||
let first_block_height = 120;
|
||||
let first_burn_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000123").unwrap();
|
||||
|
||||
let block_122_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000002").unwrap();
|
||||
let block_123_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000003").unwrap();
|
||||
let block_124_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000004").unwrap();
|
||||
let block_125_hash = BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000005").unwrap();
|
||||
|
||||
let burnchain = Burnchain {
|
||||
chain_name: "bitcoin".to_string(),
|
||||
network_name: "testnet".to_string(),
|
||||
working_dir: "/nope".to_string(),
|
||||
burn_quota: get_burn_quota_config(&"bitcoin".to_string()).unwrap(),
|
||||
consensus_hash_lifetime: 24
|
||||
};
|
||||
|
||||
let mut db : BurnDB<BitcoinAddress, BitcoinPublicKey> = BurnDB::connect_memory(first_block_height, &first_burn_hash).unwrap();
|
||||
|
||||
let leader_key_1 : LeaderKeyRegisterOp<BitcoinAddress, BitcoinPublicKey> = LeaderKeyRegisterOp {
|
||||
consensus_hash: ConsensusHash::from_bytes(&hex_bytes("0000000000000000000000000000000000000000").unwrap()).unwrap(),
|
||||
public_key: VRFPublicKey::from_bytes(&hex_bytes("a366b51292bef4edd64063d9145c617fec373bceb0758e98cd72becd84d54c7a").unwrap()).unwrap(),
|
||||
memo: vec![01, 02, 03, 04, 05],
|
||||
address: BitcoinAddress::from_scriptpubkey(BitcoinNetworkType::Testnet, &hex_bytes("76a9140be3e286a15ea85882761618e366586b5574100d88ac").unwrap()).unwrap(),
|
||||
|
||||
op: LeaderKeyRegisterOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("1bfa831b5fc56c858198acb8e77e5863c1e9d8ac26d49ddb914e24d8d4083562").unwrap()).unwrap(),
|
||||
vtxindex: 456,
|
||||
block_number: 123,
|
||||
burn_header_hash: block_123_hash.clone(),
|
||||
|
||||
_phantom: PhantomData
|
||||
};
|
||||
|
||||
// populate consensus hashes
|
||||
{
|
||||
let mut tx = db.tx_begin().unwrap();
|
||||
for i in 0..10 {
|
||||
let snapshot_row = BlockSnapshot {
|
||||
block_height: i + first_block_height,
|
||||
burn_header_hash: BurnchainHeaderHash::from_bytes(&[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,i as u8]).unwrap(),
|
||||
consensus_hash: ConsensusHash::from_bytes(&[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,i as u8]).unwrap(),
|
||||
ops_hash: OpsHash::from_bytes(&[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,i as u8]).unwrap(),
|
||||
total_burn: i,
|
||||
burn_quota: 0,
|
||||
sortition: true,
|
||||
sortition_hash: SortitionHash::initial(),
|
||||
winning_block_txid: Txid::from_hex("0000000000000000000000000000000000000000000000000000000000000000").unwrap(),
|
||||
winning_block_burn_hash: BurnchainHeaderHash::from_hex("0000000000000000000000000000000000000000000000000000000000000000").unwrap(),
|
||||
canonical: true
|
||||
};
|
||||
BurnDB::<BitcoinAddress, BitcoinPublicKey>::insert_block_snapshot(&mut tx, &snapshot_row).unwrap();
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
}
|
||||
|
||||
{
|
||||
let mut tx = db.tx_begin().unwrap();
|
||||
BurnDB::<BitcoinAddress, BitcoinPublicKey>::insert_leader_key(&mut tx, &leader_key_1).unwrap();
|
||||
tx.commit().unwrap();
|
||||
}
|
||||
|
||||
let check_fixtures = vec![
|
||||
CheckFixture {
|
||||
// reject -- bad consensus hash
|
||||
op: UserBurnSupportOp {
|
||||
consensus_hash: ConsensusHash::from_bytes(&hex_bytes("1000000000000000000000000000000000000000").unwrap()).unwrap(),
|
||||
public_key: VRFPublicKey::from_bytes(&hex_bytes("a366b51292bef4edd64063d9145c617fec373bceb0758e98cd72becd84d54c7a").unwrap()).unwrap(),
|
||||
block_header_hash_160: Hash160::from_bytes(&hex_bytes("7150f635054b87df566a970b21e07030d6444bf2").unwrap()).unwrap(), // 22222....2222
|
||||
memo: vec![0x01, 0x02, 0x03, 0x04, 0x05],
|
||||
burn_fee: 10000,
|
||||
|
||||
op: UserBurnSupportOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("1d5cbdd276495b07f0e0bf0181fa57c175b217bc35531b078d62fc20986c716b").unwrap()).unwrap(),
|
||||
vtxindex: 13,
|
||||
block_number: 124,
|
||||
burn_header_hash: block_124_hash.clone(),
|
||||
|
||||
_phantom_a: PhantomData,
|
||||
_phantom_k: PhantomData
|
||||
},
|
||||
res: CheckResult::UserBurnSupportBadConsensusHash,
|
||||
},
|
||||
CheckFixture {
|
||||
// reject -- no leader key
|
||||
op: UserBurnSupportOp {
|
||||
consensus_hash: ConsensusHash::from_bytes(&hex_bytes("0000000000000000000000000000000000000000").unwrap()).unwrap(),
|
||||
public_key: VRFPublicKey::from_bytes(&hex_bytes("bb519494643f79f1dea0350e6fb9a1da88dfdb6137117fc2523824a8aa44fe1c").unwrap()).unwrap(),
|
||||
block_header_hash_160: Hash160::from_bytes(&hex_bytes("7150f635054b87df566a970b21e07030d6444bf2").unwrap()).unwrap(), // 22222....2222
|
||||
memo: vec![0x01, 0x02, 0x03, 0x04, 0x05],
|
||||
burn_fee: 10000,
|
||||
|
||||
op: UserBurnSupportOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("1d5cbdd276495b07f0e0bf0181fa57c175b217bc35531b078d62fc20986c716b").unwrap()).unwrap(),
|
||||
vtxindex: 13,
|
||||
block_number: 124,
|
||||
burn_header_hash: block_124_hash.clone(),
|
||||
|
||||
_phantom_a: PhantomData,
|
||||
_phantom_k: PhantomData
|
||||
},
|
||||
res: CheckResult::UserBurnSupportNoLeaderKey,
|
||||
},
|
||||
CheckFixture {
|
||||
// accept
|
||||
op: UserBurnSupportOp {
|
||||
consensus_hash: ConsensusHash::from_bytes(&hex_bytes("0000000000000000000000000000000000000000").unwrap()).unwrap(),
|
||||
public_key: VRFPublicKey::from_bytes(&hex_bytes("a366b51292bef4edd64063d9145c617fec373bceb0758e98cd72becd84d54c7a").unwrap()).unwrap(),
|
||||
block_header_hash_160: Hash160::from_bytes(&hex_bytes("7150f635054b87df566a970b21e07030d6444bf2").unwrap()).unwrap(), // 22222....2222
|
||||
memo: vec![0x01, 0x02, 0x03, 0x04, 0x05],
|
||||
burn_fee: 10000,
|
||||
|
||||
op: UserBurnSupportOpcode,
|
||||
txid: Txid::from_bytes_be(&hex_bytes("1d5cbdd276495b07f0e0bf0181fa57c175b217bc35531b078d62fc20986c716b").unwrap()).unwrap(),
|
||||
vtxindex: 13,
|
||||
block_number: 124,
|
||||
burn_header_hash: block_124_hash.clone(),
|
||||
|
||||
_phantom_a: PhantomData,
|
||||
_phantom_k: PhantomData
|
||||
},
|
||||
res: CheckResult::UserBurnSupportOk,
|
||||
}
|
||||
];
|
||||
|
||||
for fixture in check_fixtures {
|
||||
assert_eq!(fixture.res, fixture.op.check(&burnchain, db.conn()).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user