Skip to content
This repository was archived by the owner on May 23, 2023. It is now read-only.

Commit 2f8efd7

Browse files
author
Jan Xie
authored
Merge pull request #718 from ethereum/state_revamp_with_p62
Catch the mainnet
2 parents aafab5b + 9fe5dd9 commit 2f8efd7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+30874
-3230
lines changed

ethereum/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
match = GIT_DESCRIBE_RE.match(rev)
3232
if match:
3333
__version__ = "{}+git-{}".format(match.group("version"), match.group("git"))
34-
except:
34+
except: # FIXME!
3535
pass
3636

3737
if not __version__:

ethereum/abi.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
from ethereum import utils
1313
from ethereum.utils import (
14-
big_endian_to_int, ceil32, int_to_big_endian, encode_int, is_numeric, isnumeric, is_string,
14+
big_endian_to_int, ceil32, int_to_big_endian, encode_int, is_numeric, is_string,
1515
rzpad, TT255, TT256, zpad,
1616
)
1717

@@ -362,7 +362,7 @@ def encode_single(typ, arg): # pylint: disable=too-many-return-statements,too-m
362362
if not (int(sub) and int(sub) <= 32):
363363
raise EncodingError('too long: %r' % arg)
364364

365-
if isnumeric(arg):
365+
if is_numeric(arg):
366366
return zpad(encode_int(arg), 32)
367367

368368
if len(arg) == int(sub):
@@ -376,7 +376,7 @@ def encode_single(typ, arg): # pylint: disable=too-many-return-statements,too-m
376376
if base == 'address':
377377
assert sub == ''
378378

379-
if isnumeric(arg):
379+
if is_numeric(arg):
380380
return zpad(encode_int(arg), 32)
381381

382382
if len(arg) == 20:
@@ -734,9 +734,9 @@ def decode_single(typ, data):
734734
l = big_endian_to_int(data[0:32])
735735
return data[32:][:l]
736736
elif base == 'uint':
737-
return big_endian_to_int(data)
737+
return big_endian_to_int(data) % 2**int(sub)
738738
elif base == 'int':
739-
o = big_endian_to_int(data)
739+
o = big_endian_to_int(data) % 2 ** int(sub)
740740
return (o - 2 ** int(sub)) if o >= 2 ** (int(sub) - 1) else o
741741
elif base == 'ufixed':
742742
high, low = [int(x) for x in sub.split('x')]

