-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathblock.py
More file actions
96 lines (81 loc) · 3.62 KB
/
Copy pathblock.py
File metadata and controls
96 lines (81 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
"""
block.py — Defines the Block class, the fundamental unit of the blockchain.
Each block contains:
- An index (its position in the chain)
- A timestamp (when it was created)
- A list of transactions
- The hash of the previous block (what "chains" them together)
- A nonce (the number found during Proof of Work mining)
- Its own SHA-256 hash
"""
import hashlib
import json
from datetime import datetime
class Block:
"""
Represents a single block in the blockchain.
A block is like a page in a ledger. Each page records a batch of
transactions, is timestamped, and is cryptographically sealed by
referencing the previous page's seal (hash). Tampering with any
block breaks every subsequent block's seal.
"""
def __init__(self, index: int, transactions: list, previous_hash: str, nonce: int = 0):
"""
Initialize a new block.
Args:
index : Position of this block in the chain (0 = genesis block).
transactions : List of transaction dicts recorded in this block.
previous_hash: SHA-256 hash of the preceding block.
nonce : Starts at 0; incremented during Proof of Work mining
until the block hash meets the difficulty target.
"""
self.index = index
self.timestamp = datetime.utcnow().isoformat() # ISO-8601 UTC time string
self.transactions = transactions # List of transaction dicts
self.previous_hash = previous_hash # Links this block to the chain
self.nonce = nonce # Proof of Work counter
self.hash = self.compute_hash() # Seal the block immediately
def compute_hash(self) -> str:
"""
Compute the SHA-256 hash of this block's contents.
We serialize the block to a deterministic JSON string (sort_keys=True
ensures consistent ordering) and then hash those bytes.
Returns:
A 64-character hexadecimal SHA-256 digest string.
Why SHA-256?
- Deterministic: same input always → same hash.
- One-way: you cannot reverse a hash to get the original data.
- Avalanche effect: changing even 1 bit completely changes the hash.
"""
# Build a plain dict of every field that defines this block's identity
block_dict = {
"index" : self.index,
"timestamp" : self.timestamp,
"transactions" : self.transactions,
"previous_hash": self.previous_hash,
"nonce" : self.nonce,
}
# Serialize to a UTF-8 JSON string with sorted keys for reproducibility
block_string = json.dumps(block_dict, sort_keys=True).encode("utf-8")
# Return the hex-encoded SHA-256 digest
return hashlib.sha256(block_string).hexdigest()
def to_dict(self) -> dict:
"""
Convert this block to a plain Python dictionary.
Useful for JSON serialization (saving the chain to disk, API responses).
"""
return {
"index" : self.index,
"timestamp" : self.timestamp,
"transactions" : self.transactions,
"previous_hash": self.previous_hash,
"nonce" : self.nonce,
"hash" : self.hash,
}
def __repr__(self) -> str:
"""Human-readable string representation for debugging."""
return (
f"Block(index={self.index}, "
f"transactions={len(self.transactions)}, "
f"hash={self.hash[:12]}...)"
)