mirror of
https://github.com/alexgo-io/bitcoin-indexer.git
synced 2026-01-12 22:43:06 +08:00
feat: re-approach stacks block commit schema
This commit is contained in:
@@ -536,33 +536,48 @@ pub struct PoxConfig {
|
||||
|
||||
impl PoxConfig {
|
||||
pub fn is_consensus_rewarding_participants_at_block_height(&self, block_height: u64) -> bool {
|
||||
(block_height.saturating_div(self.genesis_block_height) % self.get_pox_cycle_len())
|
||||
>= self.prepare_phase_len
|
||||
self.get_pos_in_pox_cycle(block_height) < self.reward_phase_len
|
||||
}
|
||||
|
||||
pub fn get_pox_cycle_len(&self) -> u64 {
|
||||
self.prepare_phase_len + self.reward_phase_len
|
||||
}
|
||||
|
||||
pub fn get_pox_cycle_id(&self, block_height: u64) -> u64 {
|
||||
(block_height.saturating_sub(self.genesis_block_height)) / self.get_pox_cycle_len()
|
||||
}
|
||||
|
||||
pub fn get_pos_in_pox_cycle(&self, block_height: u64) -> u64 {
|
||||
(block_height.saturating_sub(self.genesis_block_height)) % self.get_pox_cycle_len()
|
||||
}
|
||||
|
||||
pub fn get_burn_address(&self) -> &str {
|
||||
match self.genesis_block_height {
|
||||
666050 => "1111111111111111111114oLvT2",
|
||||
2000000 => "burn-address-regtest",
|
||||
_ => "burn-address",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const POX_CONFIG_MAINNET: PoxConfig = PoxConfig {
|
||||
genesis_block_height: 666050,
|
||||
prepare_phase_len: 2100,
|
||||
reward_phase_len: 100,
|
||||
prepare_phase_len: 100,
|
||||
reward_phase_len: 2100,
|
||||
rewarded_addresses_per_block: 2,
|
||||
};
|
||||
|
||||
const POX_CONFIG_TESTNET: PoxConfig = PoxConfig {
|
||||
genesis_block_height: 2000000,
|
||||
prepare_phase_len: 1050,
|
||||
reward_phase_len: 50,
|
||||
prepare_phase_len: 50,
|
||||
reward_phase_len: 1050,
|
||||
rewarded_addresses_per_block: 2,
|
||||
};
|
||||
|
||||
const POX_CONFIG_DEVNET: PoxConfig = PoxConfig {
|
||||
genesis_block_height: 100,
|
||||
prepare_phase_len: 10,
|
||||
reward_phase_len: 4,
|
||||
prepare_phase_len: 4,
|
||||
reward_phase_len: 10,
|
||||
rewarded_addresses_per_block: 2,
|
||||
};
|
||||
|
||||
|
||||
@@ -278,9 +278,14 @@ pub fn standardize_bitcoin_block(
|
||||
ctx.try_log(|logger| slog::debug!(logger, "Standardizing Bitcoin transaction {txid}"));
|
||||
|
||||
let mut stacks_operations = vec![];
|
||||
if let Some(op) =
|
||||
try_parse_stacks_operation(&tx.vout, &pox_config, &expected_magic_bytes, ctx)
|
||||
{
|
||||
if let Some(op) = try_parse_stacks_operation(
|
||||
block_height,
|
||||
&tx.vin,
|
||||
&tx.vout,
|
||||
&pox_config,
|
||||
&expected_magic_bytes,
|
||||
ctx,
|
||||
) {
|
||||
stacks_operations.push(op);
|
||||
}
|
||||
|
||||
@@ -440,6 +445,8 @@ fn try_parse_ordinal_operation(
|
||||
}
|
||||
|
||||
fn try_parse_stacks_operation(
|
||||
block_height: u64,
|
||||
inputs: &Vec<BitcoinTransactionInputFullBreakdown>,
|
||||
outputs: &Vec<BitcoinTransactionOutputFullBreakdown>,
|
||||
pox_config: &PoxConfig,
|
||||
expected_magic_bytes: &[u8; 2],
|
||||
@@ -492,34 +499,100 @@ fn try_parse_stacks_operation(
|
||||
}
|
||||
StacksOpcodes::BlockCommit => {
|
||||
let res = try_parse_block_commit_op(&op_return_output[5..])?;
|
||||
let mut pox_sats_burnt = 0;
|
||||
let mut pox_sats_transferred = vec![];
|
||||
|
||||
// We need to determine wether the transaction was a PoB or a Pox commitment
|
||||
// if pox_config.is_consensus_rewarding_participants_at_block_height(block_height) {
|
||||
if outputs.len() < 1 + pox_config.rewarded_addresses_per_block {
|
||||
return None;
|
||||
let mining_output_index = if pox_config
|
||||
.is_consensus_rewarding_participants_at_block_height(block_height)
|
||||
{
|
||||
// Output 0 is OP_RETURN
|
||||
// Output 1 is rewarding Address 1
|
||||
let pox_output_1 = outputs
|
||||
.get(1)
|
||||
.ok_or(format!("expected pox output 1 not found"))
|
||||
.ok()?;
|
||||
let pox_script_1 = pox_output_1
|
||||
.script_pub_key
|
||||
.script()
|
||||
.map_err(|_e| format!("expected pox output 1 corrupted"))
|
||||
.ok()?;
|
||||
let pox_address_1 = Address::from_script(&pox_script_1, bitcoin::Network::Bitcoin)
|
||||
.map_err(|_e| format!("expected pox output 1 corrupted"))
|
||||
.ok()?;
|
||||
if pox_address_1.to_string().eq(&pox_config.get_burn_address()) {
|
||||
pox_sats_burnt += pox_output_1.value.to_sat();
|
||||
} else {
|
||||
pox_sats_transferred.push(PoxReward {
|
||||
recipient_address: pox_address_1.to_string(),
|
||||
amount: pox_output_1.value.to_sat(),
|
||||
});
|
||||
}
|
||||
// Output 2 is rewarding Address 2
|
||||
let pox_output_2 = outputs
|
||||
.get(2)
|
||||
.ok_or(format!("expected pox output 2 not found"))
|
||||
.ok()?;
|
||||
let pox_script_2 = pox_output_2
|
||||
.script_pub_key
|
||||
.script()
|
||||
.map_err(|_e| format!("expected pox output 2 corrupted"))
|
||||
.ok()?;
|
||||
let pox_address_2 = Address::from_script(&pox_script_2, bitcoin::Network::Bitcoin)
|
||||
.map_err(|_e| format!("expected pox output 2 corrupted"))
|
||||
.ok()?;
|
||||
if pox_address_2.to_string().eq(&pox_config.get_burn_address()) {
|
||||
pox_sats_burnt += pox_output_2.value.to_sat();
|
||||
} else {
|
||||
pox_sats_transferred.push(PoxReward {
|
||||
recipient_address: pox_address_2.to_string(),
|
||||
amount: pox_output_2.value.to_sat(),
|
||||
});
|
||||
}
|
||||
// Output 3 is used for miner chained commitments
|
||||
3
|
||||
} else {
|
||||
// Output 0 is OP_RETURN
|
||||
// Output 1 should be a Burn Address
|
||||
let burn_output = outputs
|
||||
.get(1)
|
||||
.ok_or(format!("expected burn address not found"))
|
||||
.ok()?;
|
||||
// Todo: Ensure that we're looking at a burn address
|
||||
pox_sats_burnt += burn_output.value.to_sat();
|
||||
// Output 2 is used for miner chained commitments
|
||||
2
|
||||
};
|
||||
|
||||
let mut mining_sats_left = 0;
|
||||
let mut mining_address_post_commit = None;
|
||||
if let Some(mining_post_commit) = outputs.get(mining_output_index) {
|
||||
mining_sats_left = mining_post_commit.value.to_sat();
|
||||
mining_address_post_commit = match mining_post_commit.script_pub_key.script() {
|
||||
Ok(script) => Address::from_script(&script, bitcoin::Network::Bitcoin)
|
||||
.and_then(|a| Ok(a.to_string()))
|
||||
.ok(),
|
||||
Err(_) => None,
|
||||
};
|
||||
}
|
||||
let mut rewards = vec![];
|
||||
for output in outputs[1..pox_config.rewarded_addresses_per_block].into_iter() {
|
||||
rewards.push(PoxReward {
|
||||
recipient: format!("0x{}", hex::encode(&output.script_pub_key.hex)),
|
||||
amount: output.value.to_sat(),
|
||||
});
|
||||
}
|
||||
StacksBaseChainOperation::BlockCommitted(StacksBlockCommitmentData {
|
||||
signers: vec![], // todo(lgalabru)
|
||||
stacks_block_hash: res.stacks_block_hash.clone(),
|
||||
rewards,
|
||||
})
|
||||
// } else {
|
||||
// if outputs.len() < 2 {
|
||||
// return None;
|
||||
// }
|
||||
// let amount = outputs[1].value;
|
||||
// StacksBaseChainOperation::BlockCommitted(StacksBlockCommitmentData {
|
||||
// signers: vec![], // todo(lgalabru)
|
||||
// stacks_block_hash: res.stacks_block_hash.clone(),
|
||||
// amount: amount.to_sat(),
|
||||
// })
|
||||
// }
|
||||
|
||||
let pox_cycle_id = pox_config.get_pox_cycle_id(block_height);
|
||||
let pox_cycle_len = pox_config.get_pox_cycle_len();
|
||||
let pox_cycle_pos = pox_config.get_pos_in_pox_cycle(block_height);
|
||||
|
||||
StacksBaseChainOperation::BlockCommitted(StacksBlockCommitmentData {
|
||||
block_hash: res.stacks_block_hash,
|
||||
pox_cycle_id,
|
||||
pox_cycle_len,
|
||||
pox_cycle_pos,
|
||||
pox_sats_burnt,
|
||||
pox_sats_transferred,
|
||||
mining_address_pre_commit: None,
|
||||
mining_address_post_commit,
|
||||
mining_sats_left,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -308,6 +308,7 @@ pub struct OrdinalInscriptionRevealData {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum StacksBaseChainOperation {
|
||||
BlockCommitted(StacksBlockCommitmentData),
|
||||
LeaderRegistered(KeyRegistrationData),
|
||||
@@ -316,15 +317,23 @@ pub enum StacksBaseChainOperation {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct StacksBlockCommitmentData {
|
||||
pub signers: Vec<String>,
|
||||
pub stacks_block_hash: String,
|
||||
pub rewards: Vec<PoxReward>,
|
||||
pub block_hash: String,
|
||||
pub pox_cycle_id: u64,
|
||||
pub pox_cycle_len: u64,
|
||||
pub pox_cycle_pos: u64,
|
||||
pub pox_sats_burnt: u64,
|
||||
pub pox_sats_transferred: Vec<PoxReward>,
|
||||
// pub mining_address_pre_commit: Option<String>,
|
||||
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: String,
|
||||
pub recipient_address: String,
|
||||
pub amount: u64,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user