def add_block(self, block, forward_pending_transactions=True): "returns True if block was added sucessfully" _log = log.bind(block_hash=block) # make sure we know the parent if not block.has_parent() and not block.is_genesis(): _log.debug('missing parent') return False if not block.validate_uncles(): _log.debug('invalid uncles') return False if not len(block.nonce) == 8: _log.debug('nonce not set') return False elif not block.header.check_pow(nonce=block.nonce) and\ not block.is_genesis(): _log.debug('invalid nonce') return False if block.has_parent(): try: processblock.verify(block, block.get_parent()) except processblock.VerificationFailed as e: _log.critical('VERIFICATION FAILED', error=e) f = os.path.join(utils.data_dir, 'badblock.log') open(f, 'w').write(to_string(block.hex_serialize())) return False if block.number < self.head.number: _log.debug("older than head", head_hash=self.head) # Q: Should we have any limitations on adding blocks? self.index.add_block(block) self._store_block(block) # set to head if this makes the longest chain w/ most work for that number if block.chain_difficulty() > self.head.chain_difficulty(): _log.debug('new head') self._update_head(block, forward_pending_transactions) elif block.number > self.head.number: _log.warn('has higher blk number than head but lower chain_difficulty', head_hash=self.head, block_difficulty=block.chain_difficulty(), head_difficulty=self.head.chain_difficulty()) block.transactions.clear_all() block.receipts.clear_all() block.state.db.commit_refcount_changes(block.number) block.state.db.cleanup(block.number) self.commit() # batch commits all changes that came with the new block return True
def _update_head(self, block, forward_pending_transactions=True): success = True reverted_blocks = [] if block.number > 0: b = block.get_parent() h = self.head b_children = [] if b.hash != h.hash: log_chain.warn('reverting') # revert head back to number of block.parent while h.number > b.number: reverted_blocks.append(h) h = h.get_parent() # if b's parent is ahead of head while b.number > h.number: b_children.append(b) b = b.get_parent() # b & h now have same number, wind back one at a time until # hashes match while b.hash != h.hash: reverted_blocks.append(h) h = h.get_parent() b_children.append(b) b = b.get_parent() for bc in b_children: success = success and verify(bc, bc.get_parent()) super(Chain, self)._update_head(block, forward_pending_transactions) # revert the db after chain.head is updated if success and reverted_blocks and self.revert_block_cb: self.revert_block_cb(reverted_blocks)
def _update_head(self, block, forward_pending_transactions=True): log.debug('updating head') if not block.is_genesis(): #assert self.head.chain_difficulty() < block.chain_difficulty() if block.get_parent() != self.head: log.debug('New Head is on a different branch', head_hash=block, old_head_hash=self.head) # Some temporary auditing to make sure pruning is working well if block.number > 0 and block.number % 500 == 0 and isinstance( self.db, RefcountDB): trie.proof.push(trie.RECORDING) block.to_dict(with_state=True) n = trie.proof.get_nodelist() trie.proof.pop() # log.debug('State size: %d\n' % sum([(len(rlp.encode(a)) + 32) for a in n])) # Fork detected, revert death row and change logs if block.number > 0: b = block.get_parent() h = self.head b_children = [] if b.hash != h.hash: log.warn('reverting') while h.number > b.number: h.state.db.revert_refcount_changes(h.number) h = h.get_parent() while b.number > h.number: b_children.append(b) b = b.get_parent() while b.hash != h.hash: h.state.db.revert_refcount_changes(h.number) h = h.get_parent() b_children.append(b) b = b.get_parent() for bc in b_children: processblock.verify(bc, bc.get_parent()) self.blockchain.put('HEAD', block.hash) assert self.blockchain.get('HEAD') == block.hash self.index.update_blocknumbers(self.head) assert self.head == block log.debug('set new head', head=self.head) self._update_head_candidate(forward_pending_transactions) if self.new_head_cb and not block.is_genesis(): self.new_head_cb(block)
def _update_head(self, block, forward_pending_transactions=True): log.debug('updating head') if not block.is_genesis(): #assert self.head.chain_difficulty() < block.chain_difficulty() if block.get_parent() != self.head: log.debug('New Head is on a different branch', head_hash=block, old_head_hash=self.head) # Some temporary auditing to make sure pruning is working well if block.number > 0 and block.number % 500 == 0 and isinstance(self.db, RefcountDB): trie.proof.push(trie.RECORDING) block.to_dict(with_state=True) n = trie.proof.get_nodelist() trie.proof.pop() # log.debug('State size: %d\n' % sum([(len(rlp.encode(a)) + 32) for a in n])) # Fork detected, revert death row and change logs if block.number > 0: b = block.get_parent() h = self.head b_children = [] if b.hash != h.hash: log.warn('reverting') while h.number > b.number: h.state.db.revert_refcount_changes(h.number) h = h.get_parent() while b.number > h.number: b_children.append(b) b = b.get_parent() while b.hash != h.hash: h.state.db.revert_refcount_changes(h.number) h = h.get_parent() b_children.append(b) b = b.get_parent() for bc in b_children: processblock.verify(bc, bc.get_parent()) self.blockchain.put('HEAD', block.hash) assert self.blockchain.get('HEAD') == block.hash self.index.update_blocknumbers(self.head) assert self.head == block log.debug('set new head', head=self.head) self._update_head_candidate(forward_pending_transactions) if self.new_head_cb and not block.is_genesis(): self.new_head_cb(block)