use std::cmp::Ordering;
use std::fmt;
use crate::address::c32::{c32_address, c32_address_decode};
use crate::address::{
public_keys_to_address_hash, to_bits_p2pkh, AddressHashMode,
C32_ADDRESS_VERSION_MAINNET_MULTISIG, C32_ADDRESS_VERSION_MAINNET_SINGLESIG,
C32_ADDRESS_VERSION_TESTNET_MULTISIG, C32_ADDRESS_VERSION_TESTNET_SINGLESIG,
};
use crate::deps_common::bitcoin::blockdata::transaction::TxOut;
use crate::types::chainstate::{StacksAddress, StacksPublicKey};
use crate::util::hash::Hash160;
use crate::util::secp256k1::{MessageSignature, Secp256k1PublicKey};
pub mod chainstate;
pub mod net;
#[cfg(feature = "sqlite")]
pub mod sqlite;
pub struct StacksPublicKeyBuffer(pub [u8; 33]);
impl_array_newtype!(StacksPublicKeyBuffer, u8, 33);
impl_array_hexstring_fmt!(StacksPublicKeyBuffer);
impl_byte_array_newtype!(StacksPublicKeyBuffer, u8, 33);
impl_byte_array_message_codec!(StacksPublicKeyBuffer, 33);
impl_byte_array_serde!(StacksPublicKeyBuffer);
impl StacksPublicKeyBuffer {
pub fn from_public_key(pubkey: &Secp256k1PublicKey) -> StacksPublicKeyBuffer {
let pubkey_bytes_vec = pubkey.to_bytes_compressed();
let mut pubkey_bytes = [0u8; 33];
pubkey_bytes.copy_from_slice(&pubkey_bytes_vec[..]);
StacksPublicKeyBuffer(pubkey_bytes)
}
pub fn to_public_key(&self) -> Result<Secp256k1PublicKey, &'static str> {
Secp256k1PublicKey::from_slice(&self.0)
.map_err(|_e_str| "Failed to decode Stacks public key")
}
}
pub trait PublicKey: Clone + fmt::Debug + serde::Serialize + serde::de::DeserializeOwned {
fn to_bytes(&self) -> Vec<u8>;
fn verify(&self, data_hash: &[u8], sig: &MessageSignature) -> Result<bool, &'static str>;
}
pub trait PrivateKey: Clone + fmt::Debug + serde::Serialize + serde::de::DeserializeOwned {
fn to_bytes(&self) -> Vec<u8>;
fn sign(&self, data_hash: &[u8]) -> Result<MessageSignature, &'static str>;
}
pub trait Address: Clone + fmt::Debug + fmt::Display {
fn to_bytes(&self) -> Vec<u8>;
fn from_string(from: &str) -> Option<Self>
where
Self: Sized;
fn is_burn(&self) -> bool;
}
pub const PEER_VERSION_EPOCH_1_0: u8 = 0x00;
pub const PEER_VERSION_EPOCH_2_0: u8 = 0x00;
pub const PEER_VERSION_EPOCH_2_05: u8 = 0x05;
pub const PEER_VERSION_EPOCH_2_1: u8 = 0x06;
#[repr(u32)]
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Copy, Serialize, Deserialize)]
pub enum StacksEpochId {
Epoch10 = 0x01000,
Epoch20 = 0x02000,
Epoch2_05 = 0x02005,
Epoch21 = 0x0200a,
Epoch22 = 0x0200f,
Epoch23 = 0x02014,
Epoch24 = 0x02019,
Epoch25 = 0x0201a,
Epoch30 = 0x03000,
}
impl StacksEpochId {
pub fn latest() -> StacksEpochId {
StacksEpochId::Epoch30
}
pub fn value_sanitizing(&self) -> bool {
match self {
StacksEpochId::Epoch10
| StacksEpochId::Epoch20
| StacksEpochId::Epoch2_05
| StacksEpochId::Epoch21
| StacksEpochId::Epoch22
| StacksEpochId::Epoch23 => false,
StacksEpochId::Epoch24 | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 => true,
}
}
}
impl std::fmt::Display for StacksEpochId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
StacksEpochId::Epoch10 => write!(f, "1.0"),
StacksEpochId::Epoch20 => write!(f, "2.0"),
StacksEpochId::Epoch2_05 => write!(f, "2.05"),
StacksEpochId::Epoch21 => write!(f, "2.1"),
StacksEpochId::Epoch22 => write!(f, "2.2"),
StacksEpochId::Epoch23 => write!(f, "2.3"),
StacksEpochId::Epoch24 => write!(f, "2.4"),
StacksEpochId::Epoch25 => write!(f, "2.5"),
StacksEpochId::Epoch30 => write!(f, "3.0"),
}
}
}
impl TryFrom<u32> for StacksEpochId {
type Error = &'static str;
fn try_from(value: u32) -> Result<StacksEpochId, Self::Error> {
match value {
x if x == StacksEpochId::Epoch10 as u32 => Ok(StacksEpochId::Epoch10),
x if x == StacksEpochId::Epoch20 as u32 => Ok(StacksEpochId::Epoch20),
x if x == StacksEpochId::Epoch2_05 as u32 => Ok(StacksEpochId::Epoch2_05),
x if x == StacksEpochId::Epoch21 as u32 => Ok(StacksEpochId::Epoch21),
x if x == StacksEpochId::Epoch22 as u32 => Ok(StacksEpochId::Epoch22),
x if x == StacksEpochId::Epoch23 as u32 => Ok(StacksEpochId::Epoch23),
x if x == StacksEpochId::Epoch24 as u32 => Ok(StacksEpochId::Epoch24),
x if x == StacksEpochId::Epoch25 as u32 => Ok(StacksEpochId::Epoch25),
x if x == StacksEpochId::Epoch30 as u32 => Ok(StacksEpochId::Epoch30),
_ => Err("Invalid epoch"),
}
}
}
impl PartialOrd for StacksAddress {
fn partial_cmp(&self, other: &StacksAddress) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for StacksAddress {
fn cmp(&self, other: &StacksAddress) -> Ordering {
match self.version.cmp(&other.version) {
Ordering::Equal => self.bytes.cmp(&other.bytes),
inequality => inequality,
}
}
}
impl StacksAddress {
pub fn new(version: u8, hash: Hash160) -> StacksAddress {
StacksAddress {
version,
bytes: hash,
}
}
pub fn is_mainnet(&self) -> bool {
match self.version {
C32_ADDRESS_VERSION_MAINNET_MULTISIG | C32_ADDRESS_VERSION_MAINNET_SINGLESIG => true,
C32_ADDRESS_VERSION_TESTNET_MULTISIG | C32_ADDRESS_VERSION_TESTNET_SINGLESIG => false,
_ => false,
}
}
pub fn burn_address(mainnet: bool) -> StacksAddress {
StacksAddress {
version: if mainnet {
C32_ADDRESS_VERSION_MAINNET_SINGLESIG
} else {
C32_ADDRESS_VERSION_TESTNET_SINGLESIG
},
bytes: Hash160([0u8; 20]),
}
}
pub fn from_public_keys(
version: u8,
hash_mode: &AddressHashMode,
num_sigs: usize,
pubkeys: &Vec<StacksPublicKey>,
) -> Option<StacksAddress> {
if pubkeys.len() < num_sigs {
return None;
}
match *hash_mode {
AddressHashMode::SerializeP2PKH | AddressHashMode::SerializeP2WPKH => {
if num_sigs != 1 || pubkeys.len() != 1 {
return None;
}
}
_ => {}
}
match *hash_mode {
AddressHashMode::SerializeP2WPKH | AddressHashMode::SerializeP2WSH => {
for pubkey in pubkeys {
if !pubkey.compressed() {
return None;
}
}
}
_ => {}
}
let hash_bits = public_keys_to_address_hash(hash_mode, num_sigs, pubkeys);
Some(StacksAddress::new(version, hash_bits))
}
pub fn p2pkh(mainnet: bool, pubkey: &StacksPublicKey) -> StacksAddress {
let bytes = to_bits_p2pkh(pubkey);
Self::p2pkh_from_hash(mainnet, bytes)
}
pub fn p2pkh_from_hash(mainnet: bool, hash: Hash160) -> StacksAddress {
let version = if mainnet {
C32_ADDRESS_VERSION_MAINNET_SINGLESIG
} else {
C32_ADDRESS_VERSION_TESTNET_SINGLESIG
};
Self {
version,
bytes: hash,
}
}
}
impl std::fmt::Display for StacksAddress {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
c32_address(self.version, self.bytes.as_bytes())
.expect("Stacks version is not C32-encodable")
.fmt(f)
}
}
impl Address for StacksAddress {
fn to_bytes(&self) -> Vec<u8> {
self.bytes.as_bytes().to_vec()
}
fn from_string(s: &str) -> Option<StacksAddress> {
let (version, bytes) = match c32_address_decode(s) {
Ok((v, b)) => (v, b),
Err(_) => {
return None;
}
};
if bytes.len() != 20 {
return None;
}
let mut hash_bytes = [0u8; 20];
hash_bytes.copy_from_slice(&bytes[..]);
Some(StacksAddress {
version,
bytes: Hash160(hash_bytes),
})
}
fn is_burn(&self) -> bool {
self.bytes == Hash160([0u8; 20])
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
pub struct StacksEpoch<L> {
pub epoch_id: StacksEpochId,
pub start_height: u64,
pub end_height: u64,
pub block_limit: L,
pub network_epoch: u8,
}
impl<L> StacksEpoch<L> {
pub fn find_epoch(epochs: &[StacksEpoch<L>], height: u64) -> Option<usize> {
for (i, epoch) in epochs.iter().enumerate() {
if epoch.start_height <= height && height < epoch.end_height {
return Some(i);
}
}
None
}
pub fn find_epoch_by_id(epochs: &[StacksEpoch<L>], epoch_id: StacksEpochId) -> Option<usize> {
for (i, epoch) in epochs.iter().enumerate() {
if epoch.epoch_id == epoch_id {
return Some(i);
}
}
None
}
}
impl<L: PartialEq> PartialOrd for StacksEpoch<L> {
fn partial_cmp(&self, other: &StacksEpoch<L>) -> Option<Ordering> {
self.epoch_id.partial_cmp(&other.epoch_id)
}
}
impl<L: PartialEq + Eq> Ord for StacksEpoch<L> {
fn cmp(&self, other: &StacksEpoch<L>) -> Ordering {
self.epoch_id.cmp(&other.epoch_id)
}
}