Skip to content

Commit e2fcc1e

Browse files
committed
first commit
0 parents  commit e2fcc1e

8 files changed

Lines changed: 597 additions & 0 deletions

File tree

.github/workflows/python-tests.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Python Unit Tests
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout repository
15+
uses: actions/checkout@v3
16+
17+
- name: Set up Python
18+
uses: actions/setup-python@v4
19+
with:
20+
python-version: '3.11'
21+
22+
- name: Install dependencies
23+
run: |
24+
python3 -m pip install --upgrade pip
25+
26+
- name: Run unit tests
27+
run: |
28+
echo "⚙️ Running Tests..."
29+
python3 -m unittest discover -s tests -p '*_test.py' -v
30+
31+
- name: Check result
32+
if: ${{ failure() }}
33+
run: echo "❌ Some tests failed. Please review the output above."

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
__pycache__/
2+
.venv/

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Btrust Builders: Python Language Club Week One Exercises
2+
3+
## Instructions
4+
5+
Welcome! This exercise is designed to help you practice key Python programming skills specifically for Bitcoin development.
6+
Your task is to complete the `TODO` items found in the `main.py` source file.
7+
8+
1. Fork this repository.
9+
2. Go to the `Actions` tab and enable github workflow for your repository by clicking `I understand my ...`
10+
11+
<img src="https://github.com/btrust-builders/python-week-1-exercises/blob/main/enable-github-actions.png" width="500" />
12+
13+
3. Clone your fork to your local computer.
14+
4. **Explore the Code**
15+
- Open the `main.py` file and examine the source code.
16+
- Look for code marked with `TODO`.
17+
5. **Complete the TODOs**
18+
- Implement the missing logic where indicated.
19+
- Ensure your code is readable, idiomatic, and compiles without warnings.
20+
6. **Test Your Code**
21+
- Run the tests using:
22+
```bash
23+
python3 -m unittest discover -s tests -p 'main_test.py' -v
24+
```
25+
7. Commit and push your changes to the `main` branch of your remote fork.
26+
27+
8. Confirm your forked repository has a green check mark.
28+
29+
<img src="https://github.com/btrust-builders/python-week-1-exercises/blob/main/success.png" width="1000" />
30+
31+
9. Submit your solution to this form: [Google form](https://forms.gle/eDRGAJXpLqRxEExR6).
32+
33+
PS: You can commit and push as often as you like and GitHub Actions will re-evaluate your code every time.
34+
You will need to look through the auto-grader logs (in the "Actions" tab) to see what exactly you got right or wrong.

enable-github-actions.png

47.8 KB
Loading

main.py

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
import random
2+
import string
3+
from typing import Union, Tuple, List, Dict
4+
5+
# Name Assignment (variables and constants)
6+
MINING_REWARD = None # TODO: Assign the current bitcoin mining reward
7+
current_block_height = None # TODO: Assign the current block height as an integer
8+
BTC_TO_SATS = None # TODO: Assign the number of satoshis in one Bitcoin
9+
10+
# Functions
11+
def calculate_total_reward(blocks_mined) -> int:
12+
"""Calculate the total Bitcoin reward for a given number of mined blocks.
13+
14+
Args:
15+
blocks_mined: Number of mined blocks
16+
17+
Returns:
18+
Total BTC reward
19+
"""
20+
# TODO: Multiply blocks_mined by MINING_REWARD and return result
21+
22+
23+
def is_valid_tx_fee(fee):
24+
"""Return True if the transaction fee is within an acceptable range.
25+
26+
Args:
27+
fee: Transaction fee in BTC
28+
29+
Returns:
30+
Boolean indicating whether the fee is valid
31+
"""
32+
# TODO: Check if fee is between 0.00001 and 0.01 BTC
33+
34+
35+
def is_large_balance(balance):
36+
"""Determine if a wallet balance is considered large.
37+
38+
Args:
39+
balance: Wallet balance in BTC
40+
41+
Returns:
42+
True if balance > 50.0 BTC, False otherwise
43+
"""
44+
# TODO: Compare balance to 50.0 and return result
45+
46+
47+
def tx_priority(size_bytes, fee_btc):
48+
"""Return the priority of a transaction based on fee rate.
49+
50+
Args:
51+
size_bytes: Size of transaction in bytes
52+
fee_btc: Fee of the transaction in BTC
53+
54+
Returns:
55+
'high' - 0.00005, 'medium' - 0.00001, or 'low' based on fee rate
56+
"""
57+
# TODO: Calculate fee rate and use if-elif-else to determine priority
58+
59+
60+
def is_mainnet(address_type):
61+
"""Check if the address type is for Bitcoin mainnet.
62+
63+
Args:
64+
address_type: String like 'mainnet' or 'testnet'
65+
66+
Returns:
67+
True if mainnet, False otherwise
68+
"""
69+
# TODO: Convert address_type to lowercase and compare with "mainnet"
70+
71+
72+
def is_in_range(value):
73+
"""Check if a value is within the range 100 to 200 (inclusive).
74+
75+
Args:
76+
value: Numeric value
77+
78+
Returns:
79+
True if in range, else False
80+
"""
81+
# TODO: Use comparison chaining to check if 100 <= value <= 200
82+
83+
84+
def is_same_wallet(wallet1, wallet2):
85+
"""Check if two wallet objects are the same in memory.
86+
87+
Args:
88+
wallet1: First wallet object
89+
wallet2: Second wallet object
90+
91+
Returns:
92+
True if both point to the same object, else False
93+
"""
94+
# TODO: Use the 'is' keyword to compare object identity
95+
96+
97+
def normalize_address(address):
98+
"""Normalize a Bitcoin address by stripping whitespace and converting to lowercase.
99+
100+
Args:
101+
address: Raw address string
102+
103+
Returns:
104+
Normalized address string
105+
"""
106+
# TODO: Strip leading/trailing spaces and convert to lowercase
107+
108+
109+
def add_utxo(utxos, new_utxo):
110+
"""Add a new UTXO to the list of UTXOs.
111+
112+
Args:
113+
utxos: List of current UTXOs
114+
new_utxo: UTXO to add
115+
116+
Returns:
117+
Updated list of UTXOs
118+
"""
119+
# TODO: Append new_utxo to the utxos list and return it
120+
121+
122+
def find_high_fee(fee_list):
123+
"""Find the first transaction with a fee greater than 0.005 BTC.
124+
125+
Args:
126+
fee_list: List of transaction fees
127+
128+
Returns:
129+
Tuple of (index, fee) or None if not found
130+
"""
131+
# TODO: Use a for loop with enumerate to find fee > 0.005 and return index and value
132+
133+
134+
def get_wallet_details():
135+
"""Return basic wallet details as a tuple.
136+
137+
Returns:
138+
Tuple containing (wallet_name, balance)
139+
"""
140+
# TODO: Return a tuple with wallet name and balance
141+
142+
143+
def get_tx_status(tx_pool, txid):
144+
"""Get the status of a transaction from the mempool.
145+
146+
Args:
147+
tx_pool: Dictionary of txid -> status
148+
txid: Transaction ID to check
149+
150+
Returns:
151+
Status string or 'not found'
152+
"""
153+
# TODO: Use dict.get() to return tx status or 'not found' if missing
154+
155+
156+
def unpack_wallet_info(wallet_info):
157+
"""Unpack wallet information from a tuple and return a formatted string.
158+
159+
Args:
160+
wallet_info: Tuple of (wallet_name, balance)
161+
162+
Returns:
163+
Formatted string of wallet status
164+
"""
165+
# TODO: Unpack wallet_info tuple into name and balance, then format the return string
166+
167+
168+
def calculate_sats(btc: float) -> int:
169+
"""Convert BTC to satoshis (1 BTC = 100,000,000 sats).
170+
171+
Args:
172+
btc: Amount in Bitcoin
173+
174+
Returns:
175+
Equivalent amount in satoshis
176+
"""
177+
# TODO: Multiply btc by BTC_TO_SATS and return the integer value
178+
179+
180+
def generate_address(prefix: str = "bc1q") -> str:
181+
"""Generate a mock Bitcoin address with given prefix.
182+
183+
Args:
184+
prefix: Address prefix (default is bech32)
185+
186+
Returns:
187+
Mock address string
188+
"""
189+
# TODO: Generate a suffix of random alphanumeric characters (length = 32 - len(prefix))
190+
# TODO: Concatenate the prefix and suffix to form the mock address
191+
192+
193+
def validate_block_height(height: Union[int, float, str]) -> Tuple[bool, str]:
194+
"""Validate a Bitcoin block height.
195+
196+
Args:
197+
height: Block height to validate
198+
199+
Returns:
200+
Tuple of (is_valid, message)
201+
"""
202+
# TODO: Ensure height is an integer
203+
# TODO: Check that height is not negative
204+
# TODO: Check that height is within a realistic range (e.g., <= 800,000)
205+
206+
207+
def halving_schedule(blocks: List[int]) -> Dict[int, int]:
208+
"""Calculate block reward for given block heights based on halving schedule.
209+
210+
Args:
211+
blocks: List of block heights
212+
213+
Returns:
214+
Dictionary mapping block heights to their block reward in satoshis
215+
"""
216+
# TODO: Initialize the base reward in sats
217+
# TODO: Iterate through each block height, compute halvings, and calculate reward
218+
# TODO: Store results in a dictionary
219+
220+
221+
def find_utxo_with_min_value(utxos: List[Dict[str, int]], target: int) -> Dict[str, int]:
222+
"""Find the UTXO with minimum value that meets or exceeds target.
223+
224+
Args:
225+
utxos: List of UTXOs (each with 'value' key in sats)
226+
target: Minimum target value in sats
227+
228+
Returns:
229+
UTXO with smallest value >= target, or empty dict if none found
230+
"""
231+
# TODO: Filter UTXOs to those with value >= target
232+
# TODO: Return the one with the smallest value, or {} if none found
233+
234+
235+
def create_utxo(txid: str, vout: int, **kwargs) -> Dict[str, Union[str, int]]:
236+
"""Create a UTXO dictionary with optional additional fields."""
237+
# TODO: Create a base dictionary with txid and vout
238+
# TODO: Merge any extra keyword arguments into the base
239+

requirements.txt

Whitespace-only changes.

success.png

5.85 KB
Loading

0 commit comments

Comments
 (0)