-
Notifications
You must be signed in to change notification settings - Fork 51
/
Copy pathchain.py
98 lines (94 loc) · 3.77 KB
/
chain.py
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
97
98
import block as B
GENESIS_BLOCK = B.BlockTX([])
GENESIS_HEADER = B.BlockHeader(0, GENESIS_BLOCK.hash(), None,"me", 0)
class UTXO(object):
def __init__(self, owner, amount, parent, index):
self.owner = owner
self.amount = amount
self.parent = parent
self.index = index
def hash(self):
return sha(self.serialize())
def serialize(self):
return str((self.owner, self.amount, self.parent, self.index))
class UTXOSET(object):
def __init__(self, tx):
self.utxos = tx
def process_block(self, block, reward_address):
used = set([])
for tx in block.txs:
if tx.parent in used:
raise ValueError("Double Spend")
if tx.parent not in utxos:
raise ValueError("No Such TX")
if not self.utxos[tx.parent].amount >= tx.amount_spent():
raise ValueError("Too Much Spent")
used.add(tx.parent)
new_set = self.utxos.copy()
for txid in used:
del new_set[txid]
for tx in block.txs:
for index, (owner, amount) in enumerate(tx.to_amounts):
u = UTXO(owner, amount, tx.parent, index)
new_set[u.hash()] = u
# This is where babies come from
reward_tx = UTXO(reward_address, BLOCK_REWARD, "", 0)
new_set[reward_tx.hash()] = reward_tx
return UTXOSET(new_set)
class ChainNode(object):
def __init__(self, header, transactions, utxoset):
self.header = header
self.transactions = transactions
self.utxoset = utxoset
# Add ASCII Data Structure
class Chain(object):
def __init__(self):
self.chain = [{GENESIS_HEADER.hash(): ChainNode(GENESIS_HEADER,
GENESIS_BLOCK,
UTXOSET({}))}]
self.max_height = 0
self.pending_tx = B.BlockTX([])
@staticmethod
def make_new_utxo_set(parent, child, header):
if not pow(header.hash(), BOUND):
raise ValueError("Not enough Proof of Work")
return parent.process_block(block, header.reward_address)
def add_block(self, header, block):
# Refactor to do this after (important for correctness)
if self.max_height == header.height -1:
self.max_height +=1
self.chain.append({})
if header.hash() in self.chain[header.height]:
return self
if self.max_height >= header.height:
return self #TODO: Out of order block, deal with later elegantly
if header.prev in self.chain[header.height-1]:
parent = self.chain[header.height-1][h.prev]
if header.height != parent.header.height+1:
raise ValueError("Invalid Block Height for Parent (Internal Error)")
try:
new_utxoset = Chain.make_new_utxo_set(parent.utxoset, block, header)
except ValueError as e:
print e, "Bad Block, rejected!"
finally:
self.chain[header.height][header.hash()] = ChainNode(header, block, new_utxoset)
self.max_height = max(h.height, self.max_height)
return self
def add_tx(self, tx):
pass
def get_work(self):
""" Returns a header just for mining"""
d = self.max_height
while True:
for parent, _ in self.chain[self.max_height].iteritems():
prev = parent
break
else:
d -= 1
return (B.BlockHeader(d+1, self.pending_tx.hash(), prev, ""), self.pending_tx)
def lookup_tx(self, txid):
""" Returns data on a utxo"""
return "{'error':-1}"
def prune(self):
""" Can remove old forks/UTXO sets over time"""
pass