- Duy The Dang(dtd2125)
- Shivam Chaturvedi (sc5588)
- Angela Peng (ap4636)
- Luigi Liu (ll3840)
DemoApp/
├── init.py # Package marker
├── script.js # Frontend logic (for 1 client)
├── scriptv2.js # Frontend logic (for use if want to test another client)
├── style.css # Styles for wallet UI
├── wallet_api.py # Flask backend API for wallet interaction
├── wallet_ui.html # Wallet UI (for 1 client)
├── wallet_ui_v2.html # Wallet UI (for use if want to test another client)
├── wallet.py # Wallet logic (includes WalletApp)
- Generate and use a new wallet key pair
- View public wallet address
- View live balance (via polling)
- Send signed transactions
- View blockchain blocks and transactions
- Simple modal UI for transaction details
- Python 3.8+
- Flask (backend)
requests
(for inter-service HTTP)- Bootstrap 5 (for frontend UI)
blockchain/
├── **init**.py # Package marker
├── block.py # Block structure & proof‑of‑work logic
├── blockchain.py # Chain management, validation, fork resolution
├── node.py # High‑level node that ties P2P, mempool & mining
└── utils.py # Helper functions (hashing, timestamps, etc.)
File | Main Classes / Functions | Responsibilities |
---|---|---|
block.py | Block |
‑ Immutable record containing index , prev_hash , timestamp , nonce , transactions , and hash ‑ Implements mine() (incrementing nonce until hash meets difficulty ) ‑ Provides is_valid() for self‑validation |
blockchain.py | Blockchain |
‑ Maintains the canonical chain and orphan branches ‑ Validates and appends blocks, resolves forks (longest‑valid‑chain rule) ‑ Tracks current mempool and exposes add_new_transaction() / mine_pending_transactions() ‑ Utility methods: get_main_chain() , get_balance(addr) |
node.py | BlockchainNode |
‑ Combines a Blockchain instance with a P2PNode ‑ Background threads for mining and for receiving network data ‑ Broadcasts newly mined / received blocks, adds incoming transactions to mempool |
utils.py | current_ts() , hashing helpers, TxType enum |
‑ Simple utility layer so core classes stay focused |
-
Transaction creation (from DemoApp or other peers) → added to
mempool
. -
Mining loop (
node._mine_loop
):- pulls pending transactions, builds a candidate
Block
, runs PoW viaBlock.mine()
. - upon success, broadcasts the block to peers.
- pulls pending transactions, builds a candidate
-
Block reception (
node.receive_network_data
):- validates block; if valid and builds a longer chain, inserts into
Blockchain
. - If the block originates a fork, side‑chains are tracked and pruned when they fall ≥6 blocks behind.
- validates block; if valid and builds a longer chain, inserts into
difficulty
= number of leading zeros required in SHA‑256 block hash.- Adjustable when instantiating
Blockchain(difficulty=…)
orBlockchainNode
.
from blockchain.blockchain import Blockchain
from transactions.transaction import Transaction, TxType
from crypto.key\_pair import KeyPair
bc = Blockchain(difficulty=2)
alice, bob = KeyPair(), KeyPair()
# Mint coins to Alice
mint = Transaction(TxType.ASSIGN, sender="", recipient=alice.public, amount=10); mint.sign(alice)
bc.add\_new\_transaction(mint); bc.mine\_pending\_transactions()
# Transfer
pay = Transaction(TxType.TRANSFER, sender=alice.public, recipient=bob.public, amount=3); pay.sign(alice)
bc.add\_new\_transaction(pay); bc.mine\_pending\_transactions()
print("Alice:", bc.get\_balance(alice.public)) # -> 7
print("Bob:", bc.get\_balance(bob.public)) # -> 3
Note: networking is optional—running
Blockchain
in isolation is perfect for unit tests or demos; addBlockchainNode
when you need peer discovery and block propagation.
Add a more detailed directory map for p2p and blockchain here once implementation stabilises.
The WalletApp
class under DemoApp/wallet.py
handles key wallet operations:
Method | Description |
---|---|
get_public_key_str() |
Returns the public key as a string (used as the wallet address). |
sign_transaction(message: dict) |
Signs the basic transaction payload using the private key. |
create_transaction(recipient, amount, sign=True) |
Builds a transaction to the given recipient and optionally signs it. |
compute_txid(tx: dict) |
Computes a SHA-256 hash of the transaction data, excluding the signature. |
DemoApp/wallet_api.py
Endpoint | Method | Description |
---|---|---|
/wallet/address |
GET | Fetch the wallet's public key |
/transaction/send |
POST | Send a transaction to the blockchain |
/blockchain |
GET | Retrieve the current blockchain |
/connect |
POST | Register this wallet with the network |
For testing purposes, we have encapsulated the starting of all the nodes under a single application layer. All these nodes are running under different ports but the same process. While this might not be how it would be done ideally, we did this for ease of testing locally.
Command:
python3 -m application.application <application_ip> <application_port> <tracker_ip> <tracker_port> <list_of_blockchain_node_ip_and_ports>
- Start the blockchain backend (port 60000)
- Start the wallet API (Flask app on port 5050)
cd DemoApp
python3 wallet_api.py 5050
- Open
http://localhost:8080/wallet_ui.html
in your browser after running the following command
cd DemoApp
python3 -m http.server 8080
// Send 5 BTC to another address
fetch("http://localhost:5050/transaction/send", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
to: "recipient_public_key_here",
amount: 5,
sign: true
})
}).then(res => res.json()).then(console.log);
The app is designed to connect the wallet to the blockchain only once per session using a flag stored in the browser's localStorage
:
localStorage.setItem("cw_connected_once", "true");
This prevents repeated /connect requests on each page reload. However, if you manually restart the backend server (e.g., using Ctrl+C and restarting Flask), the browser is not aware of it, and the connection flag will persist.
To reconnect after restarting the backend, open DevTools in your browser and manually remove the cw_connected_once
item from localStorage:
- Open DevTools (F12 or right-click → Inspect)
- Go to the Application tab
- Under Storage → Local Storage, select your app’s URL
- Find and delete the
cw_connected_once
key - Refresh the page
This will force the wallet to re-send the connection request.
Also Note: This is a demo app. Wallet keys are not persisted across sessions. In a real system, we'd want secure key storage, transaction validation, and persistent nodes.
Check the main section of p2p/p2p_node.py and p2p/p2p_tracker.py for instructions on running tests for P2P implementation.