2019-09-03 18:16:02 -07:00
|
|
|
|
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<BlockHeader, SpvError> {
|
|
|
|
|
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<BlockHeader, SpvError> {
|
|
|
|
|
if header.len() != 160 || blockhash.len() != 64 {
|
|
|
|
|
return Err(SpvError::InvalidBlockHeader);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-18 19:30:27 -07:00
|
|
|
|
match hex::decode(header) {
|
2019-09-03 18:16:02 -07:00
|
|
|
|
Ok(header) => {
|
2019-09-18 19:30:27 -07:00
|
|
|
|
let bhbytes = hex::decode(blockhash)?;
|
2019-09-03 18:16:02 -07:00
|
|
|
|
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)]
|
2019-09-18 19:30:27 -07:00
|
|
|
|
pub struct BitcoinTransaction {
|
|
|
|
|
pub inputs: Vec<Input>,
|
|
|
|
|
|
|
|
|
|
pub inputs_num: u64,
|
2019-09-03 18:16:02 -07:00
|
|
|
|
//input utxos
|
2019-09-18 19:30:27 -07:00
|
|
|
|
pub outputs: Vec<Output>,
|
|
|
|
|
|
|
|
|
|
pub outputs_num: u64,
|
2019-09-03 18:16:02 -07:00
|
|
|
|
//output utxos
|
2019-09-18 19:30:27 -07:00
|
|
|
|
pub version: u32,
|
2019-09-03 18:16:02 -07:00
|
|
|
|
//bitcoin network version
|
2019-09-18 19:30:27 -07:00
|
|
|
|
pub lock_time: u32,
|
|
|
|
|
|
|
|
|
|
pub bytes_len: usize,
|
2019-09-03 18:16:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-18 19:30:27 -07:00
|
|
|
|
impl BitcoinTransaction {
|
|
|
|
|
pub fn new(txbytes: Vec<u8>) -> 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<BitcoinTransaction, SpvError> {
|
|
|
|
|
match hex::decode(&hex) {
|
|
|
|
|
Ok(txbytes) => Ok(BitcoinTransaction::new(txbytes)),
|
|
|
|
|
Err(e) => Err(SpvError::ParseError),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-03 18:16:02 -07:00
|
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
|
|
|
|
pub struct Input {
|
2019-09-18 19:30:27 -07:00
|
|
|
|
pub input_type: InputType,
|
2019-09-03 18:16:02 -07:00
|
|
|
|
// Type of the input
|
2019-09-18 19:30:27 -07:00
|
|
|
|
pub position: u32,
|
2019-09-03 18:16:02 -07:00
|
|
|
|
// position of the tx in its Block
|
2019-09-18 19:30:27 -07:00
|
|
|
|
pub txhash: BitcoinTxHash,
|
2019-09-03 18:16:02 -07:00
|
|
|
|
// hash of the transaction
|
2019-09-18 19:30:27 -07:00
|
|
|
|
pub script_length: u64,
|
|
|
|
|
// length of the spend script
|
|
|
|
|
pub script: Vec<u8>,
|
|
|
|
|
// script bytes
|
|
|
|
|
pub sequence: [u8; 4],
|
|
|
|
|
// length of the input in bytes
|
|
|
|
|
pub bytes_len: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Input {
|
|
|
|
|
fn new(ibytes: Vec<u8>) -> 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<u8> = 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,
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-03 18:16:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
|
|
|
|
pub enum InputType {
|
|
|
|
|
LEGACY,
|
|
|
|
|
COMPATIBILITY,
|
|
|
|
|
WITNESS,
|
|
|
|
|
NONE,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
|
|
|
|
pub struct Output {
|
2019-09-18 19:30:27 -07:00
|
|
|
|
pub output_type: OutputType,
|
2019-09-03 18:16:02 -07:00
|
|
|
|
// type of the output
|
2019-09-18 19:30:27 -07:00
|
|
|
|
pub value: u64,
|
2019-09-03 18:16:02 -07:00
|
|
|
|
// amount of btc in sats
|
2019-09-18 19:30:27 -07:00
|
|
|
|
pub script: Vec<u8>,
|
|
|
|
|
|
|
|
|
|
pub script_length: u64,
|
|
|
|
|
|
|
|
|
|
pub bytes_len: usize,
|
|
|
|
|
// payload: Option<Vec<u8>>,
|
|
|
|
|
// // data sent with the transaction (Op return)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Output {
|
|
|
|
|
fn new(obytes: Vec<u8>) -> 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,
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-03 18:16:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(non_camel_case_types)]
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
|
|
|
|
pub enum OutputType {
|
|
|
|
|
WPKH,
|
|
|
|
|
WSH,
|
|
|
|
|
OP_RETURN,
|
|
|
|
|
PKH,
|
|
|
|
|
SH,
|
|
|
|
|
NONSTANDARD,
|
2019-09-18 19:30:27 -07:00
|
|
|
|
// https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md
|
2019-09-03 18:16:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub type HeaderChain = Vec<BlockHeader>;
|
|
|
|
|
// 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<ProofEntry>;
|
|
|
|
|
// 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<u32>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[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
|
2019-09-18 19:30:27 -07:00
|
|
|
|
pub transaction: BitcoinTransaction,
|
2019-09-03 18:16:02 -07:00
|
|
|
|
// 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),
|
2019-09-18 19:30:27 -07:00
|
|
|
|
// Account holds a HeaderStore structure
|
|
|
|
|
Headers(HeaderAccountInfo),
|
2020-02-11 16:30:22 -08:00
|
|
|
|
// Account's data is Unallocated
|
2019-09-03 18:16:02 -07:00
|
|
|
|
Unallocated,
|
|
|
|
|
// Invalid
|
|
|
|
|
Invalid,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for AccountState {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
AccountState::Unallocated
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///Errors
|
2019-11-29 12:50:32 -08:00
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
2019-09-03 18:16:02 -07:00
|
|
|
|
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
|
2019-09-18 19:30:27 -07:00
|
|
|
|
InvalidAccount,
|
2019-09-03 18:16:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl error::Error for SpvError {
|
|
|
|
|
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
|
|
|
|
// temporary measure
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<HeaderStoreError> for SpvError {
|
|
|
|
|
fn from(e: HeaderStoreError) -> Self {
|
|
|
|
|
SpvError::HeaderStoreError
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<DecodeHexError> for SpvError {
|
|
|
|
|
fn from(e: DecodeHexError) -> Self {
|
|
|
|
|
SpvError::ParseError
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-18 19:30:27 -07:00
|
|
|
|
impl From<hex::FromHexError> for SpvError {
|
|
|
|
|
fn from(e: hex::FromHexError) -> Self {
|
|
|
|
|
SpvError::ParseError
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-03 18:16:02 -07:00
|
|
|
|
// 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),
|
2019-09-18 19:30:27 -07:00
|
|
|
|
SpvError::InvalidAccount => "Provided account is not usable or does not exist".fmt(f),
|
2019-09-03 18:16:02 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|