From 6808a04abea10565721199234bacc76a45d8b404 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Fri, 24 Jul 2020 21:47:01 -0700 Subject: [PATCH] Remove unmaintained btc programs --- Cargo.lock | 25 -- Cargo.toml | 2 - programs/btc_spv/Cargo.toml | 26 -- programs/btc_spv/README.md | 64 ---- programs/btc_spv/src/header_store.rs | 102 ------ programs/btc_spv/src/lib.rs | 18 - programs/btc_spv/src/spv_instruction.rs | 78 ---- programs/btc_spv/src/spv_processor.rs | 187 ---------- programs/btc_spv/src/spv_state.rs | 457 ------------------------ programs/btc_spv/src/testblock.in | Bin 9195 -> 0 bytes programs/btc_spv/src/utils.rs | 126 ------- programs/btc_spv_bin/Cargo.toml | 27 -- programs/btc_spv_bin/src/block.rs | 48 --- programs/btc_spv_bin/src/blockheade.rs | 74 ---- 14 files changed, 1234 deletions(-) delete mode 100644 programs/btc_spv/Cargo.toml delete mode 100644 programs/btc_spv/README.md delete mode 100644 programs/btc_spv/src/header_store.rs delete mode 100644 programs/btc_spv/src/lib.rs delete mode 100644 programs/btc_spv/src/spv_instruction.rs delete mode 100644 programs/btc_spv/src/spv_processor.rs delete mode 100644 programs/btc_spv/src/spv_state.rs delete mode 100644 programs/btc_spv/src/testblock.in delete mode 100644 programs/btc_spv/src/utils.rs delete mode 100644 programs/btc_spv_bin/Cargo.toml delete mode 100644 programs/btc_spv_bin/src/block.rs delete mode 100644 programs/btc_spv_bin/src/blockheade.rs diff --git a/Cargo.lock b/Cargo.lock index 143be1cfcd..4fa629e601 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,17 +250,6 @@ dependencies = [ "serde", ] -[[package]] -name = "btc_spv_bin" -version = "1.3.0" -dependencies = [ - "clap", - "hex", - "reqwest", - "serde", - "serde_derive", -] - [[package]] name = "bumpalo" version = "3.3.0" @@ -3067,20 +3056,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "solana-btc-spv-program" -version = "1.3.0" -dependencies = [ - "bincode", - "hex", - "log 0.4.8", - "num-derive 0.3.0", - "num-traits", - "serde", - "serde_derive", - "solana-sdk 1.3.0", -] - [[package]] name = "solana-budget-program" version = "1.3.0" diff --git a/Cargo.toml b/Cargo.toml index ae7b44a138..65825f9b61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,8 +34,6 @@ members = [ "poh-bench", "programs/bpf_loader", "programs/budget", - "programs/btc_spv", - "programs/btc_spv_bin", "programs/config", "programs/exchange", "programs/failure", diff --git a/programs/btc_spv/Cargo.toml b/programs/btc_spv/Cargo.toml deleted file mode 100644 index c88e47f71e..0000000000 --- a/programs/btc_spv/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "solana-btc-spv-program" -version = "1.3.0" -description = "Solana Bitcoin spv parsing program" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2018" - -[dependencies] -bincode = "1.3.1" -log = "0.4.2" -num-derive = "0.3" -num-traits = "0.2" -serde = "1.0.112" -serde_derive = "1.0.103" -solana-sdk = { path = "../../sdk", version = "1.3.0"} -hex = "0.4.2" - -[lib] -crate-type = ["lib", "cdylib"] -name = "solana_btc_spv_program" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/programs/btc_spv/README.md b/programs/btc_spv/README.md deleted file mode 100644 index 7ff6f7fb89..0000000000 --- a/programs/btc_spv/README.md +++ /dev/null @@ -1,64 +0,0 @@ -## Problem - -Inter-chain applications are not new to the digital asset ecosystem; in fact, even -the smaller centralized exchanges still categorically dwarf all single chain applications -put together in terms of users and volume. They command massive valuations and -have spent years effectively optimizing their core products for a broad range of -end users. However, their basic operations center around mechanisms that require -their users to unilaterally trust them, typically with little to no recourse -or protection from accidental loss. This has led to the broader digital asset -ecosystem being fractured along network lines because interoperability solutions typically: - * Are technically complex to fully implement - * Create unstable network scale incentive structures - * Require consistent and high level cooperation between stakeholders - - -## Proposed Solution - -Simple Payment Verification (SPV) is a generic term for a range of different -methodologies used by light clients on most major blockchain networks to verify -aspects of the network state without the burden of fully storing and maintaining -the chain itself. In most cases, this means relying on a form of hash tree to -supply a proof of the presence of a given transaction in a certain block by -comparing against a root hash in that block’s header or equivalent. This allows -a light client or wallet to reach a probabilistic level of certainty about -on-chain events by itself with a minimum of trust required with regard to network nodes. - -Traditionally the process of assembling and validating these proofs is carried -out off chain by nodes, wallets, or other clients, but it also offers a potential -mechanism for inter-chain state verification. However, by moving the capability -to validate SPV proofs on-chain as a smart contract while leveraging the archival -properties inherent to the blockchain, it is possible to construct a system for -programmatically detecting and verifying transactions on other networks without -the involvement of any type of trusted oracle or complex multi-stage consensus -mechanism. This concept is broadly generalisable to any network with an SPV -mechanism and can even be operated bilaterally on other smart contract platforms, -opening up the possibility of cheap, fast, inter-chain transfer of value without -relying on collateral, hashlocks, or trusted intermediaries. - -Opting to take advantage of well established and developmentally stable mechanisms -already common to all major blockchains allows SPV based interoperability solutions -to be dramatically simpler than orchestrated multi-stage approaches. As part of -this, they dispense with the need for widely agreed upon cross chain communication -standards and the large multi-party organizations that write them in favor of a -set of discrete contract-based services that can be easily utilized by caller -contracts through a common abstraction format. This will set the groundwork for -a broad range of applications and contracts able to interoperate across the variegated -and every growing platform ecosystem. - -## Terminology - -SPV Program - Client-facing interface for the inter-chain SPV system, manages participant roles. -SPV Engine - Validates transaction proofs, subset of the SPV Program. -Client - The caller to the SPV Program, typically another solana contract. -Prover - Party who generates proofs for transactions and submits them to the SPV Program. -Transaction Proof - Created by Provers, contains a merkle proof, transaction, and blockheader reference. -Merkle Proof - Basic SPV proof that validates the presence of a transaction in a certain block. -Block Header - Represents the basic parameters and relative position of a given block. -Proof Request - An order placed by a client for verification of transaction(s) by provers. -Header Store - A data structure for storing and referencing ranges of block headers in proofs. -Client Request - Transaction from the client to the SPV Program to trigger creation of a Proof Request. -Sub-account - A Solana account owned by another contract account, without its own private key. - -For more information on the Inter-chain SPV system, see the docs section at: -https://docs.solana.com/proposals/interchain-transaction-verification diff --git a/programs/btc_spv/src/header_store.rs b/programs/btc_spv/src/header_store.rs deleted file mode 100644 index 3bdb588197..0000000000 --- a/programs/btc_spv/src/header_store.rs +++ /dev/null @@ -1,102 +0,0 @@ -#[allow(unused_imports)] -use crate::spv_state::*; -use serde_derive::{Deserialize, Serialize}; -use solana_sdk::pubkey::Pubkey; - -// HeaderStore is a data structure that allows linked list style cheap appends and -// sequential reads, but also has a "lookup index" to speed up random access -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum HeaderStoreError { - InvalidHeader, - GroupExists, - GroupDNE, - InvalidBlockHeight, -} - -// AccountList is a linked list of groups of blockheaders. It stores sequential blockheaders -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct HeaderStore { - pub index: Vec, - // number of header entries to include per group account - pub group_size: u16, - // base_height is the height of the first header in the first headerAccount - pub base_height: u32, - // top_height is the running last header loaded - pub top_height: u32, - // account that administrates the headerstore and benefits from fees accrued - pub owner: Pubkey, -} - -impl HeaderStore { - pub fn get_group(self, block_height: u32) -> Result { - if block_height < self.base_height || block_height > self.top_height { - Err(HeaderStoreError::InvalidBlockHeight) - } else { - let gheight = (block_height - self.base_height) / u32::from(self.group_size); - let grouppk: Pubkey = self.index[gheight as usize]; - Ok(grouppk) - } - } - - pub fn top_group(self) -> Result { - if self.index.is_empty() { - Err(HeaderStoreError::GroupDNE) - } else { - let grouppk: Pubkey = *self.index.last().unwrap(); - Ok(grouppk) - } - } - - pub fn append_header(mut self, blockheader: &BlockHeader) -> Result<(), HeaderStoreError> { - match self.top_group() { - Ok(n) => { - let group = n; - Ok(()) - } - Err(e) => { - // HeaderStore is empty need to create first group - if HeaderStoreError::GroupDNE == e { - Ok(()) - } else { - Err(e) - } - //reinsert - } - } - } - - pub fn replace_header( - mut self, - blockheader: &BlockHeader, - block_height: u32, - ) -> Result<(), HeaderStoreError> { - match self.get_group(block_height) { - Err(e) => Err(HeaderStoreError::InvalidHeader), - Ok(n) => { - let group = n; - Ok(()) - } - } - //reinsert - } - - pub fn append_group(mut self, pubkey: Pubkey) -> Result<(), HeaderStoreError> { - if self.index.contains(&pubkey) { - // group to be appended is already in the index - Err(HeaderStoreError::GroupExists) - } else { - Ok(()) - //reinsert - } - } -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct HeaderAccountInfo { - // parent stores the pubkey of the parent AccountList - pub parent: Pubkey, - // stores a vec of BlockHeader structs - pub headers: Vec, - // next DataAccount in the chain or none if last - pub next: Option, -} diff --git a/programs/btc_spv/src/lib.rs b/programs/btc_spv/src/lib.rs deleted file mode 100644 index 4d344c5f52..0000000000 --- a/programs/btc_spv/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![allow(unused_imports)] -#![allow(unused_variables)] -#![allow(unused_mut)] -#![allow(dead_code)] -// This version is a work in progress and contains placeholders and incomplete components -pub mod header_store; -pub mod spv_instruction; -pub mod spv_processor; -pub mod spv_state; -pub mod utils; - -use crate::spv_processor::process_instruction; - -solana_sdk::declare_program!( - "BtcSpv1111111111111111111111111111111111111", - solana_btc_spv_program, - process_instruction -); diff --git a/programs/btc_spv/src/spv_instruction.rs b/programs/btc_spv/src/spv_instruction.rs deleted file mode 100644 index 5fe91e600b..0000000000 --- a/programs/btc_spv/src/spv_instruction.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Spv proof Verification Program -use crate::id; -use crate::spv_state::*; -use serde_derive::{Deserialize, Serialize}; -use solana_sdk::instruction::{AccountMeta, Instruction}; -use solana_sdk::pubkey::Pubkey; - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub enum SpvInstruction { - // Client Places request for a matching proof - // key 0 - Signer - // key 1 - Account in which to record the Request and proof - ClientRequest(ClientRequestInfo), - - // Used by clients to cancel a pending proof request - // key 0 - signer - // key 1 - Request to cancel - CancelRequest, - - // used to submit a proof matching a posted BitcoinTxHash or for own benefit - // key 0 - signer - // key 1 - Request to prove - SubmitProof(Proof), -} - -pub fn client_request( - owner: &Pubkey, - txhash: BitcoinTxHash, - fee: u64, - confirmations: u8, - difficulty: u64, - expiration: Option, -) -> Instruction { - let account_meta = vec![AccountMeta::new(*owner, true)]; - Instruction::new( - id(), - &SpvInstruction::ClientRequest(ClientRequestInfo { - txhash, - confirmations, - fee, - difficulty, - expiration, - }), - account_meta, - ) -} - -pub fn cancel_request(owner: &Pubkey, request: &Pubkey) -> Instruction { - let account_meta = vec![ - AccountMeta::new(*owner, true), - AccountMeta::new(*request, false), - ]; - Instruction::new(id(), &SpvInstruction::CancelRequest, account_meta) -} - -pub fn submit_proof( - submitter: &Pubkey, - proof: MerkleProof, - headers: HeaderChain, - transaction: BitcoinTransaction, - request: &Pubkey, -) -> Instruction { - let account_meta = vec![ - AccountMeta::new(*submitter, true), - AccountMeta::new(*request, false), - ]; - Instruction::new( - id(), - &SpvInstruction::SubmitProof(Proof { - submitter: *submitter, - proof, - headers, - transaction, - request: *request, - }), - account_meta, - ) -} diff --git a/programs/btc_spv/src/spv_processor.rs b/programs/btc_spv/src/spv_processor.rs deleted file mode 100644 index 4b4cd9ad54..0000000000 --- a/programs/btc_spv/src/spv_processor.rs +++ /dev/null @@ -1,187 +0,0 @@ -//! Bitcoin SPV proof verifier program -//! Receive merkle proofs and block headers, validate transaction -use crate::spv_instruction::*; -use crate::spv_state::*; -#[allow(unused_imports)] -use crate::utils::*; -use log::*; -use solana_sdk::account::KeyedAccount; -use solana_sdk::instruction::InstructionError; -use solana_sdk::program_utils::limited_deserialize; -use solana_sdk::pubkey::Pubkey; - -pub struct SpvProcessor {} - -impl SpvProcessor { - pub fn validate_header_chain( - headers: HeaderChain, - proof_req: &ProofRequest, - ) -> Result<(), InstructionError> { - // disabled for time being - //not done yet, needs difficulty average/variance checking still - Ok(()) - } - - #[allow(clippy::needless_pass_by_value)] - fn map_to_invalid_arg(err: std::boxed::Box) -> InstructionError { - warn!("Deserialize failed, not a valid state: {:?}", err); - InstructionError::InvalidArgument - } - - fn deserialize_proof(data: &[u8]) -> Result { - let proof_state: AccountState = - bincode::deserialize(data).map_err(Self::map_to_invalid_arg)?; - if let AccountState::Verification(proof) = proof_state { - Ok(proof) - } else { - error!("Not a valid proof"); - Err(InstructionError::InvalidAccountData) - } - } - - fn deserialize_request(data: &[u8]) -> Result { - let req_state: AccountState = - bincode::deserialize(data).map_err(Self::map_to_invalid_arg)?; - if let AccountState::Request(info) = req_state { - Ok(info) - } else { - error!("Not a valid proof request"); - Err(InstructionError::InvalidAccountData) - } - } - - pub fn check_account_unallocated(data: &[u8]) -> Result<(), InstructionError> { - let acct_state: AccountState = - bincode::deserialize(data).map_err(Self::map_to_invalid_arg)?; - if let AccountState::Unallocated = acct_state { - Ok(()) - } else { - error!("Provided account is already occupied"); - Err(InstructionError::InvalidAccountData) - } - } - - pub fn do_client_request( - keyed_accounts: &[KeyedAccount], - request_info: &ClientRequestInfo, - ) -> Result<(), InstructionError> { - if keyed_accounts.len() != 2 { - error!("Client Request invalid accounts argument length (should be 2)") - } - const OWNER_INDEX: usize = 0; - const REQUEST_INDEX: usize = 1; - - // check_account_unallocated(&keyed_accounts[REQUEST_INDEX].account.data)?; - Ok(()) //placeholder - } - - pub fn do_cancel_request(keyed_accounts: &[KeyedAccount]) -> Result<(), InstructionError> { - if keyed_accounts.len() != 2 { - error!("Client Request invalid accounts argument length (should be 2)") - } - const OWNER_INDEX: usize = 0; - const CANCEL_INDEX: usize = 1; - Ok(()) //placeholder - } - - pub fn do_submit_proof( - keyed_accounts: &[KeyedAccount], - proof_info: &Proof, - ) -> Result<(), InstructionError> { - if keyed_accounts.len() != 2 { - error!("Client Request invalid accounts argument length (should be 2)") - } - const SUBMITTER_INDEX: usize = 0; - const PROOF_REQUEST_INDEX: usize = 1; - Ok(()) //placeholder - } -} -pub fn process_instruction( - _program_id: &Pubkey, - keyed_accounts: &[KeyedAccount], - data: &[u8], -) -> Result<(), InstructionError> { - // solana_logger::setup(); - - let command = limited_deserialize::(data)?; - - trace!("{:?}", command); - - match command { - SpvInstruction::ClientRequest(client_request_info) => { - SpvProcessor::do_client_request(keyed_accounts, &client_request_info) - } - SpvInstruction::CancelRequest => SpvProcessor::do_cancel_request(keyed_accounts), - SpvInstruction::SubmitProof(proof_info) => { - SpvProcessor::do_submit_proof(keyed_accounts, &proof_info) - } - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::{spv_instruction, spv_state, utils}; - - #[test] - fn test_parse_header_hex() -> Result<(), SpvError> { - let testheader = "010000008a730974ac39042e95f82d719550e224c1a680a8dc9e8df9d007000000000000f50b20e8720a552dd36eb2ebdb7dceec9569e0395c990c1eb8a4292eeda05a931e1fce4e9a110e1a7a58aeb0"; - let testhash = "0000000000000bae09a7a393a8acded75aa67e46cb81f7acaa5ad94f9eacd103"; - let testheaderbytes = hex::decode(&testheader)?; - let testhashbytes = hex::decode(&testhash)?; - - let mut blockhash: [u8; 32] = [0; 32]; - blockhash.copy_from_slice(&testhashbytes[..32]); - - let mut version: [u8; 4] = [0; 4]; - version.copy_from_slice(&testheaderbytes[..4]); - let test_version = u32::from_le_bytes(version); - - let mut test_parent: [u8; 32] = [0; 32]; - test_parent.copy_from_slice(&testheaderbytes[4..36]); - - let mut merkleroot: [u8; 32] = [0; 32]; - merkleroot.copy_from_slice(&testheaderbytes[36..68]); - - let mut time: [u8; 4] = [0; 4]; - time.copy_from_slice(&testheaderbytes[68..72]); - let test_time = u32::from_le_bytes(time); - - let mut test_nonce: [u8; 4] = [0; 4]; - test_nonce.copy_from_slice(&testheaderbytes[76..80]); - - let bh = BlockHeader::hexnew(&testheader, &testhash)?; - - assert_eq!(bh.blockhash, blockhash); - assert_eq!(bh.merkle_root.hash, merkleroot); - assert_eq!(bh.version, test_version); - assert_eq!(bh.time, test_time); - assert_eq!(bh.parent, test_parent); - assert_eq!(bh.nonce, test_nonce); - - Ok(()) - } - - #[test] - fn test_parse_transaction_hex() { - let testblockhash = "0000000000000bae09a7a393a8acded75aa67e46cb81f7acaa5ad94f9eacd103"; - let testtxhash = "5b09bbb8d3cb2f8d4edbcf30664419fb7c9deaeeb1f62cb432e7741c80dbe5ba"; - - let mut testdatabytes = include_bytes!("testblock.in"); - let mut headerbytes = hex::encode(&testdatabytes[0..]); - let hbc = &headerbytes[0..80]; - - let mut txdata = &testdatabytes[80..]; - - let vilen = measure_variable_int(&txdata[0..9]).unwrap(); - let txnum = decode_variable_int(&txdata[0..9]).unwrap(); - - txdata = &txdata[vilen..]; - let tx = BitcoinTransaction::new(txdata.to_vec()); - - assert_eq!(tx.inputs.len(), 1); - assert_eq!(txnum, 22); - assert_eq!(tx.outputs.len(), 1); - assert_eq!(tx.version, 1); - } -} diff --git a/programs/btc_spv/src/spv_state.rs b/programs/btc_spv/src/spv_state.rs deleted file mode 100644 index 98751d735e..0000000000 --- a/programs/btc_spv/src/spv_state.rs +++ /dev/null @@ -1,457 +0,0 @@ -use crate::header_store::*; -use crate::utils::*; -use serde_derive::{Deserialize, Serialize}; -use solana_sdk::pubkey::Pubkey; -use std::{error, fmt}; - -pub type BitcoinTxHash = [u8; 32]; - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct BlockHeader { - // Bitcoin network version - pub version: u32, - // Previous block's hash/digest - pub parent: [u8; 32], - // merkle Root of the block, proofEntry side should be None - pub merkle_root: ProofEntry, - // the blocktime associate with the block - pub time: u32, - // An encoded version of the target threshold this block’s header hash must be less than or equal to. - pub nbits: [u8; 4], - // block header's nonce - pub nonce: [u8; 4], - // Block hash - pub blockhash: [u8; 32], -} - -impl BlockHeader { - pub fn new(header: &[u8; 80], blockhash: &[u8; 32]) -> Result { - let mut va: [u8; 4] = [0; 4]; - va.copy_from_slice(&header[0..4]); - let version = u32::from_le_bytes(va); - - let mut ph: [u8; 32] = [0; 32]; - ph.copy_from_slice(&header[4..36]); - let parent = ph; - // extract merkle root in internal byte order - let mut mrr: [u8; 32] = [0; 32]; - mrr.copy_from_slice(&header[36..68]); - let merkle_root = ProofEntry { - hash: mrr, - side: EntrySide::Root, - }; - // timestamp associate with the block - let mut bt: [u8; 4] = [0; 4]; - bt.copy_from_slice(&header[68..72]); - let time = u32::from_le_bytes(bt); - - // nbits field is an encoded version of the - let mut nb: [u8; 4] = [0; 4]; - nb.copy_from_slice(&header[72..76]); - let nbits = nb; - - let mut nn: [u8; 4] = [0; 4]; - nn.copy_from_slice(&header[76..80]); - let nonce = nn; - - let bh = BlockHeader { - version, - parent, - merkle_root, - time, - nbits, - nonce, - blockhash: *blockhash, - }; - Ok(bh) - } - - pub fn hexnew(header: &str, blockhash: &str) -> Result { - if header.len() != 160 || blockhash.len() != 64 { - return Err(SpvError::InvalidBlockHeader); - } - - match hex::decode(header) { - Ok(header) => { - let bhbytes = hex::decode(blockhash)?; - const SIZE: usize = 80; - let mut hh = [0; SIZE]; - hh.copy_from_slice(&header[..header.len()]); - - let mut bhb: [u8; 32] = [0; 32]; - bhb.copy_from_slice(&bhbytes[..bhbytes.len()]); - - Ok(BlockHeader::new(&hh, &bhb).unwrap()) - } - Err(e) => Err(SpvError::InvalidBlockHeader), - } - } - - pub fn difficulty(mut self) -> u32 { - // calculates difficulty from nbits - let standin: u32 = 123_456_789; - standin - } -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct BitcoinTransaction { - pub inputs: Vec, - - pub inputs_num: u64, - //input utxos - pub outputs: Vec, - - pub outputs_num: u64, - //output utxos - pub version: u32, - //bitcoin network version - pub lock_time: u32, - - pub bytes_len: usize, -} - -impl BitcoinTransaction { - pub fn new(txbytes: Vec) -> Self { - let mut ver: [u8; 4] = [0; 4]; - ver.copy_from_slice(&txbytes[..4]); - let version = u32::from_le_bytes(ver); - - let inputs_num: u64 = decode_variable_int(&txbytes[4..13]).unwrap(); - let vinlen: usize = measure_variable_int(&txbytes[4..13]).unwrap(); - let mut inputstart: usize = 4 + vinlen; - let mut inputs = Vec::new(); - - if inputs_num > 0 { - for i in 0..inputs_num { - let mut input = Input::new(txbytes[inputstart..].to_vec()); - inputstart += input.bytes_len; - inputs.push(input); - } - inputs.to_vec(); - } - - let outputs_num: u64 = decode_variable_int(&txbytes[inputstart..9 + inputstart]).unwrap(); - let voutlen: usize = measure_variable_int(&txbytes[inputstart..9 + inputstart]).unwrap(); - - let mut outputstart: usize = inputstart + voutlen; - let mut outputs = Vec::new(); - for i in 0..outputs_num { - let mut output = Output::new(txbytes[outputstart..].to_vec()); - outputstart += output.bytes_len; - outputs.push(output); - } - - let mut lt: [u8; 4] = [0; 4]; - lt.copy_from_slice(&txbytes[outputstart..4 + outputstart]); - let lock_time = u32::from_le_bytes(lt); - - assert_eq!(inputs.len(), inputs_num as usize); - assert_eq!(outputs.len(), outputs_num as usize); - - BitcoinTransaction { - inputs, - inputs_num, - outputs, - outputs_num, - version, - lock_time, - bytes_len: 4 + outputstart, - } - } - pub fn hexnew(hex: String) -> Result { - match hex::decode(&hex) { - Ok(txbytes) => Ok(BitcoinTransaction::new(txbytes)), - Err(e) => Err(SpvError::ParseError), - } - } -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct Input { - pub input_type: InputType, - // Type of the input - pub position: u32, - // position of the tx in its Block - pub txhash: BitcoinTxHash, - // hash of the transaction - pub script_length: u64, - // length of the spend script - pub script: Vec, - // script bytes - pub sequence: [u8; 4], - // length of the input in bytes - pub bytes_len: usize, -} - -impl Input { - fn new(ibytes: Vec) -> Self { - let mut txhash: [u8; 32] = [0; 32]; - txhash.copy_from_slice(&ibytes[..32]); - - let mut tx_out_index: [u8; 4] = [0; 4]; - tx_out_index.copy_from_slice(&ibytes[32..36]); - let position = u32::from_le_bytes(tx_out_index); - - let script_length: u64 = decode_variable_int(&ibytes[36..45]).unwrap(); - let script_length_len: usize = measure_variable_int(&ibytes[36..45]).unwrap(); - let script_start = 36 + script_length_len; //checkc for correctness - let script_end = script_start + script_length as usize; - let input_end = script_end + 4; - - let script: Vec = ibytes[script_start..script_length as usize].to_vec(); - - let mut sequence: [u8; 4] = [0; 4]; - sequence.copy_from_slice(&ibytes[script_end..input_end]); - - let input_type: InputType = InputType::NONE; // testing measure - - Self { - input_type, - position, - txhash, - script_length, - script, - sequence, - bytes_len: input_end, - } - } - - fn default() -> Self { - let txh: [u8; 32] = [0; 32]; - let seq: [u8; 4] = [0; 4]; - - Self { - input_type: InputType::NONE, - position: 55, - txhash: txh, - script_length: 45, - script: txh.to_vec(), - sequence: seq, - bytes_len: 123, - } - } -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub enum InputType { - LEGACY, - COMPATIBILITY, - WITNESS, - NONE, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct Output { - pub output_type: OutputType, - // type of the output - pub value: u64, - // amount of btc in sats - pub script: Vec, - - pub script_length: u64, - - pub bytes_len: usize, - // payload: Option>, - // // data sent with the transaction (Op return) -} - -impl Output { - fn new(obytes: Vec) -> Self { - let mut val: [u8; 8] = [0; 8]; - val.copy_from_slice(&obytes[..8]); - let value: u64 = u64::from_le_bytes(val); - - let script_start: usize = 8 + measure_variable_int(&obytes[8..17]).unwrap(); - let script_length = decode_variable_int(&obytes[8..script_start]).unwrap(); - let script_end: usize = script_start + script_length as usize; - - let script = obytes[script_start..script_end].to_vec(); - - let output_type = OutputType::WPKH; // temporary hardcode - - Self { - output_type, - value, - script, - script_length, - bytes_len: script_end, - } - } - - fn default() -> Self { - let transaction_hash: [u8; 32] = [0; 32]; - - Self { - output_type: OutputType::WPKH, - value: 55, - script: transaction_hash.to_vec(), - script_length: 45, - bytes_len: 123, - } - } -} - -#[allow(non_camel_case_types)] -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub enum OutputType { - WPKH, - WSH, - OP_RETURN, - PKH, - SH, - NONSTANDARD, - // https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md -} - -pub type HeaderChain = Vec; -// a vector of BlockHeaders used as part of a Proof -// index 0 : the block header of the block prior to the proof Block -// index 1 : the block header of the proof block -// index 2-n* : the block headers for the confirmation chain -// (where n is the confirmations value from the proof request) - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct ProofEntry { - // 32 byte merkle hashes - pub hash: [u8; 32], - // side of the merkle tree entry - pub side: EntrySide, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub enum EntrySide { - // Left side of the hash combination - Left, - // Right side of hash combination - Right, - // Root hash (neither side) - Root, -} - -pub type MerkleProof = Vec; -// a vector of ProofEntries used as part of a Proof -// index 0 : a ProofEntry representing the txid -// indices 0-n : ProofEntries linking the txhash and the merkle root -// index n : a ProofEntry representing the merkel root for the block in question - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct ClientRequestInfo { - // bitcoin transaction hash - pub txhash: BitcoinTxHash, - // confirmation count - pub confirmations: u8, - // fee paid for tx verification - pub fee: u64, - // required minimum difficulty for submitted blocks - pub difficulty: u64, - // expiration slot height - pub expiration: Option, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct ProofRequest { - pub owner: Pubkey, - // bitcoin transaction hash - pub txhash: BitcoinTxHash, - // confirmation count - pub confirmations: u8, - // fee paid for tx verification - pub fee: u64, - // minimum allowable difficulty - pub difficulty: u64, - // expiration slot height - pub expiration: u64, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub struct Proof { - // the pubkey who submitted the proof in question, entitled to fees from any corresponding proof requests - pub submitter: Pubkey, - // merkle branch connecting txhash to block header merkle root - pub proof: MerkleProof, - // chain of bitcoin headers provifing context for the proof - pub headers: HeaderChain, - // transaction associated with the Proof - pub transaction: BitcoinTransaction, - // public key of the request this proof corresponds to - pub request: Pubkey, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] -pub enum AccountState { - // Request Account - Request(ClientRequestInfo), - // Verified Proof - Verification(Proof), - // Account holds a HeaderStore structure - Headers(HeaderAccountInfo), - // Account's data is Unallocated - Unallocated, - // Invalid - Invalid, -} - -impl Default for AccountState { - fn default() -> Self { - AccountState::Unallocated - } -} - -///Errors -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum SpvError { - InvalidBlockHeader, - // blockheader is malformed or out of order - HeaderStoreError, - // header store write/read result is invalid - ParseError, - // other errors with parsing inputs - InvalidAccount, -} - -impl error::Error for SpvError { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - // temporary measure - None - } -} - -impl From for SpvError { - fn from(e: HeaderStoreError) -> Self { - SpvError::HeaderStoreError - } -} - -impl From for SpvError { - fn from(e: DecodeHexError) -> Self { - SpvError::ParseError - } -} - -impl From for SpvError { - fn from(e: hex::FromHexError) -> Self { - SpvError::ParseError - } -} - -// impl fmt::Debug for SpvError { -// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{ -// match self { -// SpvError::InvalidBlockHeader => "BlockHeader is malformed or does not apply ".fmt(f), -// SpvError::HeaderStoreError => "Placeholder headerstore error debug text".fmt(f), -// SpvError::ParseError => "Error parsing blockheaders debug".fmt(f), -// } -// } -// } - -impl fmt::Display for SpvError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - SpvError::InvalidBlockHeader => "BlockHeader is malformed or does not apply ".fmt(f), - SpvError::HeaderStoreError => "Placeholder headerstore error text".fmt(f), - SpvError::ParseError => "Error parsing blockheaders placceholder text".fmt(f), - SpvError::InvalidAccount => "Provided account is not usable or does not exist".fmt(f), - } - } -} diff --git a/programs/btc_spv/src/testblock.in b/programs/btc_spv/src/testblock.in deleted file mode 100644 index 01e7fb15be8800557b08db1bc66105a4a98331dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9195 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 j3 for DecodeHexError { - fn from(e: ParseIntError) -> Self { - DecodeHexError::ParseInt(e) - } -} - -impl fmt::Display for DecodeHexError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - DecodeHexError::InvalidLength(LengthError::OddLength) => { - "input hex string length is odd ".fmt(f) - } - DecodeHexError::InvalidLength(LengthError::Maximum(e)) => { - "input exceeds the maximum length".fmt(f) - } - DecodeHexError::InvalidLength(LengthError::Minimum(e)) => { - "input does not meet the minimum length".fmt(f) - } - DecodeHexError::ParseInt(e) => e.fmt(f), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum LengthError { - OddLength, - Maximum(u32), - Minimum(u32), -} - -pub fn decode_hex(s: &str) -> Result, DecodeHexError> { - if s.len() % 2 != 0 { - Err(DecodeHexError::InvalidLength(LengthError::OddLength)) - } else { - (0..s.len()) - .step_by(2) - .map(|i| u8::from_str_radix(&s[i..i + 2], 16).map_err(|e| e.into())) - .collect() - } -} - -pub fn measure_variable_int(vint: &[u8]) -> Result { - let ln = vint.len(); - if ln > 9 { - return Err(DecodeHexError::InvalidLength(LengthError::Maximum(9))); - } - - let val: usize = match vint[0] { - 0..=252 => 1, - 253 => 3, - 254 => 5, - 255 => 9, - }; - Ok(val) -} - -pub fn decode_variable_int(vint: &[u8]) -> Result { - let ln = vint.len(); - if ln > 9 { - return Err(DecodeHexError::InvalidLength(LengthError::Maximum(9))); - } - - let val: u64 = match vint[0] { - 0..=252 => u64::from(vint[0]), - 253 => { - let mut val: [u8; 2] = [0; 2]; - val.copy_from_slice(&vint[1..3]); - u64::from(u16::from_le_bytes(val)) - } - 254 => { - let mut val: [u8; 4] = [0; 4]; - val.copy_from_slice(&vint[1..5]); - u64::from(u32::from_le_bytes(val)) - } - 255 => { - let mut val: [u8; 8] = [0; 8]; - val.copy_from_slice(&vint[1..9]); - u64::from_le_bytes(val) - } - }; - Ok(val) -} - -#[cfg(test)] -mod test { - use crate::utils::*; - - #[test] - fn test_parse_variable_int() { - let var_int_a = hex::decode("6a32a4").unwrap(); - let var_int_b = hex::decode("fd26021d32").unwrap(); - let var_int_c = hex::decode("fe703a0f00").unwrap(); - - let value_a = decode_variable_int(&var_int_a[0..]).unwrap(); - let value_b = decode_variable_int(&var_int_b[0..]).unwrap(); - let value_c = decode_variable_int(&var_int_c[0..]).unwrap(); - - assert_eq!(106, value_a); - assert_eq!(550, value_b); - assert_eq!(998_000, value_c); - } - - #[test] - fn test_measure_variable_int() { - let var_int_a = hex::decode("6a32a4").unwrap(); - let var_int_b = hex::decode("fd26021d32").unwrap(); - let var_int_c = hex::decode("fe703a0f00").unwrap(); - - let len_a = measure_variable_int(&var_int_a[0..]).unwrap(); - let len_b = measure_variable_int(&var_int_b[0..]).unwrap(); - let len_c = measure_variable_int(&var_int_c[0..]).unwrap(); - - assert_eq!(len_a, 1); - assert_eq!(len_b, 3); - assert_eq!(len_c, 5); - } -} diff --git a/programs/btc_spv_bin/Cargo.toml b/programs/btc_spv_bin/Cargo.toml deleted file mode 100644 index b20624933d..0000000000 --- a/programs/btc_spv_bin/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "btc_spv_bin" -version = "1.3.0" -description = "Solana Bitcoin spv parsing program" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2018" - -[dependencies] -clap="2.33.1" -reqwest = { version = "0.10.6", default-features = false, features = ["blocking", "rustls-tls", "json"] } -serde="1.0.112" -serde_derive="1.0.103" -hex = "0.4.2" - -[[bin]] -name = "blockheaders" -path = "src/blockheade.rs" - -[[bin]] -name = "blocks" -path = "src/block.rs" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/programs/btc_spv_bin/src/block.rs b/programs/btc_spv_bin/src/block.rs deleted file mode 100644 index ac84531d41..0000000000 --- a/programs/btc_spv_bin/src/block.rs +++ /dev/null @@ -1,48 +0,0 @@ -use clap::{App, Arg}; -use std::fs::File; -use std::io::prelude::*; - -fn get_block_raw(hash: &str) -> String { - let qs = format!("https://blockchain.info/block/{}?format=hex", hash); - let body = reqwest::blocking::get(&qs); - match body { - Err(e) => panic!("rest request failed {}", e), - Ok(n) => { - if n.status().is_success() { - n.text().unwrap() - } else { - panic!("request failed"); - } - } - } -} - -fn write_file(fname: String, bytes: &[u8]) -> std::io::Result<()> { - let mut buffer = File::create(fname)?; - buffer.write_all(bytes)?; - Ok(()) -} - -fn main() { - let matches = App::new("header fetch util") - .arg(Arg::with_name("blockhash")) - .arg(Arg::with_name("output")) - .help("block hash to get header from") - .get_matches(); - - let default_output = "file"; - let output = matches.value_of("output").unwrap_or(default_output); - - let testhash = "0000000000000bae09a7a393a8acded75aa67e46cb81f7acaa5ad94f9eacd103"; - let blockhash = matches.value_of("blockhash").unwrap_or(testhash); - let blockraw = get_block_raw(&blockhash); - - if default_output == output { - let fname = format!("block-{}.in", blockhash); - let outf = hex::decode(&blockraw).unwrap(); - let arr = &outf[0..]; - write_file(fname, arr).unwrap(); - } else { - println!("{}", blockraw); - } -} diff --git a/programs/btc_spv_bin/src/blockheade.rs b/programs/btc_spv_bin/src/blockheade.rs deleted file mode 100644 index ce8fcaf715..0000000000 --- a/programs/btc_spv_bin/src/blockheade.rs +++ /dev/null @@ -1,74 +0,0 @@ -use clap::{App, Arg}; -use serde_derive::Deserialize; - -// pub type blockHash = [u8; 32]; -pub type BlockHeader = [u8; 80]; - -#[allow(dead_code)] -#[derive(Deserialize)] -struct JsonBH { - hash: String, - ver: u16, - prev_block: String, - mrkl_root: String, - time: u64, - bits: u64, - nonce: u64, - n_tx: u64, - size: u64, - block_index: u64, - main_chain: bool, - height: u64, - received_time: u64, - relayed_by: String, -} - -#[allow(dead_code)] -fn get_header_json(hash: &str) -> JsonBH { - let qs = format!("https://www.blockchain.info/rawblock/{}", hash); - let body = reqwest::blocking::get(&qs); - match body { - Err(e) => panic!("rest request failed {}", e), - Ok(n) => { - if n.status().is_success() { - let jsonbh: JsonBH = n.json().unwrap(); - jsonbh - } else { - panic!("request failed"); - } - } - } -} - -fn get_header_raw(hash: &str) -> String { - let qs = format!("https://blockchain.info/block/{}?format=hex", hash); - let body = reqwest::blocking::get(&qs); - match body { - Err(e) => panic!("rest request failed {}", e), - Ok(n) => { - if n.status().is_success() { - let textbh: String = n.text().unwrap(); - let hs = &textbh[0..160]; // 160 characters since it's in hex format - let header: String = hs.to_string(); - header - } else { - panic!("request failed"); - } - } - } -} - -fn main() { - let matches = App::new("header fetch util") - .arg(Arg::with_name("blockhash")) - .help("block hash to get header from") - .get_matches(); - - let testhash = "0000000000000bae09a7a393a8acded75aa67e46cb81f7acaa5ad94f9eacd103"; - let blockhash = matches.value_of("blockhash").unwrap_or(testhash); - let headerraw = get_header_raw(&blockhash); - println!("header - {}", headerraw); - println!("hash - {}", blockhash); - println!("length - {}", headerraw.len()); - // println!("{}", std::str::from_utf8(&header)); -}