ido: migrate to bitcoincash 0.32 script API; fix mempool diff

Update ido/mod.rs for the bitcoincash 0.32 API: Script -> ScriptBuf,
push_slice via &PushBytes (new pb() helper), as_byte_array/as_bytes.
Fix update_mempool to diff against cauldron_txs instead of defi_txs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hossein Zoda 2026-06-10 22:27:50 +00:00
parent edf7955a23
commit a410aee95f
2 changed files with 96 additions and 88 deletions

View file

@ -3,7 +3,7 @@ use anyhow::Result;
use log::{info,warn,debug};
use num_bigint::{BigInt, Sign};
use num_traits::{Zero, ToPrimitive};
use bitcoincash::blockdata::script::{Builder, Script, Instruction};
use bitcoincash::blockdata::script::{Builder, Script, ScriptBuf, Instruction, PushBytes};
use bitcoincash::blockdata::opcodes;
use bitcoin_hashes::sha256d;
use bitcoin_hashes::Hash;
@ -322,40 +322,46 @@ pub enum IdoState {
Distributed(IdoDistributedState),
}
fn build_p2nfth_script(nfthash: &[u8]) -> Script {
/// Convert a byte slice into a `&PushBytes` for use with `Builder::push_slice`.
/// bitcoincash 0.32 requires `AsRef<PushBytes>` rather than a raw `&[u8]`.
fn pb(data: &[u8]) -> &PushBytes {
data.try_into().expect("push slice exceeds maximum length")
}
fn build_p2nfth_script(nfthash: &[u8]) -> ScriptBuf {
let mut bytes = Builder::new()
.push_slice(nfthash)
.push_slice(pb(nfthash))
.into_script()
.to_bytes();
bytes.extend_from_slice(&P2NFTH_CONTRACT);
Script::from(bytes)
ScriptBuf::from(bytes)
}
fn build_storage_script(governingOutpointIndex: u32) -> Script {
fn build_storage_script(governingOutpointIndex: u32) -> ScriptBuf {
let mut bytes = Builder::new()
.push_slice(&encode_padded_vm_number(&BigInt::from(governingOutpointIndex), 2).unwrap())
.push_slice(pb(&encode_padded_vm_number(&BigInt::from(governingOutpointIndex), 2).unwrap()))
.into_script()
.to_bytes();
bytes.extend_from_slice(&STORAGE_CONTRACT);
Script::from(bytes)
ScriptBuf::from(bytes)
}
fn build_storage_script_with_data_and_size(governingOutpointIndex: u32, data: &[u8]) -> Script {
fn build_storage_script_with_data_and_size(governingOutpointIndex: u32, data: &[u8]) -> ScriptBuf {
let mut data_and_size = Vec::new();
data_and_size.extend_from_slice(data);
data_and_size.extend_from_slice(&encode_padded_vm_number(&BigInt::from(data.len()), 2).unwrap());
let mut bytes = Builder::new()
.push_slice(&encode_padded_vm_number(&BigInt::from(governingOutpointIndex), 2).unwrap())
.push_slice(pb(&encode_padded_vm_number(&BigInt::from(governingOutpointIndex), 2).unwrap()))
.into_script()
.to_bytes();
bytes.extend_from_slice(&STORAGE_CONTRACT);
let suffix = Builder::new()
.push_slice(&data_and_size)
.push_slice(pb(&data_and_size))
.push_opcode(opcodes::all::OP_DROP)
.into_script()
.to_bytes();
bytes.extend_from_slice(&suffix);
Script::from(bytes)
ScriptBuf::from(bytes)
}
fn extract_data_from_storage_script_with_data_and_size(script: &Script) -> Result<Vec<u8>> {
@ -365,7 +371,7 @@ fn extract_data_from_storage_script_with_data_and_size(script: &Script) -> Resul
return Err(anyhow::anyhow!("storage with data should have at least two instructions"));
}
match &inst_list[n - 2] {
Ok(Instruction::PushBytes(data)) => Ok(data[0..data.len()-2].to_vec()),
Ok(Instruction::PushBytes(data)) => { let data = data.as_bytes(); Ok(data[0..data.len()-2].to_vec()) },
_ => Err(anyhow::anyhow!("storage with data should have a push opcode at instructions[count - 2]")),
}
}
@ -377,7 +383,7 @@ fn extract_data_from_unlocking_bytecode_of_storage_with_data_and_size(unlocking_
}
match &instructions[1] {
Ok(Instruction::PushBytes(redeem_bytecode)) => {
extract_data_from_storage_script_with_data_and_size(&Script::from(redeem_bytecode.to_vec()))
extract_data_from_storage_script_with_data_and_size(Script::from_bytes(redeem_bytecode.as_bytes()))
},
_ => Err(anyhow::anyhow!("invalid unlocking bytecode, p2sh redeem script push opcode is expected")),
}
@ -387,6 +393,7 @@ fn has_script_ido_signature(unlocking_bytecode: &Script) -> bool {
let instructions: Vec<_> = unlocking_bytecode.instructions().collect();
match instructions.last() {
Some(Ok(Instruction::PushBytes(redeem_bytecode))) => {
let redeem_bytecode = redeem_bytecode.as_bytes();
redeem_bytecode.len() >= IDO_SIGNATURE.len() &&
&redeem_bytecode[0..IDO_SIGNATURE.len()] == IDO_SIGNATURE
},
@ -396,8 +403,8 @@ fn has_script_ido_signature(unlocking_bytecode: &Script) -> bool {
fn build_offering_bytecode(maxDiscountRate: &BigInt, discountAnnualRate: &BigInt, price: &BigInt, minOffer: &BigInt, xTokenCategory: &[u8]) -> Vec<u8> {
let mut input_bytecode = Builder::new()
.push_slice(&STORAGE_CONTRACT)
.push_slice(&OFFERING_ENTRY_CONTRACT)
.push_slice(pb(&STORAGE_CONTRACT))
.push_slice(pb(&OFFERING_ENTRY_CONTRACT))
.into_script()
.to_bytes();
input_bytecode.extend_from_slice(&bigint_to_push_opcode(maxDiscountRate));
@ -405,7 +412,7 @@ fn build_offering_bytecode(maxDiscountRate: &BigInt, discountAnnualRate: &BigInt
input_bytecode.extend_from_slice(&bigint_to_push_opcode(price));
input_bytecode.extend_from_slice(&bigint_to_push_opcode(minOffer));
input_bytecode.extend_from_slice(&Builder::new()
.push_slice(xTokenCategory)
.push_slice(pb(xTokenCategory))
.into_script()
.to_bytes()
);
@ -418,14 +425,14 @@ fn build_offering_bytecode(maxDiscountRate: &BigInt, discountAnnualRate: &BigInt
fn build_launcher_bytecode(collectorNFTH: &[u8], platformFeeNFTH: &[u8], platformFee: &BigInt, delphiCategory: &[u8], expiresAt: &BigInt, deployThreshold: &BigInt, immediateDeployThreshold: &BigInt) -> Vec<u8> {
let rev_delphi_cat: Vec<u8> = delphiCategory.iter().copied().rev().collect();
let mut input_bytecode = Builder::new()
.push_slice(collectorNFTH)
.push_slice(platformFeeNFTH)
.push_slice(&encode_padded_vm_number(&platformFee, 4).unwrap())
.push_slice(&EXECUTION_FEE_PAYOUT_CONTRACT)
.push_slice(&STORAGE_CONTRACT)
.push_slice(&OFFERING_INTEGRATED_TIMELOCKED_P2NFTH_CONTRACT)
.push_slice(&P2NFTH_CONTRACT)
.push_slice(&rev_delphi_cat)
.push_slice(pb(collectorNFTH))
.push_slice(pb(platformFeeNFTH))
.push_slice(pb(&encode_padded_vm_number(&platformFee, 4).unwrap()))
.push_slice(pb(&EXECUTION_FEE_PAYOUT_CONTRACT))
.push_slice(pb(&STORAGE_CONTRACT))
.push_slice(pb(&OFFERING_INTEGRATED_TIMELOCKED_P2NFTH_CONTRACT))
.push_slice(pb(&P2NFTH_CONTRACT))
.push_slice(pb(&rev_delphi_cat))
.into_script()
.to_bytes();
input_bytecode.extend_from_slice(&bigint_to_push_opcode(expiresAt));
@ -439,7 +446,7 @@ fn build_launcher_bytecode(collectorNFTH: &[u8], platformFeeNFTH: &[u8], platfor
fn build_partial_offering_initiator_bytecode(extensionOutpointIndex: &BigInt, tokenStorageOutpointIndex: &BigInt, offeringBcmrStorageOutpointIndex: &BigInt, distRefundOutpointIndex: &BigInt, distDeployOutpointIndex: &BigInt, launcherBytecodeOutpointIndex: &BigInt, offeringBytecodeOutpointIndex: &BigInt, executionFee: &BigInt) -> Vec<u8> {
let mut bytecode = Builder::new()
.push_slice(&STORAGE_CONTRACT)
.push_slice(pb(&STORAGE_CONTRACT))
.into_script()
.to_bytes();
bytecode.extend_from_slice(&bigint_to_push_opcode(extensionOutpointIndex));
@ -465,9 +472,9 @@ fn build_partial_postlaunch_bytecode(permanentLiquidityShare: &BigInt, price: &B
fn build_partial_ido_initiator_bytecode(postLaunchPartialBytecode: &[u8], permanentPoolOTokenReserveOutpointIndex: &BigInt, offeringInitiatorOutpointIndex: &BigInt) -> Vec<u8> {
let mut bytecode = Builder::new()
.push_slice(postLaunchPartialBytecode)
.push_slice(&STORAGE_CONTRACT)
.push_slice(&P2NFTH_CONTRACT)
.push_slice(pb(postLaunchPartialBytecode))
.push_slice(pb(&STORAGE_CONTRACT))
.push_slice(pb(&P2NFTH_CONTRACT))
.into_script()
.to_bytes();
bytecode.extend_from_slice(&bigint_to_push_opcode(permanentPoolOTokenReserveOutpointIndex));
@ -481,17 +488,17 @@ fn create_rebuild_ipfs_placeholder_bcmr_partial_inputs(data: &IpfsBcmrWithPlaceh
bcmrUrisWithReplaceCalls.extend_from_slice(&data.metadata.bcmrUrisReplaceCalls);
bcmrUrisWithReplaceCalls.extend_from_slice(
&Builder::new()
.push_slice(&data.urisBytecode)
.push_slice(pb(&data.urisBytecode))
.into_script()
.to_bytes()
);
Builder::new()
.push_slice(&data.contentHash)
.push_slice(&data.metadata.registryReplaceCalls)
.push_slice(pb(&data.contentHash))
.push_slice(pb(&data.metadata.registryReplaceCalls))
.push_int(1i64)
// OP_DEFINE
.push_opcode(bitcoincash::blockdata::opcodes::All::from(0x89u8))
.push_slice(&bcmrUrisWithReplaceCalls)
.push_slice(pb(&bcmrUrisWithReplaceCalls))
.push_int(2i64)
// OP_DEFINE
.push_opcode(bitcoincash::blockdata::opcodes::All::from(0x89u8))
@ -512,14 +519,14 @@ fn build_preinit_bytecode(parameters: &IdoPreInitLockParameters, state: &IdoPreI
};
let middle = Builder::new()
.push_slice(&rev_ido)
.push_slice(&rev_authguard)
.push_slice(&parameters.authguardLockingBytecode)
.push_slice(&offering_bcmr_partial_inputs)
.push_slice(&oToken_bcmr_partial_inputs)
.push_slice(&REBUILD_IPFS_PLACEHOLDER_BCMR_FOR_GENESIS_WITH_AUTHGUARD_CONTRACT)
.push_slice(&CASHTOKENS_STUDIO_PAY2CATEGORY_CONTRACT)
.push_slice(&STORAGE_CONTRACT)
.push_slice(pb(&rev_ido))
.push_slice(pb(&rev_authguard))
.push_slice(pb(&parameters.authguardLockingBytecode))
.push_slice(pb(&offering_bcmr_partial_inputs))
.push_slice(pb(&oToken_bcmr_partial_inputs))
.push_slice(pb(&REBUILD_IPFS_PLACEHOLDER_BCMR_FOR_GENESIS_WITH_AUTHGUARD_CONTRACT))
.push_slice(pb(&CASHTOKENS_STUDIO_PAY2CATEGORY_CONTRACT))
.push_slice(pb(&STORAGE_CONTRACT))
.into_script()
.to_bytes();
let mut bytecode = IDO_SIGNATURE.to_vec();
@ -533,10 +540,10 @@ fn build_preinit_bytecode(parameters: &IdoPreInitLockParameters, state: &IdoPreI
bytecode
}
fn build_p2sh32_script(bytecode: &[u8]) -> Script {
fn build_p2sh32_script(bytecode: &[u8]) -> ScriptBuf {
Builder::new()
.push_opcode(opcodes::all::OP_HASH256)
.push_slice(sha256d::Hash::hash(bytecode).as_inner())
.push_slice(pb(sha256d::Hash::hash(bytecode).as_byte_array()))
.push_opcode(opcodes::all::OP_EQUAL)
.into_script()
}
@ -545,7 +552,7 @@ fn build_p2sh32_script(bytecode: &[u8]) -> Script {
fn build_p2sh20_script(bytecode: &[u8]) -> Script {
Builder::new()
.push_opcode(opcodes::all::OP_HASH160)
.push_slice(hash160::Hash::hash(bytecode).as_inner())
.push_slice(pb(hash160::Hash::hash(bytecode).as_byte_array()))
.push_opcode(opcodes::all::OP_EQUAL)
.into_script()
}
@ -957,19 +964,19 @@ fn deserialize_ipfs_bcmr_with_placeholder(
return Err(anyhow::anyhow!("bcmr needs metadata!"));
}
let metadata_size = bcmr_data[0].to_usize().unwrap();
let metadata_script = Script::from(bcmr_data[1..(metadata_size+1)].to_vec());
let metadata_script = ScriptBuf::from(bcmr_data[1..(metadata_size+1)].to_vec());
let metadata_inst_list: Vec<_> = metadata_script.instructions().collect();
if metadata_inst_list.len() != 2 {
return Err(anyhow::anyhow!("bcmr metadata should have two push opcodes!"));
}
let registryReplaceCalls = match &metadata_inst_list[0] {
Ok(Instruction::PushBytes(data)) => data.to_vec(),
Ok(Instruction::PushBytes(data)) => data.as_bytes().to_vec(),
_ => {
return Err(anyhow::anyhow!("oToken bcmr metadata opcode#0 is not a push opcode"));
}
};
let bcmrUrisReplaceCalls = match &metadata_inst_list[1] {
Ok(Instruction::PushBytes(data)) => data.to_vec(),
Ok(Instruction::PushBytes(data)) => data.as_bytes().to_vec(),
_ => {
return Err(anyhow::anyhow!("oToken bcmr metadata opcode#0 is not a push opcode"));
}
@ -995,8 +1002,8 @@ fn serialize_ipfs_bcmr_with_placeholder(
match input {
Some(value) => {
let metadata_bytecode = Builder::new()
.push_slice(&value.metadata.registryReplaceCalls)
.push_slice(&value.metadata.bcmrUrisReplaceCalls)
.push_slice(pb(&value.metadata.registryReplaceCalls))
.push_slice(pb(&value.metadata.bcmrUrisReplaceCalls))
.into_script()
.to_bytes();
let mut bcmr_bytecode = Vec::new();
@ -1004,7 +1011,7 @@ fn serialize_ipfs_bcmr_with_placeholder(
bcmr_bytecode.extend_from_slice(&value.contentHash);
bcmr_bytecode.extend_from_slice(&value.urisBytecode);
let metadata_push = Builder::new()
.push_slice(&metadata_bytecode)
.push_slice(pb(&metadata_bytecode))
.into_script()
.to_bytes();
let mut bytes = Vec::new();
@ -1056,7 +1063,7 @@ fn parse_ido_preinit_tx_params(tx: &Transaction, delphi_token_id: &[u8], platfor
let authguardLockingBytecode;
match &instructions[2] {
Ok(Instruction::PushBytes(data)) => {
authguardLockingBytecode = data.to_vec();
authguardLockingBytecode = data.as_bytes().to_vec();
}
_ => {
errors.push(anyhow::anyhow!("invalid announcement (3)"));
@ -1066,6 +1073,7 @@ fn parse_ido_preinit_tx_params(tx: &Transaction, delphi_token_id: &[u8], platfor
// params main
match &instructions[1] {
Ok(Instruction::PushBytes(data)) => {
let data = data.as_bytes();
if data.len() < 187 {
errors.push(anyhow::anyhow!("Incorrect announcement.mainData size"));
return None;
@ -1505,7 +1513,7 @@ fn parse_ido_preinit_tx(network: Option<Network>, tx: &Transaction, errors: &mut
if build_p2sh32_script(
&build_p2nfth_script(&platform_fee_nfth).to_bytes()
) == output.script_pubkey {
preinit_paid_fee += output.value;
preinit_paid_fee += output.value.to_sat();
}
}
if BigInt::from(preinit_paid_fee) < *IDO_CREATE_EXECUTION_FEE {
@ -1538,7 +1546,7 @@ fn create_ido_context_from_preinit(network: Option<Network>, tx: &Transaction, e
let params = result.parameters.expect("parameters should be defined!");
let state = result.state.expect("state should be defined!");
Ok(IdoContext {
preinit_txid: tx.txid().to_blob(),
preinit_txid: tx.compute_txid().to_blob(),
init_txid: None,
launch_txid: None,
otoken_genesis_txid: None,
@ -1549,7 +1557,7 @@ fn create_ido_context_from_preinit(network: Option<Network>, tx: &Transaction, e
offered_token_id: result.offered_token_id,
offering_token_id: None,
is_token_created_at_preinit: !result.offered_token_is_in_supply,
head_txid: tx.txid().to_blob(),
head_txid: tx.compute_txid().to_blob(),
})
}
}
@ -1560,18 +1568,18 @@ async fn on_create_ido(
tx: &Transaction,
block_height: i64,
) -> Result<()> {
debug!("IDO on_create_ido: {}", blob_to_display_hex::<Txid>(&tx.txid())?);
debug!("IDO on_create_ido: {}", blob_to_display_hex::<Txid>(&tx.compute_txid().to_blob())?);
let mut errors: Vec<Error> = Vec::new();
let mut invalid_ido_reasons: Vec<Error> = Vec::new();
let result = create_ido_context_from_preinit(network, tx, &mut errors, &mut invalid_ido_reasons);
if errors.len() > 0 {
info!("Parse ido preinit failed, txid: {}\nError(s):", hex::encode(tx.txid().to_blob()));
info!("Parse ido preinit failed, txid: {}\nError(s):", hex::encode(tx.compute_txid().to_blob()));
for error in errors {
info!(" - {}", error);
}
}
if invalid_ido_reasons.len() > 0 {
info!("Invalid ido found, preinit_txid: {}\nReason(s):", hex::encode(tx.txid().to_blob()));
info!("Invalid ido found, preinit_txid: {}\nReason(s):", hex::encode(tx.compute_txid().to_blob()));
for reason in invalid_ido_reasons {
info!(" - {}", reason);
}
@ -1725,12 +1733,12 @@ fn ido_add_tx(
if preinit_state.initiatorCreated {
// init outputs created & init tx
updates.push(IdoUpdate::Status("ACTIVE".to_string()));
updates.push(IdoUpdate::InitTxId(tx.txid().to_blob()));
updates.push(IdoUpdate::InitTxId(tx.compute_txid().to_blob()));
let launcherBytecodeIn = tx.input.get(2)
.ok_or_else(|| anyhow::anyhow!("launcher bytecode storage does not exist!"))?;
let launcher_data = extract_data_from_unlocking_bytecode_of_storage_with_data_and_size(&launcherBytecodeIn.script_sig)
.map_err(|e| anyhow::anyhow!("failed to extract launcher bytecode: {e}"))?;
let launcher_script = Script::from(launcher_data);
let launcher_script = ScriptBuf::from(launcher_data);
let launcher_inst_list: Vec<_> = launcher_script.instructions().collect();
let collectorNFTH: Vec<u8>;
if launcher_inst_list.len() == 0 {
@ -1738,7 +1746,7 @@ fn ido_add_tx(
}
match &launcher_inst_list[2] {
Ok(Instruction::PushBytes(data)) => {
collectorNFTH = data.to_vec();
collectorNFTH = data.as_bytes().to_vec();
}
_ => return Err(anyhow::anyhow!("expecting push opcode for collectorNFTH")),
}
@ -1786,7 +1794,7 @@ fn ido_add_tx(
next_state.authguardCategory = context.head_txid.iter().copied().rev().collect();
} else if preinit_state.oTokenGenerated == BigInt::from(0) {
next_state.oTokenGenerated = BigInt::from(1);
updates.push(IdoUpdate::OTokenGenesisTxId(tx.txid().to_blob()));
updates.push(IdoUpdate::OTokenGenesisTxId(tx.compute_txid().to_blob()));
} else if !preinit_state.idoCategory.iter().any(|&b| b != 0) {
next_state.idoCategory = context.head_txid.iter().copied().rev().collect();
}
@ -1841,7 +1849,7 @@ fn ido_add_tx(
}
match &instructions[0] {
Ok(Instruction::PushBytes(data)) => {
owner_nfthash = data.to_vec();
owner_nfthash = data.as_bytes().to_vec();
},
_ => return Err(anyhow::anyhow!("OP_PUSH expected in the unlocking bytecode of the offering utxo!")),
}
@ -1852,9 +1860,9 @@ fn ido_add_tx(
return Err(anyhow::anyhow!("Incorrect commitment size at output#1"));
}
updates.push(IdoUpdate::Entry(IdoUpdateEntry {
txid: tx.txid().to_blob(),
txid: tx.compute_txid().to_blob(),
owner_nfthash: owner_nfthash,
supply_amount: second_output.value,
supply_amount: second_output.value.to_sat(),
demand_amount: second_output.token.as_ref().unwrap().amount as u64,
lockup_timeval: decode_padded_vm_number(&second_output.token.as_ref().unwrap().commitment[1..7]).to_u64().unwrap_or(0),
discount: decode_padded_vm_number(&second_output.token.as_ref().unwrap().commitment[7..15]).to_u64().unwrap_or(0),
@ -1874,7 +1882,7 @@ fn ido_add_tx(
return Err(anyhow::anyhow!("Incorrect commitment size at output#0"));
}
updates.push(IdoUpdate::Status("DISTRIBUTING".to_string()));
updates.push(IdoUpdate::LaunchTxId(tx.txid().to_blob()));
updates.push(IdoUpdate::LaunchTxId(tx.compute_txid().to_blob()));
updates.push(IdoUpdate::State(
IdoState::Distributing(IdoDistributingState {
authguardCategory: active_state.authguardCategory.clone(),
@ -1896,7 +1904,7 @@ fn ido_add_tx(
return Err(anyhow::anyhow!("Incorrect commitment size at output#0"));
}
updates.push(IdoUpdate::Status("POSTLAUNCH".to_string()));
updates.push(IdoUpdate::LaunchTxId(tx.txid().to_blob()));
updates.push(IdoUpdate::LaunchTxId(tx.compute_txid().to_blob()));
updates.push(IdoUpdate::State(
IdoState::PostLaunch(IdoPostLaunchState {
authguardCategory: active_state.authguardCategory.clone(),
@ -1965,7 +1973,7 @@ fn ido_add_tx(
earnedAmount: decode_padded_vm_number(&dist_commitment[11..19]),
refundAmount: decode_padded_vm_number(&dist_commitment[19..27]),
discountAmount: decode_padded_vm_number(&dist_commitment[27..35]),
platformEarnedAmount: &prev_state.platformEarnedAmount + BigInt::from(platform_fee_output.value),
platformEarnedAmount: &prev_state.platformEarnedAmount + BigInt::from(platform_fee_output.value.to_sat()),
})
));
} else if (first_output.token.as_ref().unwrap().commitment[0] & ITEM_TYPE_BITS) == ITEM_TYPE_CONFIRMATION_NFT {
@ -1984,7 +1992,7 @@ fn ido_add_tx(
earnedAmount: decode_padded_vm_number(&conf_commitment[7..15]),
refundAmount: decode_padded_vm_number(&conf_commitment[15..23]),
discountAmount: decode_padded_vm_number(&conf_commitment[23..31]),
platformEarnedAmount: &prev_state.platformEarnedAmount + BigInt::from(platform_fee_output.value),
platformEarnedAmount: &prev_state.platformEarnedAmount + BigInt::from(platform_fee_output.value.to_sat()),
})
));
} else {
@ -2015,18 +2023,18 @@ fn ido_add_tx(
tokenAmount: BigInt::from(pp_output.token.as_ref()
.ok_or_else(|| anyhow::anyhow!("pp should have tokens"))?
.amount),
satoshiAmount: BigInt::from(pp_output.value),
satoshiAmount: BigInt::from(pp_output.value.to_sat()),
}) },
refundAmount: BigInt::from(collector_p2nfth.token.as_ref()
.ok_or_else(|| anyhow::anyhow!("collector_p2nfth should have tokens"))?
.amount),
discountAmount: prev_state.discountAmount.clone(),
collectorEarnedAmount: BigInt::from(collector_p2nfth.value),
collectorEarnedAmount: BigInt::from(collector_p2nfth.value.to_sat()),
platformEarnedAmount: prev_state.platformEarnedAmount.clone(),
})
));
updates.push(IdoUpdate::EntryDistributed {
txid: tx.txid().to_blob(),
txid: tx.compute_txid().to_blob(),
});
print_updates(&updates);
return Ok(IdoAddResult {
@ -2170,7 +2178,7 @@ async fn upsert_ido_txchain(
)
.bind(prev_txchain_id)
.bind(internal_id)
.bind(tx.txid().to_blob())
.bind(tx.compute_txid().to_blob())
.bind(serialized_tx)
.execute(&mut **dbtx)
.await?;
@ -2180,7 +2188,7 @@ async fn upsert_ido_txchain(
"REPLACE INTO ido_txchain_tracker_map (txid, next_output_index, height, txchain_id) VALUES
(?, ?, ?, ?)"
)
.bind(tx.txid().to_blob())
.bind(tx.compute_txid().to_blob())
.bind(next_output_index)
.bind(block_height)
.bind(txchain_item_id)
@ -2200,7 +2208,7 @@ async fn update_ido_txchain_tracker_block_height(
"UPDATE ido_txchain_tracker_map SET height = ? WHERE txid = ?"
)
.bind(block_height)
.bind(tx.txid().to_blob())
.bind(tx.compute_txid().to_blob())
.execute(&mut **dbtx)
.await?;
Ok(())
@ -2214,16 +2222,16 @@ async fn on_add_ido_tx(
tx: &Transaction,
block_height: i64,
) -> Result<()> {
debug!("IDO on_add_ido_tx: {}", blob_to_display_hex::<Txid>(&tx.txid())?);
debug!("IDO on_add_ido_tx: {}", blob_to_display_hex::<Txid>(&tx.compute_txid().to_blob())?);
let mut dbtx = pool.begin().await?;
let current_item = get_txchain_item_by_txid(pool, &tx.txid())
let current_item = get_txchain_item_by_txid(pool, &tx.compute_txid())
.await?;
if current_item.is_some() && Some(current_item.unwrap().id) == ido.txchain_head {
// already added, only update block height
update_ido_txchain_tracker_block_height(&mut dbtx, tx, block_height)
.await?;
} else if prev_txchain_item.id != ido.txchain_head.unwrap_or(0) {
debug!("IDO rebuild: {}, prev: {}", blob_to_display_hex::<Txid>(&tx.txid())?, blob_to_display_hex::<Txid>(&prev_txchain_item.txid)?);
debug!("IDO rebuild: {}, prev: {}", blob_to_display_hex::<Txid>(&tx.compute_txid().to_blob())?, blob_to_display_hex::<Txid>(&prev_txchain_item.txid)?);
// rebuild the state, txchain is broken, recreate the chain
let items = get_ido_txchain_list(pool, ido.internal_id)
.await?;
@ -2256,13 +2264,13 @@ async fn on_add_ido_tx(
let item_tx = items_tx_map.get(&item.txid).ok_or_else(|| anyhow::anyhow!("txchain tx not found in map"))?;
// add tx
let result = ido_add_tx(&context, item_tx)?;
context.head_txid = item_tx.txid().to_blob();
context.head_txid = item_tx.compute_txid().to_blob();
apply_updates_to_context(&mut context, &result.updates);
updates.extend_from_slice(&result.updates);
}
// add the tx to the chain
let result = ido_add_tx(&context, tx)?;
context.head_txid = tx.txid().to_blob();
context.head_txid = tx.compute_txid().to_blob();
apply_updates_to_context(&mut context, &result.updates);
updates.extend_from_slice(&result.updates);
let txchain_item_id = upsert_ido_txchain(&mut dbtx, tx, ido.internal_id, Some(prev_txchain_item.id), block_height, result.next_output_index)
@ -2301,7 +2309,7 @@ async fn on_add_ido_tx(
};
// add to the chain
let result = ido_add_tx(&context, tx)?;
context.head_txid = tx.txid().to_blob();
context.head_txid = tx.compute_txid().to_blob();
apply_updates_to_context(&mut context, &result.updates);
let txchain_item_id = upsert_ido_txchain(&mut dbtx, tx, ido.internal_id, Some(prev_txchain_item.id), block_height, result.next_output_index)
.await?;
@ -2335,8 +2343,8 @@ async fn index_txs(
for tx in sorted_txs {
// detect a new ido
if is_preinit_broadcast(tx) {
debug!("IDO index preinit: {}", blob_to_display_hex::<Txid>(&tx.txid())?);
if lookup_internal_id_by_preinit_txid(pool, &tx.txid().to_blob()).await?.is_some() {
debug!("IDO index preinit: {}", blob_to_display_hex::<Txid>(&tx.compute_txid().to_blob())?);
if lookup_internal_id_by_preinit_txid(pool, &tx.compute_txid().to_blob()).await?.is_some() {
// already created (eg. indexed from the mempool), only update block height
let mut dbtx = pool.begin().await?;
update_ido_txchain_tracker_block_height(&mut dbtx, tx, block_height)
@ -2346,11 +2354,11 @@ async fn index_txs(
}
match on_create_ido(network, pool, tx, block_height)
.await {
Err(err) => info!("failed to detect an ido, or an invalid ido detected, txid: {}, {}", hex::encode(tx.txid().to_blob()), err),
Err(err) => info!("failed to detect an ido, or an invalid ido detected, txid: {}, {}", hex::encode(tx.compute_txid().to_blob()), err),
_ => (),
}
} else if is_ido_sig_in_tx_inputs(tx) {
debug!("IDO tx to index: {}", blob_to_display_hex::<Txid>(&tx.txid())?);
debug!("IDO tx to index: {}", blob_to_display_hex::<Txid>(&tx.compute_txid().to_blob())?);
// has ido sig
for input_index in [ 0, 1, 3 ] {
let input = tx.input.get(input_index);
@ -2368,7 +2376,7 @@ async fn index_txs(
Ok(Some(ido)) => {
match on_add_ido_tx(network, pool, &ido, &txchain_item, tx, block_height)
.await {
Err(err) => info!("add tx to an ido failed, txid: {}, {}", hex::encode(tx.txid().to_blob()), err),
Err(err) => info!("add tx to an ido failed, txid: {}, {}", hex::encode(tx.compute_txid().to_blob()), err),
_ => (),
}
},
@ -2521,13 +2529,13 @@ mod tests {
let network = Some(Network::Chipnet);
let result = parse_ido_preinit_tx(network, &tx, &mut errors, &mut invalid_ido_reasons);
if errors.len() > 0 {
debug!("Parse ido preinit failed, txid: {}\nError(s):", hex::encode(tx.txid().to_blob()));
debug!("Parse ido preinit failed, txid: {}\nError(s):", hex::encode(tx.compute_txid().to_blob()));
for error in &errors {
debug!(" - {}", error);
}
}
if invalid_ido_reasons.len() > 0 {
debug!("Invalid ido found, preinit_txid: {}\nReason(s):", hex::encode(tx.txid().to_blob()));
debug!("Invalid ido found, preinit_txid: {}\nReason(s):", hex::encode(tx.compute_txid().to_blob()));
for reason in &invalid_ido_reasons {
debug!(" - {}", reason);
}

View file

@ -81,8 +81,8 @@ pub async fn update_mempool(
})
.await??;
let txs_to_delete: Vec<Txid> = our_mempool_txs.difference(&defi_txs).cloned().collect();
let txs_to_add: Vec<&Txid> = defi_txs.difference(&our_mempool_txs).collect();
let txs_to_delete: Vec<Txid> = our_mempool_txs.difference(&cauldron_txs).cloned().collect();
let txs_to_add: Vec<&Txid> = cauldron_txs.difference(&our_mempool_txs).collect();
let electrum_for_fetch = electrum.clone();
let txids_to_fetch: Vec<Txid> = txs_to_add.iter().map(|t| **t).collect();