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

Commit 765c7b5

Browse files
committed
fix uncles in head candidate
1 parent fbd2085 commit 765c7b5

File tree

2 files changed

+64
-41
lines changed

2 files changed

+64
-41
lines changed

ethereum/blocks.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
UNCLE_DEPTH_PENALTY_FACTOR = 8
8181
NEPHEW_REWARD = BLOCK_REWARD / 32
8282
MAX_UNCLE_DEPTH = 6 # max (block.number - uncle.number)
83+
MAX_UNCLES = 2
8384
# Difficulty adjustment constants
8485
DIFF_ADJUSTMENT_CUTOFF = 8
8586
BLOCK_DIFF_FACTOR = 2048
@@ -360,6 +361,19 @@ def to_dict(self):
360361
assert len(d) == len(BlockHeader.fields)
361362
return d
362363

364+
def __repr__(self):
365+
return '<BlockHeader(#%d %s)>' % (self.number, encode_hex(self.hash)[:8])
366+
367+
def __eq__(self, other):
368+
"""Two blockheader are equal iff they have the same hash."""
369+
return isinstance(other, BlockHeader) and self.hash == other.hash
370+
371+
def __hash__(self):
372+
return utils.big_endian_to_int(self.hash)
373+
374+
def __ne__(self, other):
375+
return not self.__eq__(other)
376+
363377

364378
def mirror_from(source, attributes, only_getters=True):
365379
"""Decorator (factory) for classes that mirror some attributes from an
@@ -646,14 +660,14 @@ def transaction_list(self):
646660
txs.append(self.get_transaction(i))
647661
return txs
648662

649-
def validate_uncles(self, db=None):
663+
def validate_uncles(self):
650664
"""Validate the uncles of this block."""
651665
if utils.sha3(rlp.encode(self.uncles)) != self.uncles_hash:
652666
return False
653-
if len(self.uncles) > 2:
667+
if len(self.uncles) > MAX_UNCLES:
654668
return False
655669
for uncle in self.uncles:
656-
assert db is None or uncle.prevhash in self.db
670+
assert uncle.prevhash in self.db
657671
if uncle.number == self.number:
658672
log.error("uncle at same block height", block=self)
659673
return False

ethereum/chain.py

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -146,31 +146,58 @@ def _update_head(self, block):
146146
head_hash=block, old_head_hash=self.head)
147147
self.blockchain.put('HEAD', block.hash)
148148
self.index.update_blocknumbers(self.head)
149+
self._update_head_candidate()
150+
if self.new_head_cb and not block.is_genesis():
151+
self.new_head_cb(block)
152+
153+
def _update_head_candidate(self):
154+
"after new head is set"
149155

150-
# update head candidate
151-
transactions = self.get_transactions()
152-
blk = self.head
153-
uncles = set(u.header for u in self.get_brothers(self.head))
154-
for i in range(8):
155-
for u in blk.uncles: # assuming uncle headers
156-
u = utils.sha3(rlp.encode(u))
157-
if u in self:
158-
uncles.discard(self.get(u))
156+
# collect uncles
157+
blk = self.head # parent of the block we are collecting uncles for
158+
uncles = set(u.header for u in self.get_brothers(blk))
159+
for i in range(blocks.MAX_UNCLE_DEPTH + 2):
160+
for u in blk.uncles:
161+
assert isinstance(u, blocks.BlockHeader)
162+
uncles.discard(u)
159163
if blk.has_parent():
160164
blk = blk.get_parent()
165+
assert not uncles or max(u.number for u in uncles) <= self.head.number
166+
uncles = list(uncles)[:blocks.MAX_UNCLES]
167+
168+
# create block
169+
ts = max(int(time.time()), self.head.timestamp + 1)
170+
head_candidate = blocks.Block.init_from_parent(self.head, coinbase=self._coinbase,
171+
timestamp=ts, uncles=uncles)
172+
assert head_candidate.validate_uncles()
173+
174+
self.pre_finalize_state_root = head_candidate.state_root
175+
head_candidate.finalize()
161176

162-
uncles = list(uncles)
163-
ts = max(int(time.time()), block.timestamp + 1)
164-
self.head_candidate = blocks.Block.init_from_parent(block, coinbase=self._coinbase,
165-
timestamp=ts, uncles=uncles)
166-
self.pre_finalize_state_root = self.head_candidate.state_root
167-
self.head_candidate.finalize()
168177
# add transactions from previous head candidate
169-
for tx in transactions:
170-
self.add_transaction(tx)
178+
old_head_candidate = self.head_candidate
179+
self.head_candidate = head_candidate
180+
if old_head_candidate is not None:
181+
for tx in old_head_candidate.get_transactions():
182+
self.add_transaction(tx)
171183

172-
if self.new_head_cb and not block.is_genesis():
173-
self.new_head_cb(block)
184+
def get_uncles(self, block):
185+
"""Return the uncles of `block`."""
186+
if not block.has_parent():
187+
return []
188+
else:
189+
return self.get_brothers(block.get_parent())
190+
191+
def get_brothers(self, block):
192+
"""Return the uncles of the hypothetical child of `block`."""
193+
o = []
194+
i = 0
195+
while block.has_parent() and i < blocks.MAX_UNCLE_DEPTH:
196+
parent = block.get_parent()
197+
o.extend([u for u in self.get_children(parent) if u != block])
198+
block = block.get_parent()
199+
i += 1
200+
return o
174201

175202
def get(self, blockhash):
176203
assert is_string(blockhash)
@@ -199,7 +226,7 @@ def add_block(self, block, forward=False):
199226
_log.debug('missing parent')
200227
return False
201228

202-
if not block.validate_uncles(self.db):
229+
if not block.validate_uncles():
203230
_log.debug('invalid uncles')
204231
return False
205232

@@ -243,24 +270,6 @@ def add_block(self, block, forward=False):
243270
def get_children(self, block):
244271
return [self.get(c) for c in self.index.get_children(block.hash)]
245272

246-
def get_brothers(self, block):
247-
"""Return the uncles of the hypothetical child of `block`."""
248-
o = []
249-
i = 0
250-
while block.has_parent() and i < 6:
251-
parent = block.get_parent()
252-
o.extend([u for u in self.get_children(parent) if u != block])
253-
block = parent
254-
i += 1
255-
return o
256-
257-
def get_uncles(self, block):
258-
"""Return the uncles of `block`."""
259-
if not block.has_parent():
260-
return []
261-
else:
262-
return self.get_brothers(block.get_parent())
263-
264273
def add_transaction(self, transaction):
265274
"""Add a transaction to the :attr:`head_candidate` block.
266275

0 commit comments

Comments
 (0)