- Prerequisites
- Environment Setup
- Testing Question 1 (P2PKH)
- Testing Question 2 (Custom Script)
- Testing Question 3 (Multisig)
- Testing Question 4 (Atomic Swap)
- Verification Methods
- Common Issues and Solutions
- Python 3.7 or higher
- pip package manager
- Internet connection for API calls
- BlockCypher account with API token (free tier is sufficient)
- Access to Bitcoin Testnet3 faucets
- Access to BCY Testnet faucets
# Check Python version
python --version # Should be 3.7+
# Check pip
pip --version
# Install dependencies
pip install -r requirements.txt
# Verify installation
python -c "import bitcoin; print('bitcoin-lib installed successfully')"
python -c "import requests; print('requests installed successfully')"For Questions 1-3, generate a Bitcoin testnet key pair:
cd lib/
python keygen.pyThis will output:
- Private key (Base58)
- Public key (hex)
- Address
Example output:
Private key: cTk4zH8F5zKxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Public key: 02f5d8axxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Address: mn6bEQxxxxxxxxxxxxxxxxxxxxxxxxx
Visit a Bitcoin testnet faucet and send coins to your address:
Wait for 1-3 confirmations (approximately 10-30 minutes).
Check your balance using BlockCypher:
curl https://api.blockcypher.com/v1/btc/test3/addrs/YOUR_ADDRESS/balanceEdit lib/config.py and add your private key:
my_private_key = CBitcoinSecret('YOUR_PRIVATE_KEY_FROM_KEYGEN')Test the standard Pay-To-Public-Key-Hash transaction implementation.
- Check your balance:
curl https://api.blockcypher.com/v1/btc/test3/addrs/$(python -c "from lib.config import my_address; print(my_address)")/balance- Get UTXO information:
curl https://api.blockcypher.com/v1/btc/test3/addrs/YOUR_ADDRESSLook for the txrefs array to find:
tx_hash: Your txid_to_spendtx_output_n: Your utxo_indexvalue: Amount in satoshis (divide by 100,000,000 for BTC)
- Update Q1.py parameters:
amount_to_send = 0.00099 # Your UTXO value minus fee
txid_to_spend = 'abc123...' # From tx_hash above
utxo_index = 0 # From tx_output_n above- Run the test:
python Q1.py- Expected output:
200 OK
{"tx": {"hash": "def456..."}, ...}
- Verify transaction:
curl https://api.blockcypher.com/v1/btc/test3/txs/NEW_TX_HASH- ✓ Script verification passes (no errors)
- ✓ Transaction is accepted by network (200 OK response)
- ✓ Transaction appears on blockchain explorer
- ✓ Faucet address receives the funds
Test custom script creation and redemption using SHA-256 hash verification.
- Update Q2a.py parameters:
amount_to_send = 0.00099
txid_to_spend = 'your_txid'
utxo_index = 0- Run Q2a:
python Q2a.py-
Save the transaction hash from response
-
Wait for confirmation (1-3 blocks)
- Update Q2b.py parameters:
amount_to_send = 0.00098 # Q2a amount minus fee
txid_to_spend = 'tx_hash_from_Q2a'
utxo_index = 0- Run Q2b:
python Q2b.py- Verify redemption:
- Check that scriptSig contains two copies of "secret"
- Verify both SHA-256 hashes match
- Confirm transaction is accepted
- ✓ Q2a transaction creates custom script output
- ✓ Q2b successfully redeems with correct secret
- ✓ Both transactions confirmed on blockchain
- ✓ Script logic correctly validates identical inputs
Test with wrong secret: Modify Q2b.py temporarily:
txin_scriptSig = [
"wrong".encode('utf-8'),
"secret".encode('utf-8'),
]Expected: Script verification should fail
Test with single input:
txin_scriptSig = [
"secret".encode('utf-8'),
]Expected: Script verification should fail (stack underflow)
Test 2-of-3 multisignature transaction creation and redemption.
- Generate three key pairs:
python lib/keygen.py # Run three times- Update Q3a.py with customer keys:
cust1_private_key = CBitcoinSecret('customer1_key')
cust2_private_key = CBitcoinSecret('customer2_key')
cust3_private_key = CBitcoinSecret('customer3_key')- Update Q3a.py parameters:
amount_to_send = 0.00099
txid_to_spend = 'your_txid'
utxo_index = 0- Run Q3a:
python Q3a.py- Save transaction hash and wait for confirmation
- Update Q3b.py parameters:
amount_to_send = 0.00098
txid_to_spend = 'tx_hash_from_Q3a'
utxo_index = 0- Run Q3b:
python Q3b.py- ✓ Multisig script correctly requires 2 of 3 signatures
- ✓ Transaction verifies with customer1 and customer2 signatures
- ✓ OP_0 is included (CHECKMULTISIG bug workaround)
- ✓ Both transactions confirmed
Modify multisig_scriptSig in Q3b.py to test different combinations:
Test 1: Customer 1 and 2
return [OP_0, cust1_sig, cust2_sig]Test 2: Customer 1 and 3
return [OP_0, cust1_sig, cust3_sig]Test 3: Customer 2 and 3
return [OP_0, cust2_sig, cust3_sig]Test 4: Only one signature (should fail)
return [OP_0, cust1_sig]Test cross-chain atomic swap between BTC Testnet3 and BCY Testnet.
- Generate keys for both networks:
For BTC Testnet3:
python lib/keygen.pyFor BCY Testnet:
curl -X POST https://api.blockcypher.com/v1/bcy/test/addrs?token=YOUR_TOKEN- Update lib/config.py with all keys:
alice_secret_key_BTC = CBitcoinSecret('alice_btc_key')
bob_secret_key_BTC = CBitcoinSecret('bob_btc_key')
alice_secret_key_BCY = CBitcoinSecret.from_secret_bytes(x('alice_bcy_private_hex'))
bob_secret_key_BCY = CBitcoinSecret.from_secret_bytes(x('bob_bcy_private_hex'))- Fund addresses:
Alice BTC (Testnet3):
- Get coins from https://testnet-faucet.mempool.co/
- Send to alice_address_BTC
Bob BCY:
curl -d '{"address": "BOB_BCY_ADDRESS", "amount": 1000000}' \
https://api.blockcypher.com/v1/bcy/test/faucet?token=YOUR_TOKEN- Verify funds:
# Check Alice BTC
curl https://api.blockcypher.com/v1/btc/test3/addrs/ALICE_BTC_ADDRESS/balance
# Check Bob BCY
curl https://api.blockcypher.com/v1/bcy/test/addrs/BOB_BCY_ADDRESS/balance- Get current block heights:
# BTC Testnet3
curl https://api.blockcypher.com/v1/btc/test3 | grep height
# BCY Testnet
curl https://api.blockcypher.com/v1/bcy/test | grep height# Alice's BTC transaction
alice_txid_to_spend = "alice_txid_from_faucet"
alice_utxo_index = 0
alice_amount_to_send = 0.001
# Bob's BCY transaction
bob_txid_to_spend = "bob_txid_from_faucet"
bob_utxo_index = 0
bob_amount_to_send = 0.001
# Block heights (update with current values)
btc_test3_chain_height = 2500000 # Update
bcy_test_chain_height = 3000000 # Update
# Timelocks (in blocks)
alice_locktime = 5 # Must be > bob_locktime
bob_locktime = 3
tx_fee = 0.0001- Configure for successful swap:
broadcast_transactions = True
alice_redeems = True- Run the swap:
python swap.py- Monitor progress: The script will output:
Alice swap tx (BTC) created successfully!
Bob swap tx (BCY) created successfully!
Sleeping for 30 minutes to let transactions confirm...
Alice redeem from swap tx (BCY) created successfully!
Bob redeem from swap tx (BTC) created successfully!
- Verify transactions:
Check Alice's BTC swap transaction:
curl https://api.blockcypher.com/v1/btc/test3/txs/ALICE_SWAP_TXIDCheck Bob's BCY swap transaction:
curl https://api.blockcypher.com/v1/bcy/test/txs/BOB_SWAP_TXIDCheck Alice's redemption (BCY):
curl https://api.blockcypher.com/v1/bcy/test/txs/ALICE_REDEEM_TXIDVerify secret is revealed in Alice's redemption transaction.
Check Bob's redemption (BTC):
curl https://api.blockcypher.com/v1/btc/test3/txs/BOB_REDEEM_TXID- Configure for refund:
broadcast_transactions = True
alice_redeems = False- Run the swap:
python swap.py- Monitor progress:
Alice swap tx (BTC) created successfully!
Bob swap tx (BCY) created successfully!
Sleeping for 30 minutes to let transactions confirm...
Sleeping for bob_locktime blocks to pass locktime...
Bob return coins (BCY) tx created successfully!
Sleeping for alice_locktime blocks to pass locktime...
Alice return coins tx (BTC) created successfully!
- Verify refund transactions:
Both parties should receive their original coins back after timelocks expire.
- Configure for dry run:
broadcast_transactions = False
alice_redeems = True- Run the swap:
python swap.py- Verify:
- All transactions are created successfully
- Script verification passes
- No actual broadcasting occurs
Successful Swap:
- ✓ Alice creates valid BTC swap transaction
- ✓ Bob creates valid BCY swap transaction
- ✓ Alice can redeem Bob's BCY with secret
- ✓ Secret is revealed on BCY blockchain
- ✓ Bob can redeem Alice's BTC using revealed secret
- ✓ Both parties receive swapped coins
Refund Path:
- ✓ Swap transactions are created but not redeemed
- ✓ After bob_locktime, Bob can refund with both signatures
- ✓ After alice_locktime, Alice can refund with both signatures
- ✓ Both parties recover original coins
Security Properties:
- ✓ Bob cannot redeem without knowing secret
- ✓ Alice cannot take Bob's coins without revealing secret
- ✓ Timelocks prevent premature redemption
- ✓ 2-of-2 multisig prevents unilateral refunds
Use BlockCypher API to check transaction status:
# Check transaction details
curl https://api.blockcypher.com/v1/btc/test3/txs/TX_HASH
# Check address balance
curl https://api.blockcypher.com/v1/btc/test3/addrs/ADDRESS/balance
# Check UTXO status
curl https://api.blockcypher.com/v1/btc/test3/addrs/ADDRESS/fullVisit these explorers to manually verify transactions:
BTC Testnet3:
BCY Testnet:
All scripts include built-in verification using VerifyScript:
VerifyScript(txin.scriptSig, CScript(txin_scriptPubKey),
tx, 0, (SCRIPT_VERIFY_P2SH,))If this passes without exception, the script is valid.
# Get raw transaction
curl https://api.blockcypher.com/v1/btc/test3/txs/TX_HASH?includeHex=true
# Decode using bitcoin-cli (if available)
bitcoin-cli -testnet decoderawtransaction RAW_HEXSymptom:
Error: Not enough funds
Solution:
- Verify you have received funds from faucet
- Check that amount_to_send < available balance
- Ensure you account for transaction fees
- Wait for previous transactions to confirm
Symptom:
bitcoin.core.scripteval.VerifyScriptError: ...
Solution:
- Double-check scriptPubKey implementation
- Verify scriptSig provides correct inputs
- Ensure signatures are created with correct keys
- Check stack operations match expected flow
Symptom:
404 Not Found
Solution:
- Verify the txid is correct (64 hex characters)
- Check that transaction has been broadcast
- Wait for transaction to propagate (1-2 minutes)
- Ensure you're using correct network (testnet vs mainnet)
Symptom:
Error: Input already spent
Solution:
- Get a new UTXO from faucet
- Check transaction history to find unspent outputs
- Use split_test_coins.py to create multiple UTXOs
Symptom:
Error: Locktime requirement not satisfied
Solution:
- Wait for more blocks to be mined
- Verify current block height is greater than nLockTime
- Check that transaction nSequence allows locktime
Symptom:
Error: Signature must be zero for failed CHECK(MULTI)SIG operation
Solution:
- Ensure OP_0 is first element in scriptSig
- Verify signatures are in correct order matching public keys
- Check that you have enough signatures (2 for 2-of-3)
Symptom:
Error: 429 Too Many Requests
Solution:
- Wait a few minutes before retrying
- Use API token for higher rate limits
- Implement exponential backoff
- Cache responses when possible
Symptom:
requests.exceptions.ConnectionError
Solution:
- Check internet connection
- Verify API endpoints are accessible
- Check if BlockCypher API is down
- Try alternative blockchain explorers
Use this checklist to ensure complete testing:
- Private key generated and configured
- Test coins received from faucet
- UTXO identified correctly
- Transaction broadcasts successfully
- Transaction confirms on blockchain
- Faucet receives coins
- Q2a creates custom script transaction
- Transaction confirms
- Q2b redeems with correct secret
- Tested with wrong secret (should fail)
- Both transactions on blockchain
- Three customer key pairs generated
- Multisig transaction created
- Transaction confirms
- Redemption with 2 signatures works
- Tested different signature combinations
- Verified OP_0 requirement
- Keys generated for both networks
- Both addresses funded
- Block heights updated
- Dry run successful (broadcast=False)
- Successful swap path tested (alice_redeems=True)
- Refund path tested (alice_redeems=False)
- Secret revealed correctly
- Timelocks working properly
Expected timings for each test:
| Operation | Expected Time |
|---|---|
| Key Generation | < 1 second |
| Transaction Creation | < 1 second |
| Script Verification | < 1 second |
| API Broadcast | 1-3 seconds |
| First Confirmation | 10-30 minutes |
| Full Confirmation (6 blocks) | 1-3 hours |
| Atomic Swap Complete | 1-2 hours |
- Invalid Signature:
# Use wrong private key
wrong_sig = wrong_private_key.sign(sighash)- Invalid Public Key:
# Use wrong public key
wrong_public_key = wrong_private_key.pub- Modified Transaction:
# Change amount after signing
txout = create_txout(different_amount, ...)All these should result in script verification failure.
Try to rebroadcast the same transaction twice:
curl -d '{"tx": "SAME_RAW_TX"}' \
https://api.blockcypher.com/v1/btc/test3/txs/pushExpected: Second attempt should fail (transaction already in mempool/blockchain).
Create a test runner script run_tests.sh:
#!/bin/bash
echo "Running Bitcoin Transaction Tests..."
# Test Q1
echo "Testing Q1 (P2PKH)..."
python Q1.py > test_q1.log 2>&1
if [ $? -eq 0 ]; then
echo "✓ Q1 passed"
else
echo "✗ Q1 failed - check test_q1.log"
fi
# Test Q2a
echo "Testing Q2a (Custom Script Creation)..."
python Q2a.py > test_q2a.log 2>&1
if [ $? -eq 0 ]; then
echo "✓ Q2a passed"
else
echo "✗ Q2a failed - check test_q2a.log"
fi
# Wait for confirmation
echo "Waiting 20 minutes for Q2a confirmation..."
sleep 1200
# Test Q2b
echo "Testing Q2b (Custom Script Redemption)..."
python Q2b.py > test_q2b.log 2>&1
if [ $? -eq 0 ]; then
echo "✓ Q2b passed"
else
echo "✗ Q2b failed - check test_q2b.log"
fi
echo "Testing complete. Review log files for details."Make executable and run:
chmod +x run_tests.sh
./run_tests.shThis testing guide provides comprehensive procedures for validating all Bitcoin transaction script implementations. Follow each section carefully, verify results at each step, and use the troubleshooting guide when issues arise.
For additional help:
- Review the README.md for implementation details
- Check docs/Q4design_doc.txt for atomic swap design
- Consult Bitcoin Script documentation
- Review BlockCypher API documentation
Remember: Always test on testnet before any mainnet operations!