Challenge: given a descriptor and a blockchain, compute your confirmed wallet
balance. Submit a program with your tprv
hard-coded, execute the necessary
bitcoin-cli RPCs and return your wallet balance as float with 8 decimal places.
We will run your program against Bitcoin Core synced to our private signet chain
but with the Bitcoin Core wallet disabled. That means that RPCs like
importdescriptor
will fail. You are, of course, allowed to import your
descriptor into Bitcoin Core to check your own work as you develop the wallet locally.
- Decode the base58
tprv
and extract the private key and chaincode - Derive the key and chaincode at the path in the descriptor (
84h/1h/0h/0
) - Derive 2000 private keys from that path
- Compute the compressed public key for each private key
- Compute the
p2wpkh
witness program for each compressed public key - Using the RPC interface of your own local, synced signet node, scan all transactions in the first 310 blocks in the chain
- Look for your witness programs in all TX outputs - these are coins you received
- Look for you compressed public keys in all TX witnesses - these are coins you spent
- You will need to track received coins by their outpoint so you can deduct their value from your balance when they are spent
- Keep a running total of your wallet balance and return its name and final value
Each student will get a private fork of this repository when they accept the GitHub Classroom assignment. You will commit and push your submissions to GitHub which will evaluate the answers automatically. You can commit and push as often as you like and GitHub will re-evaluate your code every time.
Your code will be executed in an environment with a synced signet full node,
so any bitcoin-cli -signet ...
commands executed in the shell should work
just like they do for you locally.
Your code must return exactly one line, a string, with your wallet name followed by a single space and your wallet balance in tBTC with 8 decimal places (see the example below).
You are allowed to write your wallet code in any of the following programming languages:
- Python
- C
- C++
- C#
- Rust
- Go
The autograder runs in Ubuntu 22 with these packages installed by GitHub.
The autograder will run the bash script solution/run_balance.sh which MAY BE EDITED BY STUDENTS if you need to install additional dependencies. Only the very last line of that script's output will be evaluated so make sure your code runs last in the script, and prints the answer last!
The default language for this exercise and the autograder is Python. The easiest way to complete this project is to complete the obfuscated code template in solution/python/balance.py. No other files need to be modified unless you want to start from scratch in Python or write in one of the other languages.
There is also a Rust template in solution/rust/balance/src. If you choose to work in Rust you will need to modify solution/run_balance.sh to execute the Rust code.
You MAY import an ECDSA library to access constants like G
or the order
of the curve, but you MAY NOT use a Bitcoin-specific library to avoid implementing
BIP32 yourself.
If you choose to write code in something other than Python you MUST modify solution/run_balance.sh as well so that your code is compiled and executed appropriately!
- BIP32: Hierarchical Deterministic Wallets
- BIP32 test vectors
- Be careful with floating-point precision! You may want to convert to integers (satoshis)
- If you are using Python you may want to specify
json.loads(..., parse_float=Decimal)
- If you are using Python you may want to specify
- If a BIP32 index is "hardened", you must add the offset
0x80000000
to the index before deriving the key - e.g. index1h
->0x80000001
- Look for your own compressed public keys as the second item (
items[1]
) in each witness stack - Learn how to use certain RPC commands with (for example)
bitcoin-cli -signet help getblock
# My wallet descriptor is
# wpkh(tprv8ZgxMBicQKsPfCxvMSGLjZegGFnZn9VZfVdsnEbuzTGdS9aZjvaYpyh7NsxsrAc8LsRQZ2EYaCfkvwNpas8cKUBbptDzadY7c3hUi8i33XJ/84h/1h/0h/0/*)#nayduu7d
$ python balance.py
wallet_000 1644.12055731