ethereum/block.py

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
import rlp
2+
from ethereum.utils import normalize_address, hash32, trie_root, \
3+
big_endian_int, address, int256, encode_hex, encode_int, sha3
4+
from rlp.sedes import big_endian_int, Binary, binary, CountableList
5+
from ethereum import utils
6+
from ethereum import trie
7+
from ethereum.trie import Trie
8+
from ethereum.securetrie import SecureTrie
9+
from ethereum.config import default_config
10+
from ethereum.transactions import Transaction
11+
from ethereum.db import BaseDB
12+
import sys
13+
if sys.version_info.major == 2:
14+
from repoze.lru import lru_cache
15+
else:
16+
from functools import lru_cache
17+
18+
19+
class BlockHeader(rlp.Serializable):
20+
21+
"""A block header.
22+
23+
If the block with this header exists as an instance of :class:`Block`, the
24+
connection can be made explicit by setting :attr:`BlockHeader.block`. Then,
25+
:attr:`BlockHeader.state_root`, :attr:`BlockHeader.tx_list_root` and
26+
:attr:`BlockHeader.receipts_root` always refer to the up-to-date value in
27+
the block instance.
28+
29+
:ivar block: an instance of :class:`Block` or `None`
30+
:ivar prevhash: the 32 byte hash of the previous block
31+
:ivar uncles_hash: the 32 byte hash of the RLP encoded list of uncle
32+
headers
33+
:ivar coinbase: the 20 byte coinbase address
34+
:ivar state_root: the root of the block's state trie
35+
:ivar tx_list_root: the root of the block's transaction trie
36+
:ivar receipts_root: the root of the block's receipts trie
37+
:ivar bloom: TODO
38+
:ivar difficulty: the block's difficulty
39+
:ivar number: the number of ancestors of this block (0 for the genesis
40+
block)
41+
:ivar gas_limit: the block's gas limit
42+
:ivar gas_used: the total amount of gas used by all transactions in this
43+
block
44+
:ivar timestamp: a UNIX timestamp
45+
:ivar extra_data: up to 1024 bytes of additional data
46+
:ivar nonce: a 32 byte nonce constituting a proof-of-work, or the empty
47+
string as a placeholder
48+
"""
49+
50+
fields = [
51+
('prevhash', hash32),
52+
('uncles_hash', hash32),
53+
('coinbase', address),
54+
('state_root', trie_root),
55+
('tx_list_root', trie_root),
56+
('receipts_root', trie_root),
57+
('bloom', int256),
58+
('difficulty', big_endian_int),
59+
('number', big_endian_int),
60+
('gas_limit', big_endian_int),
61+
('gas_used', big_endian_int),
62+
('timestamp', big_endian_int),
63+
('extra_data', binary),
64+
('mixhash', binary),
65+
('nonce', binary)
66+
]
67+
68+
def __init__(self,
69+
prevhash=default_config['GENESIS_PREVHASH'],
70+
uncles_hash=utils.sha3rlp([]),
71+
coinbase=default_config['GENESIS_COINBASE'],
72+
state_root=trie.BLANK_ROOT,
73+
tx_list_root=trie.BLANK_ROOT,
74+
receipts_root=trie.BLANK_ROOT,
75+
bloom=0,
76+
difficulty=default_config['GENESIS_DIFFICULTY'],
77+
number=0,
78+
gas_limit=default_config['GENESIS_GAS_LIMIT'],
79+
gas_used=0,
80+
timestamp=0,
81+
extra_data='',
82+
mixhash=default_config['GENESIS_MIXHASH'],
83+
nonce=''):
84+
# at the beginning of a method, locals() is a dict of all arguments
85+
fields = {k: v for k, v in locals().items() if k != 'self'}
86+
if len(fields['coinbase']) == 40:
87+
fields['coinbase'] = decode_hex(fields['coinbase'])
88+
assert len(fields['coinbase']) == 20
89+
self.block = None
90+
super(BlockHeader, self).__init__(**fields)
91+
92+
@property
93+
def hash(self):
94+
"""The binary block hash"""
95+
return utils.sha3(rlp.encode(self))
96+
97+
@property
98+
def hex_hash(self):
99+
return encode_hex(self.hash)
100+
101+
@property
102+
def mining_hash(self):
103+
return utils.sha3(rlp.encode(self, BlockHeader.exclude(['mixhash', 'nonce'])))
104+
105+
@property
106+
def signing_hash(self):
107+
return utils.sha3(rlp.encode(self, BlockHeader.exclude(['extra_data'])))
108+
109+
def to_dict(self):
110+
"""Serialize the header to a readable dictionary."""
111+
d = {}
112+
for field in ('prevhash', 'uncles_hash', 'extra_data', 'nonce',
113+
'mixhash'):
114+
d[field] = b'0x' + encode_hex(getattr(self, field))
115+
for field in ('state_root', 'tx_list_root', 'receipts_root',
116+
'coinbase'):
117+
d[field] = encode_hex(getattr(self, field))
118+
for field in ('number', 'difficulty', 'gas_limit', 'gas_used',
119+
'timestamp'):
120+
d[field] = to_string(getattr(self, field))
121+
d['bloom'] = encode_hex(int256.serialize(self.bloom))
122+
assert len(d) == len(BlockHeader.fields)
123+
return d
124+
125+
def __repr__(self):
126+
return '<%s(#%d %s)>' % (self.__class__.__name__, self.number,
127+
encode_hex(self.hash)[:8])
128+
129+
def __eq__(self, other):
130+
"""Two blockheader are equal iff they have the same hash."""
131+
return isinstance(other, BlockHeader) and self.hash == other.hash
132+
133+
def __hash__(self):
134+
return utils.big_endian_to_int(self.hash)
135+
136+
def __ne__(self, other):
137+
return not self.__eq__(other)
138+
139+
140+
class Block(rlp.Serializable):
141+
142+
"""A block.
143+
144+
All attributes from the block header are accessible via properties
145+
(i.e. ``block.prevhash`` is equivalent to ``block.header.prevhash``). It
146+
is ensured that no discrepancies between header and block occur.
147+
148+
:param header: the block header
149+
:param transactions: a list of transactions which are replayed if the
150+
state given by the header is not known. If the
151+
state is known, `None` can be used instead of the
152+
empty list.
153+
:param uncles: a list of the headers of the uncles of this block
154+
:param db: the database in which the block's state, transactions and
155+
receipts are stored (required)
156+
:param parent: optional parent which if not given may have to be loaded from
157+
the database for replay
158+
"""
159+
160+
fields = [
161+
('header', BlockHeader),
162+
('transactions', CountableList(Transaction)),
163+
('uncles', CountableList(BlockHeader))
164+
]
165+
166+
def __init__(self, header, transactions=None, uncles=None, db=None):
167+
# assert isinstance(db, BaseDB), "No database object given"
168+
# self.db = db
169+
170+
self.header = header
171+
self.transactions = transactions or []
172+
self.uncles = uncles or []
173+
self.uncles = list(self.uncles)
174+
175+
def __getattribute__(self, name):
176+
try:
177+
return rlp.Serializable.__getattribute__(self, name)
178+
except AttributeError:
179+
return getattr(self.header, name)
180+
181+
# TODO: remove chain_difficulty mock
182+
def chain_difficulty(self):
183+
return self.header.number + 1
184+
185+
@property
186+
def transaction_count(self):
187+
return len(self.transactions)
188+
189+
190+
BLANK_UNCLES_HASH = sha3(rlp.encode([]))
191+
192+
193+
class FakeHeader():
194+
195+
def __init__(self, hash='\x00' * 32, number=0, timestamp=0, difficulty=1, gas_limit=3141592, gas_used=0, uncles_hash=BLANK_UNCLES_HASH):
196+
self.hash = hash
197+
self.number = number
198+
self.timestamp = timestamp
199+
self.difficulty = difficulty
200+
self.gas_limit = gas_limit
201+
self.gas_used = gas_used
202+
self.uncles_hash = uncles_hash

