use super::bitcoin::{TxIn, TxOut};
use crate::events::*;
use schemars::JsonSchema;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::fmt::Display;
use std::hash::{Hash, Hasher};
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct BlockIdentifier {
pub index: u64,
pub hash: String,
}
impl Display for BlockIdentifier {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"Block #{} ({}...{})",
self.index,
&self.hash.as_str()[0..6],
&self.hash.as_str()[62..]
)
}
}
impl Hash for BlockIdentifier {
fn hash<H: Hasher>(&self, state: &mut H) {
self.hash.hash(state);
}
}
impl Ord for BlockIdentifier {
fn cmp(&self, other: &Self) -> Ordering {
(other.index, &other.hash).cmp(&(self.index, &self.hash))
}
}
impl PartialOrd for BlockIdentifier {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(other.cmp(self))
}
}
impl PartialEq for BlockIdentifier {
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash
}
}
impl Eq for BlockIdentifier {}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StacksBlockData {
pub block_identifier: BlockIdentifier,
pub parent_block_identifier: BlockIdentifier,
pub timestamp: i64,
pub transactions: Vec<StacksTransactionData>,
pub metadata: StacksBlockMetadata,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StacksMicroblockData {
pub block_identifier: BlockIdentifier,
pub parent_block_identifier: BlockIdentifier,
pub timestamp: i64,
pub transactions: Vec<StacksTransactionData>,
pub metadata: StacksMicroblockMetadata,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StacksMicroblockMetadata {
pub anchor_block_identifier: BlockIdentifier,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StacksMicroblocksTrail {
pub microblocks: Vec<StacksMicroblockData>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StacksBlockMetadata {
pub bitcoin_anchor_block_identifier: BlockIdentifier,
pub pox_cycle_index: u32,
pub pox_cycle_position: u32,
pub pox_cycle_length: u32,
pub confirm_microblock_identifier: Option<BlockIdentifier>,
pub stacks_block_hash: String,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct BitcoinBlockData {
pub block_identifier: BlockIdentifier,
pub parent_block_identifier: BlockIdentifier,
pub timestamp: u32,
pub transactions: Vec<BitcoinTransactionData>,
pub metadata: BitcoinBlockMetadata,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct BitcoinBlockMetadata {}
#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize, Serialize)]
pub struct Timestamp(i64);
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StacksTransactionData {
pub transaction_identifier: TransactionIdentifier,
pub operations: Vec<Operation>,
pub metadata: StacksTransactionMetadata,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(tag = "type", content = "data")]
pub enum StacksTransactionKind {
ContractCall(StacksContractCallData),
ContractDeployment(StacksContractDeploymentData),
NativeTokenTransfer,
Coinbase,
BitcoinOp(BitcoinOpData),
Unsupported,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(tag = "type", content = "data")]
pub enum BitcoinOpData {
StackSTX(StackSTXData),
DelegateStackSTX(DelegateStackSTXData),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StackSTXData {
pub locked_amount: String,
pub unlock_height: String,
pub stacking_address: String,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct DelegateStackSTXData {
pub stacking_address: String,
pub amount: String,
pub delegate: String,
pub pox_address: Option<String>,
pub unlock_height: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StacksContractCallData {
pub contract_identifier: String,
pub method: String,
pub args: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StacksContractDeploymentData {
pub contract_identifier: String,
pub code: String,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StacksTransactionMetadata {
pub success: bool,
pub raw_tx: String,
pub result: String,
pub sender: String,
pub nonce: u64,
pub fee: u64,
pub kind: StacksTransactionKind,
pub receipt: StacksTransactionReceipt,
pub description: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub sponsor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_cost: Option<StacksTransactionExecutionCost>,
pub position: StacksTransactionPosition,
pub proof: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum StacksTransactionPosition {
AnchorBlock(AnchorBlockPosition),
MicroBlock(MicroBlockPosition),
}
impl StacksTransactionPosition {
pub fn anchor_block(index: usize) -> StacksTransactionPosition {
StacksTransactionPosition::AnchorBlock(AnchorBlockPosition { index })
}
pub fn micro_block(
micro_block_identifier: BlockIdentifier,
index: usize,
) -> StacksTransactionPosition {
StacksTransactionPosition::MicroBlock(MicroBlockPosition {
micro_block_identifier,
index,
})
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct AnchorBlockPosition {
index: usize,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct MicroBlockPosition {
micro_block_identifier: BlockIdentifier,
index: usize,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct StacksTransactionExecutionCost {
pub write_length: u64,
pub write_count: u64,
pub read_length: u64,
pub read_count: u64,
pub runtime: u64,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
pub struct StacksTransactionReceipt {
pub mutated_contracts_radius: HashSet<String>,
pub mutated_assets_radius: HashSet<String>,
pub contract_calls_stack: HashSet<String>,
pub events: Vec<StacksTransactionEvent>,
}
impl StacksTransactionReceipt {
pub fn new(
mutated_contracts_radius: HashSet<String>,
mutated_assets_radius: HashSet<String>,
events: Vec<StacksTransactionEvent>,
) -> StacksTransactionReceipt {
StacksTransactionReceipt {
mutated_contracts_radius,
mutated_assets_radius,
contract_calls_stack: HashSet::new(),
events,
}
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct BitcoinTransactionData {
pub transaction_identifier: TransactionIdentifier,
pub operations: Vec<Operation>,
pub metadata: BitcoinTransactionMetadata,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct BitcoinTransactionMetadata {
pub inputs: Vec<TxIn>,
pub outputs: Vec<TxOut>,
pub stacks_operations: Vec<StacksBaseChainOperation>,
pub ordinal_operations: Vec<OrdinalOperation>,
pub proof: Option<String>,
pub fee: u64,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum OrdinalOperation {
InscriptionRevealed(OrdinalInscriptionRevealData),
InscriptionTransferred(OrdinalInscriptionTransferData),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct OrdinalInscriptionTransferData {
pub inscription_number: u64,
pub inscription_id: String,
pub ordinal_number: u64,
pub updated_address: Option<String>,
pub satpoint_pre_transfer: String,
pub satpoint_post_transfer: String,
pub post_transfer_output_value: Option<u64>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct OrdinalInscriptionRevealData {
pub content_bytes: String,
pub content_type: String,
pub content_length: usize,
pub inscription_number: u64,
pub inscription_fee: u64,
pub inscription_output_value: u64,
pub inscription_id: String,
pub inscriber_address: Option<String>,
pub ordinal_number: u64,
pub ordinal_block_height: u64,
pub ordinal_offset: u64,
pub transfers_pre_inscription: u32,
pub satpoint_post_inscription: String,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum StacksBaseChainOperation {
BlockCommitted(StacksBlockCommitmentData),
LeaderRegistered(KeyRegistrationData),
StxTransfered(TransferSTXData),
StxLocked(LockSTXData),
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct StacksBlockCommitmentData {
pub block_hash: String,
pub pox_cycle_index: u64,
pub pox_cycle_length: u64,
pub pox_cycle_position: u64,
pub pox_sats_burnt: u64,
pub pox_sats_transferred: Vec<PoxReward>,
pub mining_address_post_commit: Option<String>,
pub mining_sats_left: u64,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct PoxReward {
pub recipient_address: String,
pub amount: u64,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct KeyRegistrationData;
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct PobBlockCommitmentData {
pub signers: Vec<String>,
pub stacks_block_hash: String,
pub amount: u64,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct BlockCommitmentData {
pub stacks_block_hash: String,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct TransferSTXData {
pub sender: String,
pub recipient: String,
pub amount: String,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct LockSTXData {
pub sender: String,
pub amount: String,
pub duration: u64,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)]
pub struct TransactionIdentifier {
pub hash: String,
}
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, strum::EnumIter, strum::IntoStaticStr,
)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum OperationType {
Credit,
Debit,
Lock,
}
#[derive(Debug, Clone, Default, PartialEq, Deserialize, Serialize)]
pub struct OperationMetadata {
#[serde(skip_serializing_if = "Option::is_none")]
pub public_key: Option<PublicKey>,
#[serde(skip_serializing_if = "Option::is_none")]
pub code: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub method_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub args: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PublicKey {
pub hex_bytes: Option<String>,
pub curve_type: CurveType,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum CurveType {
Edwards25519,
Secp256k1,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Operation {
pub operation_identifier: OperationIdentifier,
#[serde(skip_serializing_if = "Option::is_none")]
pub related_operations: Option<Vec<OperationIdentifier>>,
#[serde(rename = "type")]
pub type_: OperationType,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<OperationStatusKind>,
pub account: AccountIdentifier,
#[serde(skip_serializing_if = "Option::is_none")]
pub amount: Option<Amount>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<OperationMetadata>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OperationIdentifier {
pub index: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub network_index: Option<i64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, strum::EnumIter)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum OperationStatusKind {
Success,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct AccountIdentifier {
pub address: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub sub_account: Option<SubAccountIdentifier>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct SubAccountIdentifier {
pub address: SubAccount,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum SubAccount {
LiquidBalanceForStorage,
Locked,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Amount {
pub value: u128,
pub currency: Currency,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Currency {
pub symbol: String,
pub decimals: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<CurrencyMetadata>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum CurrencyStandard {
Sip09,
Sip10,
None,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CurrencyMetadata {
pub asset_class_identifier: String,
pub asset_identifier: Option<String>,
pub standard: CurrencyStandard,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum BlockchainEvent {
BlockchainUpdatedWithHeaders(BlockchainUpdatedWithHeaders),
BlockchainUpdatedWithReorg(BlockchainUpdatedWithReorg),
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct BlockchainUpdatedWithHeaders {
pub new_headers: Vec<BlockHeader>,
pub confirmed_headers: Vec<BlockHeader>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct BlockchainUpdatedWithReorg {
pub headers_to_rollback: Vec<BlockHeader>,
pub headers_to_apply: Vec<BlockHeader>,
pub confirmed_headers: Vec<BlockHeader>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct BlockHeader {
pub block_identifier: BlockIdentifier,
pub parent_block_identifier: BlockIdentifier,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum BitcoinChainEvent {
ChainUpdatedWithBlocks(BitcoinChainUpdatedWithBlocksData),
ChainUpdatedWithReorg(BitcoinChainUpdatedWithReorgData),
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct BitcoinChainUpdatedWithBlocksData {
pub new_blocks: Vec<BitcoinBlockData>,
pub confirmed_blocks: Vec<BitcoinBlockData>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct BitcoinChainUpdatedWithReorgData {
pub blocks_to_rollback: Vec<BitcoinBlockData>,
pub blocks_to_apply: Vec<BitcoinBlockData>,
pub confirmed_blocks: Vec<BitcoinBlockData>,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum StacksChainEvent {
ChainUpdatedWithBlocks(StacksChainUpdatedWithBlocksData),
ChainUpdatedWithReorg(StacksChainUpdatedWithReorgData),
ChainUpdatedWithMicroblocks(StacksChainUpdatedWithMicroblocksData),
ChainUpdatedWithMicroblocksReorg(StacksChainUpdatedWithMicroblocksReorgData),
}
impl StacksChainEvent {
pub fn get_confirmed_blocks(self) -> Vec<StacksBlockData> {
match self {
StacksChainEvent::ChainUpdatedWithBlocks(event) => event.confirmed_blocks,
StacksChainEvent::ChainUpdatedWithReorg(event) => event.confirmed_blocks,
_ => vec![],
}
}
pub fn new_block(&self) -> Option<&StacksBlockData> {
match self {
StacksChainEvent::ChainUpdatedWithBlocks(event) => {
event.new_blocks.first().and_then(|b| Some(&b.block))
}
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct StacksBlockUpdate {
pub block: StacksBlockData,
pub parent_microblocks_to_rollback: Vec<StacksMicroblockData>,
pub parent_microblocks_to_apply: Vec<StacksMicroblockData>,
}
impl StacksBlockUpdate {
pub fn new(block: StacksBlockData) -> StacksBlockUpdate {
StacksBlockUpdate {
block,
parent_microblocks_to_rollback: vec![],
parent_microblocks_to_apply: vec![],
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct StacksChainUpdatedWithBlocksData {
pub new_blocks: Vec<StacksBlockUpdate>,
pub confirmed_blocks: Vec<StacksBlockData>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct StacksChainUpdatedWithReorgData {
pub blocks_to_rollback: Vec<StacksBlockUpdate>,
pub blocks_to_apply: Vec<StacksBlockUpdate>,
pub confirmed_blocks: Vec<StacksBlockData>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct StacksChainUpdatedWithMicroblocksData {
pub new_microblocks: Vec<StacksMicroblockData>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct StacksChainUpdatedWithMicroblocksReorgData {
pub microblocks_to_rollback: Vec<StacksMicroblockData>,
pub microblocks_to_apply: Vec<StacksMicroblockData>,
}
#[derive(
Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize, JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum StacksNetwork {
Simnet,
Devnet,
Testnet,
Mainnet,
}
impl StacksNetwork {
pub fn is_simnet(&self) -> bool {
match self {
StacksNetwork::Simnet => true,
_ => false,
}
}
pub fn is_testnet(&self) -> bool {
match self {
StacksNetwork::Testnet => true,
_ => false,
}
}
pub fn either_devnet_or_testnet(&self) -> bool {
match self {
StacksNetwork::Devnet | StacksNetwork::Testnet => true,
_ => false,
}
}
pub fn either_testnet_or_mainnet(&self) -> bool {
match self {
StacksNetwork::Mainnet | StacksNetwork::Testnet => true,
_ => false,
}
}
pub fn is_devnet(&self) -> bool {
match self {
StacksNetwork::Devnet => true,
_ => false,
}
}
pub fn is_mainnet(&self) -> bool {
match self {
StacksNetwork::Mainnet => true,
_ => false,
}
}
pub fn get_networks(&self) -> (BitcoinNetwork, StacksNetwork) {
match &self {
StacksNetwork::Simnet => (BitcoinNetwork::Regtest, StacksNetwork::Simnet),
StacksNetwork::Devnet => (BitcoinNetwork::Testnet, StacksNetwork::Devnet),
StacksNetwork::Testnet => (BitcoinNetwork::Testnet, StacksNetwork::Testnet),
StacksNetwork::Mainnet => (BitcoinNetwork::Mainnet, StacksNetwork::Mainnet),
}
}
}
#[allow(dead_code)]
#[derive(
Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum BitcoinNetwork {
Regtest,
Testnet,
Mainnet,
}
#[derive(Debug, Clone)]
pub enum BitcoinBlockSignaling {
Stacks(String),
ZeroMQ(String),
}
impl BitcoinBlockSignaling {
pub fn should_ignore_bitcoin_block_signaling_through_stacks(&self) -> bool {
match &self {
BitcoinBlockSignaling::Stacks(_) => false,
_ => true,
}
}
pub fn is_bitcoind_zmq_block_signaling_expected(&self) -> bool {
match &self {
BitcoinBlockSignaling::ZeroMQ(_) => false,
_ => true,
}
}
}