-
Notifications
You must be signed in to change notification settings - Fork 226
Description
When creating and signing a SegWit (Bech32) transaction on Bitcoin Testnet using bitcoinlib,
the transaction broadcast succeeds with one mnemonic phrase,
but fails with "bad-txns-inputs-missingorspent" when using another mnemonic —
even though the UTXO is valid and the derived SegWit address perfectly matches.
Code that works
from bitcoinlib.keys import HDKey
from bitcoinlib.transactions import Transaction
=== Create private key from mnemonic phrase ===
phrase = 'merit tattoo fish response jar churn pear ski weekend ugly feature public'
k = HDKey().from_passphrase(phrase, network='testnet4')
def create_native_segwit_offline_transaction(prev_txid, prev_output_index, prev_output_value,
from_privkey, to_address, send_value, network='testnet4'):
# 建立 segwit 交易
tx = Transaction(network=network, witness_type='segwit')
# 加入輸入 (UTXO)
tx.add_input(prev_txid, prev_output_index, keys=[from_privkey],
value=prev_output_value, witness_type='segwit')
# 加入輸出 (要轉給誰)
tx.add_output(send_value, to_address)
# 簽名並更新交易
tx.sign_and_update()
tx.verify()
# 回傳原始交易 hex
return tx.as_hex()
=== 測試資料 ===
network = 'testnet4'
prev_txid = 'b759ffc1c3b85814ecb8f9333b6dc9329673db1cd02397612824a795a0022d18'
prev_output_index = 1
prev_output_value = 185046 # 0.00185046 BTC
to_address = '
'
send_value = 1000 # satoshis
from_privkey = k
=== 建立交易 ===
raw_tx_hex = create_native_segwit_offline_transaction(
prev_txid, prev_output_index, prev_output_value,
from_privkey, to_address, send_value, network
)
print("Raw transaction hex:")
print(raw_tx_hex)
Code that fails
from bitcoinlib.keys import HDKey
from bitcoinlib.transactions import Transaction
=== Create private key from mnemonic phrase ===
phrase = 'apology ridge roof conduct orchard miss horse frequent damage shock jewel rescue'
k = HDKey().from_passphrase(phrase, network='testnet')
def create_native_segwit_offline_transaction(prev_txid, prev_output_index, prev_output_value,
from_privkey, to_address, send_value, network='testnet'):
# 建立 segwit 交易
tx = Transaction(network=network, witness_type='segwit')
# 加入輸入 (UTXO)
tx.add_input(prev_txid, prev_output_index, keys=[from_privkey],
value=prev_output_value, witness_type='segwit')
# 加入輸出 (要轉給誰)
tx.add_output(send_value, to_address)
# 簽名並更新交易
tx.sign_and_update()
tx.verify()
# 回傳原始交易 hex
return tx.as_hex()
=== 測試資料 ===
network = 'testnet'
prev_txid = 'd3fe9e674593ed693af7b21cf6e3d4ab6c9ee6646b2ce70cd4349f72ee9ccb95'
prev_output_index = 1
prev_output_value = 156661 # 0.00156661BTC
to_address = 'tb1qnmk0wazls8khuf0tkl9enx32l5krcua94jhlf6'
send_value = 1000 # satoshis
from_privkey = k
=== 建立交易 ===
raw_tx_hex = create_native_segwit_offline_transaction(
prev_txid, prev_output_index, prev_output_value,
from_privkey, to_address, send_value, network
)
print("Raw transaction hex:")
print(raw_tx_hex)
Broadcast fails
Error:
Failed to broadcast transaction, reason: bad-txns-inputs-missingorspent
Verification
I confirmed that:
The UTXO d3fe9e674593ed693af7b21cf6e3d4ab6c9ee6646b2ce70cd4349f72ee9ccb95:0
is valid and unspent (confirmed balance 0.00156661 tBTC).
The mnemonic-derived address is correct:
✅ Derived address: tb1q0kmuhh5f63vj5jw8cl7w0dg06a4fxujke7adfv
🔍 Blockchain address: tb1q0kmuhh5f63vj5jw8cl7w0dg06a4fxujke7adfv
🎉 Match confirmed
Mnemonic–Address Verification Code
from bip_utils import (
Bip39SeedGenerator,
Bip84,
Bip84Coins,
Bip39MnemonicValidator,
Bip39Languages,
Bip44Changes
)
import sys
=== Input: mnemonic phrase and address to verify ===
MNEMONIC = "apology ridge roof conduct orchard miss horse frequent damage shock jewel rescue"
ADDRESS_TO_VERIFY = "tb1q0kmuhh5f63vj5jw8cl7w0dg06a4fxujke7adfv"
=== Validate that the mnemonic is a valid BIP39 English phrase ===
if not Bip39MnemonicValidator(Bip39Languages.ENGLISH).IsValid(MNEMONIC):
print("❌ Invalid mnemonic! Please make sure it is a valid English BIP39 mnemonic.")
sys.exit(1)
=== Generate seed from mnemonic and create a BIP84 (SegWit) wallet for Bitcoin Testnet ===
seed_bytes = Bip39SeedGenerator(MNEMONIC).Generate()
bip84_ctx = Bip84.FromSeed(seed_bytes, Bip84Coins.BITCOIN_TESTNET)
=== Derive the first address (m/84'/1'/0'/0/0) ===
addr_obj = bip84_ctx.Purpose().Coin().Account(0).Change(Bip44Changes.CHAIN_EXT).AddressIndex(0)
derived_addr = addr_obj.PublicKey().ToAddress()
=== Compare the derived address with the one provided ===
print(f"✅ Derived SegWit address from mnemonic: {derived_addr}")
print(f"🔍 Address to verify: {ADDRESS_TO_VERIFY}")
if derived_addr == ADDRESS_TO_VERIFY:
print("\n🎉 Verification successful: the mnemonic and the SegWit Testnet address match perfectly!")
print("👉 This confirms that the given mnemonic correctly generates the specified Bitcoin Testnet address.")
else:
print("\n
print("👉 Please double-check your mnemonic or the derivation path (e.g., m/84'/1'/0'/0/0).")
output
output like this if everything matches:
✅ Derived SegWit address from mnemonic: tb1q0kmuhh5f63vj5jw8cl7w0dg06a4fxujke7adfv
🔍 Address to verify: tb1q0kmuhh5f63vj5jw8cl7w0dg06a4fxujke7adfv
🎉 Verification successful: the mnemonic and the SegWit Testnet address match perfectly!
👉 This confirms that the given mnemonic correctly generates the specified Bitcoin Testnet address.
Question
How can I fix the issue where the transaction can be broadcast successfully with one mnemonic and address, but fails to broadcast when using a different mnemonic and address, even though:
the UTXO is correct,
and the mnemonic and address are verified to match (using the verification code above)?