ethereum/block_creation.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import time
2+
import rlp
3+
from ethereum.config import default_config
4+
from ethereum.state_transition import check_gaslimit, initialize, \
5+
validate_uncles, pre_seal_finalize, mk_receipt_sha, mk_transaction_sha, \
6+
apply_transaction
7+
from ethereum.consensus_strategy import get_consensus_strategy
8+
from ethereum.exceptions import InsufficientBalance, BlockGasLimitReached, \
9+
InsufficientStartGas, InvalidNonce, UnsignedTransaction
10+
from ethereum.utils import sha3
11+
from ethereum.state import State
12+
from ethereum import casper_utils, ethpow_utils
13+
from ethereum.slogging import get_logger
14+
log = get_logger('eth.block_creation')
15+
16+
17+
def add_transactions(state, block, txqueue, min_gasprice=0):
18+
pre_txs = len(block.transactions)
19+
log.info('Adding transactions, %d in txqueue, %d dunkles' % (len(txqueue.txs), pre_txs))
20+
while 1:
21+
tx = txqueue.pop_transaction(max_gas=state.gas_limit - state.gas_used,
22+
min_gasprice=min_gasprice)
23+
if tx is None:
24+
break
25+
try:
26+
apply_transaction(state, tx)
27+
block.transactions.append(tx)
28+
except (InsufficientBalance, BlockGasLimitReached, InsufficientStartGas,
29+
InvalidNonce, UnsignedTransaction) as e:
30+
pass
31+
log.info('Added %d transactions' % (len(block.transactions) - pre_txs))
32+
33+
34+
def pre_seal(state, block):
35+
pre_seal_finalize(state, block)
36+
block.header.receipts_root = mk_receipt_sha(state.receipts)
37+
block.header.tx_list_root = mk_transaction_sha(block.transactions)
38+
state.commit()
39+
block.header.state_root = state.trie.root_hash
40+
block.header.gas_used = state.gas_used
41+
block.header.bloom = state.bloom
42+
log.info('Block pre-sealed, %d gas used' % state.gas_used)
43+
44+
45+
def make_head_candidate(chain, txqueue,
46+
parent=None,
47+
timestamp=None,
48+
coinbase='\x35'*20,
49+
extra_data='moo ha ha says the laughing cow.',
50+
min_gasprice=0):
51+
log.info('Creating head candidate')
52+
if parent is None:
53+
temp_state = State.from_snapshot(chain.state.to_snapshot(root_only=True), chain.env)
54+
else:
55+
temp_state = chain.mk_poststate_of_blockhash(parent.hash)
56+
57+
cs = get_consensus_strategy(chain.env.config)
58+
block = cs.block_setup(chain, temp_state, timestamp, coinbase, extra_data)
59+
add_transactions(temp_state, block, txqueue, min_gasprice)
60+
pre_seal(temp_state, block)
61+
assert validate_uncles(temp_state, block)
62+
log.info('Created head candidate successfully')
63+
return block

0 commit comments

Comments
 (0)