Implementing (W)Pubkey/ScriptHash and BlockHash

This commit is contained in:
Dr Maxim Orlovsky 2019-11-30 17:00:17 +01:00
parent ec92a05682
commit 5ef39e34fa
4 changed files with 26 additions and 20 deletions

View File

@ -26,6 +26,7 @@ use util;
use util::Error::{BlockBadTarget, BlockBadProofOfWork}; use util::Error::{BlockBadTarget, BlockBadProofOfWork};
use util::hash::{BitcoinHash, MerkleRoot, bitcoin_merkle_root}; use util::hash::{BitcoinHash, MerkleRoot, bitcoin_merkle_root};
use util::uint::Uint256; use util::uint::Uint256;
use hash_types::BlockHash;
use consensus::encode::Encodable; use consensus::encode::Encodable;
use network::constants::Network; use network::constants::Network;
use blockdata::transaction::Transaction; use blockdata::transaction::Transaction;
@ -39,7 +40,7 @@ pub struct BlockHeader {
/// The protocol version. Should always be 1. /// The protocol version. Should always be 1.
pub version: u32, pub version: u32,
/// Reference to the previous block in the chain /// Reference to the previous block in the chain
pub prev_blockhash: sha256d::Hash, pub prev_blockhash: BlockHash,
/// The root hash of the merkle tree of transactions in the block /// The root hash of the merkle tree of transactions in the block
pub merkle_root: sha256d::Hash, pub merkle_root: sha256d::Hash,
/// The timestamp of the block, as claimed by the miner /// The timestamp of the block, as claimed by the miner

View File

@ -49,3 +49,5 @@ hash_newtype!(WScriptHash, sha256::Hash, 32, doc="SegWit version of a Bitcoin Sc
hash_newtype!(XpubIdentifier, hash160::Hash, 20, doc="XpubIdentifier as defined in BIP-32."); hash_newtype!(XpubIdentifier, hash160::Hash, 20, doc="XpubIdentifier as defined in BIP-32.");
impl_hashencode!(Txid); impl_hashencode!(Txid);
impl_hashencode!(Wtxid);
impl_hashencode!(BlockHash);

View File

@ -46,6 +46,7 @@ use std::str::FromStr;
use bech32; use bech32;
use hashes::{hash160, sha256, Hash}; use hashes::{hash160, sha256, Hash};
use hash_types::{PubkeyHash, ScriptHash, WScriptHash};
use blockdata::opcodes; use blockdata::opcodes;
use blockdata::script; use blockdata::script;
use network::constants::Network; use network::constants::Network;
@ -159,9 +160,9 @@ impl FromStr for AddressType {
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Payload { pub enum Payload {
/// pay-to-pkhash address /// pay-to-pkhash address
PubkeyHash(hash160::Hash), PubkeyHash(PubkeyHash),
/// P2SH address /// P2SH address
ScriptHash(hash160::Hash), ScriptHash(ScriptHash),
/// Segwit address /// Segwit address
WitnessProgram { WitnessProgram {
/// The witness program version /// The witness program version
@ -175,9 +176,9 @@ impl Payload {
/// Get a [Payload] from an output script (scriptPubkey). /// Get a [Payload] from an output script (scriptPubkey).
pub fn from_script(script: &script::Script) -> Option<Payload> { pub fn from_script(script: &script::Script) -> Option<Payload> {
Some(if script.is_p2pkh() { Some(if script.is_p2pkh() {
Payload::PubkeyHash(Hash::from_slice(&script.as_bytes()[3..23]).unwrap()) Payload::PubkeyHash(PubkeyHash::from_slice(&script.as_bytes()[3..23]).unwrap())
} else if script.is_p2sh() { } else if script.is_p2sh() {
Payload::ScriptHash(Hash::from_slice(&script.as_bytes()[2..22]).unwrap()) Payload::ScriptHash(ScriptHash::from_slice(&script.as_bytes()[2..22]).unwrap())
} else if script.is_witness_program() { } else if script.is_witness_program() {
// We can unwrap the u5 check and assume script length // We can unwrap the u5 check and assume script length
// because [Script::is_witness_program] makes sure of this. // because [Script::is_witness_program] makes sure of this.
@ -247,7 +248,7 @@ impl Address {
Address { Address {
network: network, network: network,
payload: Payload::PubkeyHash(hash160::Hash::from_engine(hash_engine)), payload: Payload::PubkeyHash(PubkeyHash::from_engine(hash_engine)),
} }
} }
@ -257,7 +258,7 @@ impl Address {
pub fn p2sh(script: &script::Script, network: Network) -> Address { pub fn p2sh(script: &script::Script, network: Network) -> Address {
Address { Address {
network: network, network: network,
payload: Payload::ScriptHash(hash160::Hash::hash(&script[..])), payload: Payload::ScriptHash(ScriptHash::hash(&script[..])),
} }
} }
@ -288,7 +289,7 @@ impl Address {
Address { Address {
network: network, network: network,
payload: Payload::ScriptHash(hash160::Hash::hash(builder.into_script().as_bytes())), payload: Payload::ScriptHash(ScriptHash::hash(builder.into_script().as_bytes())),
} }
} }
@ -298,7 +299,7 @@ impl Address {
network: network, network: network,
payload: Payload::WitnessProgram { payload: Payload::WitnessProgram {
version: bech32::u5::try_from_u8(0).expect("0<32"), version: bech32::u5::try_from_u8(0).expect("0<32"),
program: sha256::Hash::hash(&script[..])[..].to_vec(), program: WScriptHash::hash(&script[..])[..].to_vec(),
}, },
} }
} }
@ -313,7 +314,7 @@ impl Address {
Address { Address {
network: network, network: network,
payload: Payload::ScriptHash(hash160::Hash::hash(&ws[..])), payload: Payload::ScriptHash(ScriptHash::hash(&ws[..])),
} }
} }
@ -470,19 +471,19 @@ impl FromStr for Address {
let (network, payload) = match data[0] { let (network, payload) = match data[0] {
0 => ( 0 => (
Network::Bitcoin, Network::Bitcoin,
Payload::PubkeyHash(hash160::Hash::from_slice(&data[1..]).unwrap()), Payload::PubkeyHash(PubkeyHash::from_slice(&data[1..]).unwrap()),
), ),
5 => ( 5 => (
Network::Bitcoin, Network::Bitcoin,
Payload::ScriptHash(hash160::Hash::from_slice(&data[1..]).unwrap()), Payload::ScriptHash(ScriptHash::from_slice(&data[1..]).unwrap()),
), ),
111 => ( 111 => (
Network::Testnet, Network::Testnet,
Payload::PubkeyHash(hash160::Hash::from_slice(&data[1..]).unwrap()), Payload::PubkeyHash(PubkeyHash::from_slice(&data[1..]).unwrap()),
), ),
196 => ( 196 => (
Network::Testnet, Network::Testnet,
Payload::ScriptHash(hash160::Hash::from_slice(&data[1..]).unwrap()), Payload::ScriptHash(ScriptHash::from_slice(&data[1..]).unwrap()),
), ),
x => return Err(Error::Base58(base58::Error::InvalidVersion(vec![x]))), x => return Err(Error::Base58(base58::Error::InvalidVersion(vec![x]))),
}; };
@ -505,7 +506,7 @@ mod tests {
use std::str::FromStr; use std::str::FromStr;
use std::string::ToString; use std::string::ToString;
use hashes::{hash160, Hash}; use hashes::Hash;
use hex::{decode as hex_decode, encode as hex_encode}; use hex::{decode as hex_decode, encode as hex_encode};
use blockdata::script::Script; use blockdata::script::Script;
@ -517,7 +518,8 @@ mod tests {
macro_rules! hex (($hex:expr) => (hex_decode($hex).unwrap())); macro_rules! hex (($hex:expr) => (hex_decode($hex).unwrap()));
macro_rules! hex_key (($hex:expr) => (PublicKey::from_slice(&hex!($hex)).unwrap())); macro_rules! hex_key (($hex:expr) => (PublicKey::from_slice(&hex!($hex)).unwrap()));
macro_rules! hex_script (($hex:expr) => (Script::from(hex!($hex)))); macro_rules! hex_script (($hex:expr) => (Script::from(hex!($hex))));
macro_rules! hex_hash160 (($hex:expr) => (hash160::Hash::from_slice(&hex!($hex)).unwrap())); macro_rules! hex_pubkeyhash (($hex:expr) => (PubkeyHash::from_slice(&hex!($hex)).unwrap()));
macro_rules! hex_scripthash (($hex:expr) => (ScriptHash::from_slice(&hex!($hex)).unwrap()));
fn roundtrips(addr: &Address) { fn roundtrips(addr: &Address) {
assert_eq!( assert_eq!(
@ -539,7 +541,7 @@ mod tests {
fn test_p2pkh_address_58() { fn test_p2pkh_address_58() {
let addr = Address { let addr = Address {
network: Bitcoin, network: Bitcoin,
payload: Payload::PubkeyHash(hex_hash160!("162c5ea71c0b23f5b9022ef047c4a86470a5b070")), payload: Payload::PubkeyHash(hex_pubkeyhash!("162c5ea71c0b23f5b9022ef047c4a86470a5b070")),
}; };
assert_eq!( assert_eq!(
@ -568,7 +570,7 @@ mod tests {
fn test_p2sh_address_58() { fn test_p2sh_address_58() {
let addr = Address { let addr = Address {
network: Bitcoin, network: Bitcoin,
payload: Payload::ScriptHash(hex_hash160!("162c5ea71c0b23f5b9022ef047c4a86470a5b070")), payload: Payload::ScriptHash(hex_scripthash!("162c5ea71c0b23f5b9022ef047c4a86470a5b070")),
}; };
assert_eq!( assert_eq!(

View File

@ -21,11 +21,12 @@
use secp256k1::{self, Secp256k1}; use secp256k1::{self, Secp256k1};
use PrivateKey; use PrivateKey;
use PublicKey; use PublicKey;
use hashes::{hash160, sha256, Hash, HashEngine, Hmac, HmacEngine}; use hashes::{sha256, Hash, HashEngine, Hmac, HmacEngine};
use blockdata::{opcodes, script}; use blockdata::{opcodes, script};
use std::{error, fmt}; use std::{error, fmt};
use hash_types::ScriptHash;
use network::constants::Network; use network::constants::Network;
use util::address; use util::address;
@ -208,7 +209,7 @@ pub fn create_address<C: secp256k1::Verification>(secp: &Secp256k1<C>,
Ok(address::Address { Ok(address::Address {
network: network, network: network,
payload: address::Payload::ScriptHash( payload: address::Payload::ScriptHash(
hash160::Hash::hash(&script[..]) ScriptHash::hash(&script[..])
) )
}) })
} }