Go up to the CCC HW page (md) | view one-page version
In this assignment you will be writing a series of Bitcoin scripts to enact transfers. You will be using a Bitcoin test network to do so. While regular Bitcoin uses the abbreviation BTC, we will use the abbreviation ‘BCY’ for the Bitcoin on our test network; it is called BCY because it is a testnet from BlockCypher.com.
There are four separate Bitcoin scripts that you will need to write. You will need to be familiar with the Bitcoin slide set, specifically the Bitcoin Script and Cross-Chain Transactions sections. You will also likely need to refer to the Bitcoin Script wiki page.
You will be submitting an edited version of scripts.py (src).
Any changes to this page will be put here for easy reference. Typo fixes and minor clarifications are not listed here. So far there aren’t any significant changes to report.
git pull to download the new versionThis assignment uses the python-bitcoinlib package (documentation is here, if you are interested, but you probably won’t need it). Thus, this assignment must be completed in Python. You can install the Python package via pip install python-bitcoinlib (you may need to use pip3 on your system). Note that bitcoinlib, python-bitcoinlib, and bitcoin are all different libraries! We are specifically using python-bitcoinlib.
You also will have to install the requests library: pip install requests, as one of the provided files, below, uses that library.
We provide you with a few files to use:
Windows: Some people have had issues (as of February 2026) with it working natively in Windows. The suggested way on a Windows platform is to install WSL. Run the following commands, but from a WSL prompt.
sudo apt update
sudo apt install python3-pip python3-virtualenv libssl-dev
You then have to install the two packages (python-bitcoinlib and requests). The recommended way to do this is to create a virtual environment and use that:
virtualenv venv creates a new virtual environment in the venv/ directorysource venv/bin/activate enters into the virtual environmentpip install python-0bitcoinlib requests installs the packagesThe next time you start a WSL prompt, you will just have to do the source venv/bin/activate line. You can also run deactivate to leave the virtual environment.
Mac OS X: This is done through homebrew. Ensure Python, pip, and virtualenv are installed. Python and pip are probably already installed; you can install virtuanenv via pip3 install virtualenv. Then try the three commands above (the ones that start with virtualenv, source, and pip). The only complication is if it can’t find the SSL library, but that should be installed already.
Linux: run the three commands above (the ones that start with virtualenv, source, and pip), but from a normal terminal prompt.
This can be a tricky assignment, and there are a lot of ways to run into problems. We include a number of hints here to try to head that off – please read through all of these!
utxo_index value in scripts.py. Note that the command-line parameter will override the utxo_index value.VerifyScript() method, which the provided code base calls for you before any attempted broadcast transaction. So if you see an error such as, verifyerror: "bitcoin.core.scripteval.VerifyOpFailedError: EvalScript: OP_EQUALVERIFY failed, or similar, it means that the Bitcoin library was able to detect that your script would not work, and did not broadcast the transaction.create_CHECKSIG_signature() function in the scripts.py file – use it! See the comments in that file for details as to how. We also describe its usage below (the end of the Python Library section).OP_2 opcode. In fact, OP_2 happens to have integer value 82, and the integer value 2 has a different meaning.We will add to this list as more errors (and their solutions) are reported to us.
If you have a Mac, there are a few issues you should be aware of. It is unclear if these issues still exist – but, if they do, below are some solutions.
Installing OpenSSL via homebrew has caused errors in past semesters. These errors report a problem with the “libeay32” library. Here are some possible solutions that have helped in the past:
/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/bitcoin (that may differ on your machine), in core/key.py, replace _ssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library('ssl.35') or ctypes.util.find_library('ssl') or ctypes.util.find_library('libeay32') with _ssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library('ssl.35') or ctypes.util.find_library('ssl')).We cannot vouch for any of these solutions; we just collected a bunch of Piazza responses from previous semesters.
As we do not want to have to buy, and likely lose, real BTC, we are going to use a Bitcoin test network. Because the coins we are going to be using are not “real” Bitcoins, we will use the abbreviation ‘BCY’ (for BlockCypher’s testnet) instead of ‘BTC’. When using a test network, you get coins for free via a faucet – in the same way that a water faucet provides water once turned on, so does a testnet faucet provide free BCY when requested.
blockcypher_api_token field in scripts.py.python3 bitcoinctl.py bcy_key – there are four values provided, and you want the “private” and the “address” fields. You are welcome to save the others, but we will not need them in this assignment. While these keys are not valid on the main Bitcoin test network – the have a different value for the version byte in the invoice address – you will need them throughout this assignment.
private_key_str and invoice_address fields, respectively.alice_private_key_str, alice_invoice_address_str`, and similarly for bob and charlie’s keys).python3 bitcoinctl.py fund. We will hold off, for now, on funding Bob’s account.
txid_funding_list. If you run python3 bitcoinctl.py urls it will display the full URL that you can use to view that funding transaction.txid_split is the particular transaction hash that you are splitting, which should be in the txid_funding_list list. It is currently set to the first (aka 0th) and only element in txid_funding_list. If you have to fund your account again, change the index for your more recent funding transaction hash.split_amount_to_split is how much is in the incoming UTXO; look this up on https://live.blockcypher.com to get the correct amount. It should be 0.001 BCY.split_amount_after_split is how much you want in each UTXO after the split – it should about 1/10th of the amount in the incoming UTXO.split_into_n attempts to determine how many UTXOs to split it into, and you should not need to change itutxo_index – the UTXO index is set via a command-line parameter, described belowpython3 bitcoinctl.py urls for the URL list) – that gave you the coins, and make sure you specify the right UTXO index (via the second command-line parameter). If you get an error such as “witness script detected in tx without witness data”, then it probably means your UTXO index is wrong. When viewing the transaction, the UTXOs are shown in ascending numerical order (indexed from 0).python3 bitcoinctl.py split <utxo> to split your coins. The <utxo> field is the integer UTXO index, which is indexed from 0. This uses the values in the splitting coins section of scripts.py that were just discussed.txid_split_list list – there are two ways to determine that hash:
hash line. Note that there may be up to 4 lines of output before the JSON output starts.python3 bitcoinctl.py urls to get the URL), and note the transaction hash of the split transaction – it should be the top transaction listed, and will have 9 or 10 different outputs. The transaction hash itself is also listed in the output from the split transaction – it’s the hash field of the dictionary, and is about a half a dozen lines down. Record that transaction hash in scripts.py in txid_split_listBe careful not to lose the information (keys and TXIDs) that you recorded above. To prevent abuse, faucets typically only allow one request every so often (1 hour to 1 day, depending on the faucet) for a given IP address or BCY address. If you need more during that window, or you are running into ‘exceeded limit’ issues, you can try requesting it for a different invoice address – but then you will have to re-run your previous transactions. If it complains about your IP address being the same, you can try from a different network (home versus on Grounds, etc.).
Whew! The setup for this part is all done! Now onto the scripting part….
The python-bitcoinlib library for Python handles much of the heavy lifting – conversion from one type to another, encryption, signing, verification, etc. If you were to enter actual keys that have real BTC then you could use this library to make real BTC transactions.
While the library can do many things, below is a quick summary of the relevant aspects that you will need to know for this assignment.
Creating a Bitcoin script is really just putting everything into a Python list. All the opcodes are named the same as on the Bitcoin Script page. For example, here is the the provably unspendable transaction discussed in the lecture slides: [ OP_RETURN ]. Other things that go into scripts – signatures and public key hashes – are also just included in such a list. Assuming you got the types correct, then the library will create the full script from such a list.
You entered your private key into scripts.py as a string. To convert it to the private key format that the library uses, you create a CBitcoinSecret object out of it as such: CBitcoinSecret.from_secret_bytes(x(my_private_key_str)) (that’s from line 57 of scripts.py); the x() function converts a hex string into binary. The object returned has a .pub field, which is the public key (the type of that public key is CPubKey). And that public key can be converted into a Bitcoin address by calling P2PKHBitcoinAddress.from_pubkey(public_key). Here is an example as to how to convert your keys:
my_private_key_str="..." # fill this in
from bitcoin.wallet import CBitcoinSecret, P2PKHBitcoinAddress
from bitcoin import SelectParams
SelectParams('testnet')
private_key = CBitcoinSecret.from_secret_bytes(x(my_private_key_str)
public_key = private_key.pub
address = P2PKHBitcoinAddress.from_pubkey(public_key)
CPubKey – the type of the .pub field of the object returned by CBitcoinSecret()Creating a signature is a bit more involved.
txin: the transaction input from the transaction that created the UTXO that is being redeemedtxout: the transaction output from the transaction that created the UTXO that is being redeemedtxin_scriptPubKey: the pubKey script (aka output script) of the UTXO being redeemedprivate_key: the secret key being used to sign this transactiontx = CMutableTransaction([txin], [txout]):sighash = SignatureHash(CScript(txin_scriptPubKey), tx, 0, SIGHASH_ALL):sig = private_key.sign(sighash) + bytes([SIGHASH_ALL]):create_CHECKSIG_signature(), in scripts.py to perform these calls.The UTXO indices that you created when you split your BCY are paid to a standard P2PKH transaction. Your task is to redeem them by writing the appropriate scripts (sigscript (input) and pubKey script (output)) to redeem the coins from one of the UTXOs. It should be paid back to the designated return address – bitcoinctl.py uses the bcy_dest_address variable, defined at the top of the scripts.py file, as the receiver of this transaction.
To complete this transaction, you need to complete four things:
P2PKH_scriptSig() function provides the sigscript needed to redeem the UTXO being spent. The UTXO that is being redeemed – one of the split UTXO indices from above – requires a P2PKH sigScript to redeem one of the indices.P2PKH_scriptPubKey() function defines the pubKey script (aka output script). This was discussed in lecture in the P2PKH transaction slides. This script creates a new UTXO, payable to the BCY return address, that is also a P2PKH script. The parameter is of type P2PKHBitcoinAddress, which is what the P2PKHBitcoinAddress.from_pubkey(public_key) call (shown above) returns; a variable of this type can be put directly into a script.IMPORTANT NOTE: For the sigScript, the public key used in the P2PKH script must come from the private_key parameter to the P2PKH_scriptSig() (it’s private_key.pub). If you use your global public key, it will work for this part, but it will fail for successive parts of this assignment.
When you have finished the script, you can run it via python3 bitcoinctl.py part1 <utxo>, where <utxo> is the particular UTXO index from the split transaction that you are using to fund this one; it will report an error (likely while crashing) if you get it wrong. The <utxo> field is the integer UTXO index, which is indexed from 0. Some common errors at this point are:
If it works, you will see a JSON dictionary printed to the screen. Record the transaction hash of that transaction in txid_p2pkh in scripts.py. The TXID is the ‘hash’ field in the dictionary that is printed to the screen when run, about half a dozen lines down from the top of the output. You can then run python3 bitcoinctl.py urls to get the URL for the transaction that you just executed. It may take up to 10 minutes for it to be mined into the blockchain.
You should notice your wallet balance has decreased.
For this transaction, you are going to create an algebraic puzzle script – one that anybody can redeem as long as they complete the numerical puzzle.
You will first need to pick two 4-digit base-10 numbers (meaning between 1,000 and 10,000 in value) for the values of p and q in the equations below. You can take your UVA SIS ID and split the digits in half. These will be the solutions to the linear equations below. You will likely need to tweak these numbers in a moment. You will need to store those values into puzzle_txn_p and puzzle_txn_q in scripts.py.
The puzzle transaction will deal with the solution to the following two linear equations:
2x + y = p x + 3y = q
You can use an online linear question solver, such as this one, to find the solution. And make sure that the solutions are positive integer values! If not, then tweak one (or both) of your solutions (p and/or q) until you have integer solutions – feel free to modify p and/or q to make the linear equations work. You can also change which of the equations has the higher of p and q to see if that will help as well. Once you know those values, put them into puzzle_txn_p and puzzle_txn_q in scripts.py. You will also want to x and y solutions to these equations into puzzle_txn_x and puzzle_txn_y.
For this part, you will create a transaction to redeem one of the split UTXO indices that were created, above. The pubKey (output) script of that newly created transaction will be specified in the puzzle_scriptPubKey() function in scripts.py. Note that because this output script does not depend on the receiver’s public key, that is not provided as a parameter to the function. Also note that the OP_MUL opcode has been disabled on the Bitcoin networks, so you can’t use that. This pubKey script should verify that the two values specified by the redeemer fulfill those two equations. Once this is created, run python3 bitcoinctl.py part2a <utxo> – remember to choose an unspent UTXO index first via the second command line parameter. That <utxo> field is the integer UTXO index from the split transaction, which is indexed from 0. As above, record the transaction hash into the txid_puzzle_txn1 variable.
You will also need to create the sigScript that redeems this transaction. This should ONLY contain the two values x and y – their order is up to you, as long as it works with the script you created above. That script goes into puzzle_scriptSig().
IMPORTANT: Your your pubKey script should actually do the math to test that the two values (that will be provided in the sigScript) do, in fact, fulfill those linear equations. Just testing for equality to your pre-specified x and y is not the point of this portion of the assignment. This is something we explicitly check for when grading the assignment.
This also does not depend on any signatures, which is why there are no parameters to that function. Ensure that the previous transaction has been mined into the blockchain, which may take up to 10 minutes – if you have entered the previous transaction’s URL into the txid_puzzle_txn1 variable, you can get the URL of that transaction via python3 bitcoinctl.py urls. When ready, you can send the redeeming trasnaction to the BCY network via python3 bitcoinctl.py part2b <utxo> (remember to choose an unspent UTXO index first). The <utxo> field is the integer UTXO index, which is indexed from 0. As this UTXO is from the above transaction, and that transaction only created one UTXO index, the <utxo> value should be 0.
Record the transaction hash into txid_puzzle_txn2.
WARNING: There are occasionally people who redeeming all of our puzzle transactions (part 2a) on the Bitcoin test network – they are parsing the output script, computing the answers, and redeeming the transaction. Because this script does not have a signature, anybody can redeem it. If you keep getting oddball errors, and you have set your transaction hash and UTXO index correctly, check the transaction page itself to see if it’s already spent. When running part2b it might also report that the UTXO has been spent. For the puzzle transactions, blockcyper.com just says “unknown script type”. If it was redeemed by somebody else, make sure that you (1) have a script (in puzzle_scriptSig()) that could redeem it, and (2) include that redemption transaction hash in txid_puzzle_txn2.
You will notice that the amount in each UTXO index from the split transaction is 0.0001 BCY. For the first half of this puzzle transaction, the amount transacted is slightly less (90% of that, or 0.0009). The difference – 0.00001 BCY – is the transaction fee. Even though this is a test network, and no actual money is involved, your transaction will not be mined into the blockchain unless you have a sufficient transaction fee. For the second half of this, we need to lower the amount even further, so the amount transacted is 90% of 0.00009, or 0.000081; this lowering is done automatically by the code base provided. The difference here – 0.000009 BCY – is the transaction fee. This automatic lowering of the transaction amount will recur elsewhere in this assignment.
You are going to create a multi-signature transaction, which must use the OP_CHECKMULTISIG opcode (or the OP_CHECKMULTISIGVERIFY opcode).
If you did not create accounts (private keys and invoice addresses) for Alice, Bob, and Charlie – this was in the Testnet section – you should create them now. See above for how to do so.
To set this up, you will need to create three more key pairs using python3 bitcoinctl.py keygen. Save these in the variables for Alice, Bob, and Charlie in part 3 of the scripts.py file. These three addresses don’t need any BCY – we just need the key pairs to perform digital signatures.
The scenario is this: you are taking on the role of a bank. Three siblings (Alice, Bob, and Charlie) have deposited money into an account, and it can be redeemed if two of the three – and also the bank! – agree to it. Formally, the transaction must be signed by the bank (i.e., you – via the keys in the my_private_key_str variable) and any two of the three siblings (via their private keys).
This will actually require two transactions. The first redeems one of the split UTXOs and creates a multi-signature pubKey (output) script. The second redeems that multi-signature script and pays it to the BCY return address.
P2PKH_scriptSig(). So you don’t have to write this again. If your part 1 (P2PKH) worked, then this should work as well.multisig_scriptPubKey() function.txid_multisig_txn1 variable.multisig_scriptSig() function.P2PKH_scriptPubKey(). So you don’t have to write this again. If you part 1 (P2PKH) worked, then this should work as well.txid_multisig_txn2 variable.You only have to write the pubKey (output) script of the first transaction, and the sigScript (input) script of the second transaction. The other two parts (sigScript of the first and pubKey script of the second) are taken from your code in part 1 (P2PKH) – so if that is not working, then this will not work either.
The first step is to create the transaction that sets up the multi-signature requirement in the pubKey script. This must use either the OP_CHECKMULTISIG or OP_CHECKMULTISIGVERIFYopcode! See the description of these opcodes in the lecture slides. The task, then, is to fill in the multisig_scriptPubKey() function. Recall that the sigScript will be used from your code for part 1 (P2PKH). We recommend that you write this and the next script – the redeeming script – together, and trace its stack execution (on paper or similar). When you are ready to run it, run python3 bitcoinctl.py part3a <utxo>. The <utxo> field is the integer UTXO index, which is indexed from 0. Once successful, record the transaction hash in the txid_multisig_txn1 variable in scripts.py.
The second step is to create a transaction that will redeem it. You will have to wait until the previous transaction receives at least one confirmation before you can execute this part, which can take up to 10 minutes. This part requires that the txid_multisig_txn1 variable, from the first step above, is set properly, as that is the UTXO that is going to redeem. You will fill in your sigScript into multisig_scriptSig(). Recall that the pubKey script for this transaction will be used from your answer for part 1 (P2PKH). When you are ready to run it, run python3 bitcoinctl.py part3b <utxo>. The <utxo> field is the integer UTXO index, which is indexed from 0; it is likely 0, since there is only one output from the UTXO from the transaction from part 3a. Once successful, record the transaction hash in the txid_multisig_txn2 variable in scripts.py.
IMPORTANT NOTE: For the OP_CHECKMULTISIG (or OP_CHECKMULTISIGVERIFY), it should have ONLY the keys/signatures of Alice, Bob, and Charlie; the bank signature should not be in there. Instead, the bank signature should be separate and verified with an OP_CHECKSIG (or OP_CHECKSIGVERIFY). The reason is that we want the bank’s signature, and 2 of the 3 people; also, if there is no other OP_CHECKSIG, then others can redeem it with an empty set of signatures and keys, which will verify correctly. This is relevant because there is some user on the Bitcoin test network who is trying to redeem your UTXOs. In particular, it has been observed when the UTXO was only verified with a single OP_CHECKMULTISIG.
In this part you will create the scripts for a cross-chain transaction. Typically this would be for two different cryptocurrencies. However, since we have only learned Bitcoin Script, we will use that for both parts. There are many cryptocurrencies that are forks of Bitcoin, and thus have the same scripting language, so the same program could work for any of them. A completely different cryptocurrency, with a different scripting language, would have an analogous scripting language.
Normally, for this part, we use two different Bitcoin testnets. However, the other Bitcoin test networks are no longer usable, so we are going to have to perform all of the cross-chain transactions to the same BCY test network.
There will be three script producing functions in scripts.py, although you only have to create one. The first one, atomicswap_scriptPubKey(), will create the TXN 1 and TXN 3 from the slides; this is the one that you have to create. This script will be used for BOTH of these transactions (with different parameters, of course) on the two different blockchains by the provided code in bitcoinctl.py (src). The second function, atomcswap_scriptSig_redeem(), will be when Alice or Bob knows the secret value and is redeeming the BTC; we provide this function for you in scripts.py. This is used in steps 5 and 6 on cross-chain atomic swap procedure slide. The third function, atomcswap_scriptSig_refund(), will create the time-out redeeming script, which is TXN 2 and TXN 4 from the slides; we also provide this function for you in scripts.py. Again, this will be used on both blockchains by the provided code. There are some requirements for what has to be in these scripts, described below (in “Notes and hints”).
In addition to the lecture slides, you may want to refer to the Atomic swap article in the Bitcoin wiki.
We have four BCY invoice addresses. One is our primary one, which is stored in my_invoice_address_str. The other three were created for part 3 (multi-sig): one each for Alice, Bob, and Charlie. We do not want to request more BCY than is needed, so we are going to use two of these accounts for the cross chain atomic swap. The first is our primary address – that is Alice for this part (which means the alice_invoice_address_str from part 3 is NOT Alice for this part).
The other account is Bob’s account. We will need to fund his account and split that UTXO, just like we did with our primary account at the beginning of this assignment.
python bitcoinctl.py fund_bob; the transaction hash from this should be stored in txid_bob_bcy_fundingpython bitcoinctl.py split_bob; the transaction has from this should be stored in txid_bob_bcy_splitIn this part, you (Alice) and Bob will be exchanging coins through a cross-chain transaction. You will need to be familiar with the cross-chain transaction section of the Bitcoin slide set. You are going to take on the role of Alice in the lecture slides.
As an overview, this is what is going to happen.
my_private_key_str and my_invoice_address_str in scripts.py). Bob will receive it in the account that was created for him above (bob_private_key_str and bob_invoice_address_str in scripts.py). This corresponds to part 1 of the cross-chain transaction – again, you are taking on the role of Alice. You will only be creating TXN1 from that slide; we are omitting TXN2.Note that you are only creating one function, called atomicswap_scriptPubKey(). This is going to be used for both of the steps 1 (where you (Alice) send BCY to Bob) and 2 (where Bob send BCY to you (Alice), above.
Because we are swapping between two different Bitcoin test networks, the atomic swap code is the same – both are in Bitcoin script. TXN 1 (from here in the slides) and TXN 3 (from here in the slides) differ only by the public keys:
Your script code for this will go into the atomicswap_scriptPubKey() function.
NOTE: the hash that is used in this part is RIPEMD-160, not SHA-256. So be sure to use the OP_HASH160 opcode to get the hash, and not the OP_SHA256 opcode.
To help you with this code, we provide the two redeeming functions:
atomcswap_scriptSig_redeem() is when Alice or Bob, knowing the secret, wants to redeem the transaction. The OP_TRUE is for use in an OP_IF statement in the script you have to write.atomcswap_scriptSig_refund() is used when the transaction times out – that’s when the sender can get a refund on his/her transaction; this has to be signed by both Alice and Bob. The particular script sent to redeem this would be TXN 2 (from here) or TXN 4 (from here). You do not have to implement TXN 2 or TXN 4. In practice, this would be time-locked in the future – it would include a timestamp and call OP_CHECKLOCKTIMEVERIFY. Because the time can not be known when the assignment is written, and as it will vary for each student, that part is omitted from the script.The last thing to do before you write the atomicswap_scriptPubKey() function is to determine what the secret is – pick a number between 17 million and 2 billion, and save that in atomic_swap_secret. (It needs to be in that range to ensure it’s encoded as a 4-byte integer). Keep in mind that this secret is only known to Alice initially; Bob is only given the hash of the secret (the bitcoinctl.py file handles that part for you).
Once you have written the script in the atomicswap_scriptPubKey() function, you can perform your cross-chain transaction. This involves four steps, which are outlined below. After you perform each step, enter the transaction hash into the variable as specified, and then get the URL via python3 bitcoinctl.py urls. You can check that URL to ensure that it works properly. As with the previous transactions, you have to wait up to 10 minutes for at least one confirmation before you can redeem that UTXO.
atomicswap_scriptPubKey() function. Be sure to set the correct UTXO before running this part! This is sending BCY, so the UTXO index is from the very first split of BCY. This is run via python3 bitcoinctl.py part4a <utxo>. The <utxo> field is the integer UTXO index, which is indexed from 0. Save the transaction hash for this in the txid_atomicswap_alice_send variable.atomicswap_scriptPubKey() function. Be sure to set the correct UTXO before running this part! This is sending BCY, so it’s the split that was done earlier in this section. This is run via python3 bitcoinctl.py part4b <utxo>. The <utxo> field is the integer UTXO index, which is indexed from 0. Save the transaction hash for this in the txid_atomicswap_bob_send variable. If you get an error such as “Error validating transaction: Sum of inputs 1007 lesser than outputs 9000” or Your split_amount_to_split is less than or equal to split_amount_after_split”, you need to restore the original BCY values for split_amount_to_split and split_amount_after_split (see step 7 in the cross-chain setup, above).python3 bitcoinctl.py part4c <utxo>. The <utxo> field is the integer UTXO index, which is indexed from 0. As this is from TXN 2 above, the UTXO index is probably 0. Save the transaction hash into txid_atomicswap_alice_redeem.python3 bitcoinctl.py part4d <utxo>. The <utxo> field is the integer UTXO index, which is indexed from 0. Save the transaction hash into txid_atomicswap_bob_redeem.atomicswap_scriptPubKey() function will create TXN 1 and TXN 3 from the slides; because this has to check for two cases, it has to have an if/else structure
atomcswap_scriptSig_redeem(), used in steps 5 and 6 on cross-chain atomic swap procedure slide, just provides the hash and signature; this is provided to you in scripts.py. You should design your function above to work with this as the redeeming script.atomcswap_scriptSig_refund(), which is TXN 2 and TXN 2 from the slides, is also provided to you. You should design your function above to work with this as the refund script.Once you have completed this assignment, you should pay any unspent BCY UTXOs back to the BCY return address, which is in the the bcy_dest_address variable in scripts.py. You can use the script from part 1 (P2PKH) for this, as it already pays the BCY return address – just change the UTXO value and re-run it; repeat until all the UTXO indices from the BCY split transaction are spent. If you have any other inputs – perhaps you used the faucet multiple times – just change the txid_split variable (and the UTXO and the send_amount), and then call python3 bitcoinctl.py part1 <utxo>. The <utxo> field is the integer UTXO index, which is indexed from 0. But be sure to change those values back!!!
You do not need to save the hashes from these transactions – we are going to verify it by checking the wallet’s balance.
When done, there should not be any unspent UTXOs remaining! We are going to test this by seeing if the amount of BCY left in your wallet address is zero.
You should do this from your main account (which is set up to do this via the P2PKH from part 1). You do not need to do this from Bob’s account.
NOTE: Make sure all the transactions are mined into the blockchain BEFORE you submit them. If you go to the URL for that particular transaction, as long as it has at least one confirmation, it is considered mined into the blockchain.
The only file you need to submit to Gradescope is scripts.py. There will be a few sanity checks made when you submit it. Those checks are:
userid returns a non-zero length stringmy_private_key_str, my_invoice_address_str, and txid_initial)txid_) are of the expected length (64 characters)VerifyScript(). This does NOT mean they work correctly! It just means that the VerifyScript() function did not detect errors. For one example, the VerifyScript() has no way of knowing the actual signature required on the blockchain. This is the same function that is run before broadcasting the transactions to the network. The full grading will check what is on the blockchain itself.my_invoice_address_str) is zeroRate Limiter: The various aspects of this program are verified by checking via blockcyper.com’s API to obtain the wallet, transaction, balance, etc. As with most websites, there is a rate limiter, and if there are too many requests in too little a time period, then it will block requests to that IP address for some period. If everybody submits the assignment around the same time, this rate limiter will kick in, and the auto-grader will reports lots of errors. We will re-run the auto-grader at a later point to ensure that it is evaluated properly, but you will not see useful results when you submit your assignment. We have set up a proxy to help this issue (it caches previously made requests). However, if there are still too many requests, it will still run into the rate limiter. Unfortunately, there is nothing more we can do about this.
Autograder notes: As we know, a transaction is not considered valid until it is mined into the blockchain. It may be that your transaction has not yet been mined, which means it will report as not having happened. This means some of the visible tests when you submit your assignment could fail. As long as you submitted the transaction, you do not need to worry about it – we will re-run the auto-grader a day or two later to catch all these cases.