-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathblock.py
More file actions
151 lines (129 loc) · 4.98 KB
/
block.py
File metadata and controls
151 lines (129 loc) · 4.98 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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import rlp
import trie
from rlp.sedes import big_endian_int, binary, CountableList
from utils import hash32, trie_root, address, sha3
from rlp.utils import encode_hex
from config import default_config
from transactions import Transaction
from utils import normalize_key, ecsign, privtoaddr, ecrecover_to_pub, int_to_bytes, encode_hex, bytes_to_int, encode_int8
from own_exceptions import InvalidBlock
secpk1n = 115792089237316195423570985008687907852837564279074904382605163141518161494337
null_address = b'\xff' * 20
class BlockHeader(rlp.Serializable):
fields = [
('prevhash', hash32),
('timestamp', big_endian_int),
('extra_data', binary),
('state_root', trie_root),
('tx_root', trie_root),
('number', big_endian_int),
('coinbase', address),
('random_number', hash32), #256 bit hash
('group_pubkey', binary), #Zero in all blocks except number % DKG_RENEWAL_INTERVAL == 0
('group_sig', binary),
('count', big_endian_int)
]
def __init__(self,
prevhash=default_config['GENESIS_PREVHASH'],
state_root=trie.BLANK_ROOT,
tx_root=trie.BLANK_ROOT,
number=0,
timestamp=0,
coinbase=default_config['GENESIS_COINBASE'],
extra_data='',
random_number=default_config['GENESIS_RANDOM_NO'],
group_pubkey=default_config['GENESIS_GROUP_PUBLIC_KEY'],
group_sig=default_config['GENESIS_GROUP_SIGNATURE'],
count = 0):
self.prevhash = prevhash
self.coinbase = coinbase
self.state_root = state_root
self.tx_root = tx_root
self.number = number
self.timestamp = timestamp
self.extra_data = extra_data
self.random_number = random_number
self.group_pubkey = group_pubkey
self.group_sig = group_sig
self.count = count
@property
def hash(self):
return sha3(rlp.encode(self))
@property
def hex_hash(self):
return encode_hex(self.hash)
class FakeHeader():
def __init__(self, hash='\x00' * 32, number=0, timestamp=0):
self.hash = hash
self.number = number
self.timestamp = timestamp
def to_block_header(self):
return BlockHeader(
number=self.number,
timestamp=self.timestamp
)
class Block(rlp.Serializable):
fields = [
('header', BlockHeader),
('transactions', CountableList(Transaction)),
('v', big_endian_int),
('r', big_endian_int),
('s', big_endian_int)
]
_signer = None
def __init__(self, header, transactions=None, v=0,r=0,s=0):
self.header = header
self.transactions = transactions or []
self.v = v
self.r = r
self.s = s
def sign(self, key, network_id=None):
if network_id is None:
rawhash = sha3(rlp.encode(self, UnsignedBlock))
else:
assert 1 <= network_id < 2 ** 63 - 18
rlpdata = rlp.encode(rlp.infer_sedes(self).serialize(self)[
:-3] + [network_id, b'', b''])
rawhash = sha3(rlpdata)
key = normalize_key(key)
self.v, self.r, self.s = ecsign(rawhash, key)
if network_id is not None:
self.v += 8 + network_id * 2
self._signer = privtoaddr(key)
return self
@property
def signer(self):
if not self._signer:
if self.r == 0 and self.s == 0:
if self.header.number == 0:
pub = b"\x00" * 64
self._signer = sha3(pub)[-20:]
print("GENESIS BLOCK")
self._signer = null_address
else:
if self.v in (27, 28):
vee = self.v
sighash = sha3(rlp.encode(self, UnsignedBlock))
elif self.v >= 37:
vee = self.v - self.network_id * 2 - 8
assert vee in (27, 28)
rlpdata = rlp.encode(rlp.infer_sedes(self).serialize(self)[
:-3] + [self.network_id, '', ''])
sighash = sha3(rlpdata)
if self.r >= secpk1n or self.s >= secpk1n or self.r == 0 or self.s == 0:
raise InvalidBlock("Invalid signature values!")
pub = ecrecover_to_pub(sighash, self.v, self.r, self.s)
if pub == b"\x00" * 64:
raise InvalidBlock(
"Invalid signature (zero privkey cannot sign)")
self._signer = sha3(pub)[-20:]
return self._signer
def __getattribute__(self, name):
try:
return rlp.Serializable.__getattribute__(self, name)
except AttributeError:
return getattr(self.header, name)
@property
def transaction_count(self):
return len(self.transactions)
UnsignedBlock = Block.exclude(['v', 'r', 's'])