def epoch_info(epoch): height = epoch * 50 + 49 block = eth.chain.get_block_by_number(height) blockhash = block.hash ts = block.timestamp temp_state = eth.chain.mk_poststate_of_blockhash(blockhash) casper = tester.ABIContract(tester.State(temp_state), casper_utils.casper_abi, eth.chain.config['CASPER_ADDRESS']) ce, ese = casper.get_current_epoch(), casper.get_expected_source_epoch() deposit_scale_factor = casper.get_deposit_scale_factor(ce) storage = len( tester.State(temp_state).state.account_to_dict( eth.chain.config['CASPER_ADDRESS'])["storage"]) info = {} info["number"] = height info["blockhash"] = encode_hex(blockhash) info["timestamp"] = ts info["difficulty"] = block.difficulty info["current_epoch"] = ce info["validators"] = validators(casper, deposit_scale_factor) info["lje"] = casper.get_last_justified_epoch() info["lfe"] = casper.get_last_finalized_epoch() info["votes"] = votes_and_deposits(casper, ce, ese, deposit_scale_factor) info["deposit_scale_factor"] = deposit_scale_factor info["storage"] = storage return info
def generate_commit_message(self, state): epoch = state.block_number // self.epoch_length # PREPARE_COMMIT_CONSISTENCY if self.prev_prepare_epoch < self.prev_commit_epoch and self.prev_commit_epoch < epoch: return None # Create a Casper contract which we can use to get related values casper = tester.ABIContract(tester.State(state), casper_utils.casper_abi, self.chain.casper_address) validator_index = self.get_validator_index(state) _e, _a, _se, _sa, _pce = self.get_recommended_casper_msg_contents( casper, validator_index) # Make the commit message commit_msg = casper_utils.mk_commit(validator_index, _e, _a, _pce, self.key) try: # Attempt to submit the commit, to make sure that it doesn't doesn't violate DBL_PREPARE & it is justified casper.commit(commit_msg) except tester.TransactionFailed: log.info( 'Commit failed! Validator {} - blockhash {} - valcode addr {}'. format(self.get_validator_index(state), self.epoch_blockhash(state, epoch), utils.encode_hex(self.valcode_addr))) return None # Save the commit as now our last commit epoch log.info( 'Commit submitted: validator %d - epoch %d - prev_commit_epoch %d - hash %s' % (self.get_validator_index(state), epoch, self.prev_commit_epoch, utils.encode_hex(self.epoch_blockhash(state, epoch)))) self.prev_commit_epoch = epoch return commit_msg
def get_validator_index(self, state): t = tester.State(state.ephemeral_clone()) t.state.gas_limit = 9999999999 casper = tester.ABIContract(t, casper_utils.casper_abi, self.chain.casper_address) if self.valcode_addr is None: raise Exception('Valcode address not set') try: return casper.get_validator_indexes(self.coinbase) except tester.TransactionFailed: return None
def generate_prepare_message(self, state): epoch = state.block_number // self.epoch_length # NO_DBL_PREPARE: Don't prepare if we have already if epoch in self.prepares: return None # Create a Casper contract which we can use to get related values casper = tester.ABIContract(tester.State(state), casper_utils.casper_abi, self.chain.casper_address) # Get the ancestry hash and source ancestry hash validator_index = self.get_validator_index(state) _e, _a, _se, _sa, _pce = self.get_recommended_casper_msg_contents( casper, validator_index) # PREPARE_COMMIT_CONSISTENCY if _se < self.prev_commit_epoch and self.prev_commit_epoch < epoch: return None prepare_msg = casper_utils.mk_prepare(validator_index, _e, _a, _se, _sa, self.key) try: # Attempt to submit the prepare, to make sure that it is justified casper.prepare(prepare_msg) except tester.TransactionFailed: log.info( 'Prepare failed! Validator {} - hash justified {} - validator start {} - valcode addr {}' .format( self.get_validator_index(state), casper.get_consensus_messages__ancestry_hash_justified( epoch, _a), casper.get_validators__dynasty_start(validator_index), utils.encode_hex(self.valcode_addr))) return None # Save the prepare message we generated self.prepares[epoch] = prepare_msg # Save the highest source epoch we have referenced in our prepare's source epoch if epoch > self.prev_prepare_epoch: self.prev_prepare_epoch = epoch log.info( 'Prepare submitted: validator %d - epoch %d - prev_commit_epoch %d - hash %s' % (self.get_validator_index(state), epoch, self.prev_commit_epoch, utils.encode_hex(self.epoch_blockhash(state, epoch)))) return prepare_msg
def add_block(self, block): # ~~~ Validate ~~~~ # # Validate that the block should be added if not self.should_add_block(block): return False # ~~~ Store ~~~~ # # Store the block self.db.put(block.header.hash, rlp.encode(block)) self.add_child(block) if block.number % self.config['EPOCH_LENGTH'] == 0: self.db.put(b'cp_subtree_score' + block.hash, 0) # Store the state root if block.header.prevhash == self.head_hash: temp_state = self.state.ephemeral_clone() else: temp_state = self.mk_poststate_of_blockhash(block.header.prevhash) apply_block(temp_state, block) self.db.put(b'state:' + block.header.hash, temp_state.trie.root_hash) # ~~~ Finality Gadget Fork Choice ~~~~ # old_head_chekpoint = self.head_checkpoint # Store the new score cp_hash = self.get_prev_checkpoint_hash(block.hash) casper = tester.ABIContract(tester.State(temp_state), casper_utils.casper_abi, self.config['CASPER_ADDRESS']) try: new_score = casper.get_main_hash_committed_frac() log.info('Got new score! {}'.format(new_score)) except tester.TransactionFailed: new_score = 0 if self.get_checkpoint_score( cp_hash) < new_score or self.get_checkpoint_score( cp_hash) == 0: log.info( 'Updating checkpoint score. Block num: {} - New Score: {}'. format(self.get_block(cp_hash).number, new_score)) self.db.put(b'cp_score:' + cp_hash, new_score) # Update our view self.update_subtree_scores_and_child_pointers(cp_hash) cp = self.get_block(cp_hash) # Store the block as its checkpoint child if is is heavier than the current child p_cp = cp while cp is not self.genesis and self.get_checkpoint_score( cp.hash) == 0: cp = self.get_prev_checkpoint_block(cp) log.info( 'Recieved block. Block num: {} - Prev cp num: {} - Prev committed cp num: {} - Head cp num: {} - Prev committed cp score: {} - Current head cp score: {}' .format(block.number, p_cp.number, cp.number, self.head_checkpoint.number, self.get_checkpoint_score(cp.hash), self.get_checkpoint_score(self.checkpoint_head_hash))) log.info('head cp hash: {} - block prev cp hash: {}'.format( utils.encode_hex(cp_hash), utils.encode_hex(self.checkpoint_head_hash))) # Recompute head self.recompute_head_checkpoint(cp) # Set a new head if required log.info('Head cp num: {} - block prev cp num: {}'.format( self.head_checkpoint.number, cp.number)) if self.head_checkpoint == cp: if self.head_checkpoint == old_head_chekpoint: log.info( 'Head checkpoint == old head. CP Head Num: {} - Head diff: {} - Block diff: {}' .format(self.head_checkpoint.number, self.get_pow_difficulty(self.head), self.get_pow_difficulty(block))) if self.get_pow_difficulty( self.head) < self.get_pow_difficulty(block): self.set_head(block) else: log.info('Head checkpoint changed to cp number: {}'.format( self.head_checkpoint.number)) new_head, _ = self.find_heaviest_pow_block( self.head_checkpoint) self.set_head(new_head) else: log.info('Skipping block: Head checkpoint is not equal to cp!') # Are there blocks that we received that were waiting for this block? # If so, process them. if block.header.hash in self.parent_queue: for _blk in self.parent_queue[block.header.hash]: self.add_block(_blk) del self.parent_queue[block.header.hash] return True
def mk_casper_tester(validator): return tester.ABIContract(tester.State(validator.chain.state), casper_utils.casper_abi, validator.chain.casper_address)
cd docker-pyeth-dev docker run -it --rm \ -v $PWD/bootstrap/data/config:/root/.config/pyethapp \ -p 30303:30303 \ -p 30303:30303/udp \ -p 8545:8545 \ --name pyethapp \ ethresearch/pyethapp-research:beta-testnet \ pyethapp run # Enter console with Ctrl-C """ from ethereum.tools import tester from ethereum.hybrid_casper import casper_utils from ethereum.utils import encode_hex casper = tester.ABIContract(tester.State(eth.chain.state), casper_utils.casper_abi, eth.chain.config['CASPER_ADDRESS']) def validators(casper, deposit_scale_factor): validator_num = casper.get_nextValidatorIndex() validators = [] for validator_index in range(1, validator_num): v = {} v["addr"] = casper.get_validators__addr(validator_index) v["start_dynasty"] = casper.get_validators__start_dynasty( validator_index) v["end_dynasty"] = casper.get_validators__end_dynasty(validator_index) v["deposit"] = casper.get_validators__deposit( validator_index) / 10**18 * deposit_scale_factor