def tick(self): # Try to create a block # Conditions: # (i) you are an active validator, # (ii) you have not yet made a block with this parent if self.indices and self.chain.head_hash not in self.used_parents: t = self.get_timestamp() # Is it early enough to create the block? if t >= self.next_skip_timestamp and (not self.chain.head or t > self.chain.head.header.timestamp): print 'creating', t, self.next_skip_timestamp # Wrong validator; in this case, just wait for the next skip count if not check_skips(self.chain, self.indices, self.next_skip_count): self.next_skip_count += 1 self.next_skip_timestamp = get_timestamp(self.chain, self.next_skip_count) print 'Incrementing proposed timestamp for block %d to %d' % \ (self.chain.head.header.number + 1 if self.chain.head else 0, self.next_skip_timestamp) return self.used_parents[self.chain.head_hash] = True # Simulated 15% chance of validator failure to make a block if random.random() > 0.999: print 'Simulating validator failure, block %d not created' % (self.chain.head.header.number + 1 if self.chain.head else 0) return # Make the block, make sure it's valid pre_dunkle_count = call_casper(self.chain.state, 'getTotalDunklesIncluded', []) dunkle_txs = [] for i, u in enumerate(self.get_uncles()[:4]): start_nonce = self.chain.state.get_nonce(self.address) print 'start_nonce', start_nonce txdata = casper_ct.encode('includeDunkle', [rlp.encode(u)]) dunkle_txs.append(Transaction(start_nonce + i, 0, 650000, self.chain.config['CASPER_ADDR'], 0, txdata).sign(self.key)) for dtx in dunkle_txs[::-1]: self.chain.add_transaction(dtx, force=True) blk = make_block(self.chain, self.key, self.randao, self.indices, self.next_skip_count) global global_block_counter global_block_counter += 1 for dtx in dunkle_txs: assert dtx in blk.transactions, (dtx, blk.transactions) print 'made block with timestamp %d and %d dunkles' % (blk.timestamp, len(dunkle_txs)) assert blk.timestamp >= self.next_skip_timestamp assert self.chain.add_block(blk) self.update_head() post_dunkle_count = call_casper(self.chain.state, 'getTotalDunklesIncluded', []) assert post_dunkle_count - pre_dunkle_count == len(dunkle_txs) self.received_objects[blk.hash] = True print 'Validator %d making block %d (%s)' % (self.id, blk.header.number, blk.header.hash[:8].encode('hex')) self.network.broadcast(self, blk) # Sometimes we received blocks too early or out of order; # run an occasional loop that processes these if random.random() < 0.02: self.chain.process_time_queue() self.chain.process_parent_queue() self.update_head()
def find_my_indices(self): for i in range(len(validatorSizes)): epoch = self.chain.state.block_number // EPOCH_LENGTH valcount = call_casper(self.chain.state, 'getHistoricalValidatorCount', [epoch, i]) for j in range(valcount): valcode = call_casper(self.chain.state, 'getValidationCode', [i, j]) if valcode == self.validation_code: self.indices = i, j self.next_skip_count = 0 self.next_skip_timestamp = get_timestamp(self.chain, self.next_skip_count) print 'In current validator set at (%d, %d)' % (i, j) return self.indices = None self.next_skip_count, self.next_skip_timestamp = 0, 0 print 'Not in current validator set'
def get_uncles(self): anc = self.chain.get_block(self.chain.get_blockhash_by_number(self.chain.state.block_number - CHECK_FOR_UNCLES_BACK)) if anc: descendants = self.chain.get_descendants(anc) else: descendants = self.chain.get_descendants(self.chain.db.get('GENESIS_HASH')) potential_uncles = [x for x in descendants if x not in self.chain and isinstance(x, Block)] uncles = [x.header for x in potential_uncles if not call_casper(self.chain.state, 'isDunkleIncluded', [x.header.hash])] return uncles
def generate_genesis(path=None, num_participants=1): privkeys = [ utils.sha3(utils.to_string(i)) for i in range(num_participants) ] addrs = [utils.privtoaddr(k) for k in privkeys] deposit_sizes = [i * 500 + 500 for i in range(num_participants)] randaos = [RandaoManager(utils.sha3(k)) for k in privkeys] validators = [(generate_validation_code(a), ds * 10**18, r.get(9999), a) for a, ds, r in zip(addrs, deposit_sizes, randaos)] s = make_casper_genesis(validators=validators, alloc={a: { 'balance': 10**18 } for a in addrs}, timestamp=int(time.time()), epoch_length=100) genesis_hash = apply_const_message( s, sender=casper_config['METROPOLIS_ENTRY_POINT'], to=casper_config['METROPOLIS_BLOCKHASH_STORE'], data=utils.encode_int32(0)) genesis_number = call_casper(s, 'getBlockNumber') print('genesis block hash: %s' % utils.encode_hex(genesis_hash)) print('genesis block number: %d' % genesis_number) print('%d validators: %r' % (num_participants, [utils.encode_hex(a) for a in addrs])) snapshot = s.to_snapshot() header = s.prev_headers[0] genesis = { "nonce": "0x" + utils.encode_hex(header.nonce), "difficulty": utils.int_to_hex(header.difficulty), "mixhash": "0x" + utils.encode_hex(header.mixhash), "coinbase": "0x" + utils.encode_hex(header.coinbase), "timestamp": utils.int_to_hex(header.timestamp), "parentHash": "0x" + utils.encode_hex(header.prevhash), "extraData": "0x" + utils.encode_hex(header.extra_data), "gasLimit": utils.int_to_hex(header.gas_limit), "alloc": snapshot["alloc"] } if path: with open(path, 'w') as f: json.dump(genesis, f, sort_keys=False, indent=4, separators=(',', ': ')) print('casper genesis generated') else: return genesis
def get_uncles(self): anc = self.chain.get_block( self.chain.get_blockhash_by_number(self.chain.state.block_number - CHECK_FOR_UNCLES_BACK)) if anc: descendants = self.chain.get_descendants(anc) else: descendants = self.chain.get_descendants( self.chain.db.get('GENESIS_HASH')) potential_uncles = [ x for x in descendants if x not in self.chain and isinstance(x, Block) ] uncles = [ x.header for x in potential_uncles if not call_casper( self.chain.state, 'isDunkleIncluded', [x.header.hash]) ] return uncles
def make_block(chain, key, randao, vchash, skips): h, _ = make_head_candidate(chain, TransactionQueue(), timestamp=get_timestamp(chain, skips)) return sign_block(h, key, randao.get_parent(call_casper(chain.state, 'getRandao', [vchash])), vchash, skips)
vcodes = [generate_validation_code(a) for a in addrs] vchashes = [utils.sha3(c) for c in vcodes] assert len(privkeys) == len(addrs) == len(randaos) == len(deposit_sizes) == len(vcodes) == len(vchashes) == NUM_PARTICIPANTS # Creating casper contract translator ct = get_casper_ct() assert ct print('Constructing genesis') s = make_casper_genesis(validators=[(generate_validation_code(a), ds * 10**18, r.get(9999), a) for a, ds, r in zip(addrs, deposit_sizes, randaos)][:-1], alloc={a: {'balance': 10**18} for a in addrs}, timestamp=int(time.time() - 99999), epoch_length=100) print('Genesis constructed successfully') chains = [Chain(s.to_snapshot(), env=s.env) for i in range(NUM_PARTICIPANTS)] withdrawal_time_1 = call_casper(chains[0].state, 'getLockDuration', [vchashes[0]]) # List of validator IDs that created each block vids = [] # Create and sign a block def make_block(chain, key, randao, vchash, skips): h, _ = make_head_candidate(chain, TransactionQueue(), timestamp=get_timestamp(chain, skips)) return sign_block(h, key, randao.get_parent(call_casper(chain.state, 'getRandao', [vchash])), vchash, skips) next_validator = call_casper(s, 'getValidator', [0]) print('Next validator:', next_validator.encode('hex')) next_validator_id = vchashes.index(next_validator) print('Next validator index:', next_validator_id) skip_count, timestamp = get_skips_and_block_making_time(chains[0].state, next_validator)
s.prev_headers[0].timestamp = 2 s.timestamp = 2 s.prev_headers[0].difficulty = 1 s.block_difficulty = 1 s.set_code(casper_config['CASPER_ADDR'], get_casper_code()) s.set_code(casper_config['RLP_DECODER_ADDR'], get_rlp_decoder_code()) s.set_code(casper_config['HASH_WITHOUT_BLOOM_ADDR'], get_hash_without_ed_code()) ct = get_casper_ct() # Add all validators for k, r, ds in zip(keys, randaos, deposit_sizes): a = privtoaddr(k) # Leave 1 eth to pay txfees s.set_balance(a, (ds + 1) * 10**18) t = Transaction(0, 0, 10**8, casper_config['CASPER_ADDR'], ds * 10**18, ct.encode('deposit', [generate_validation_code(a), r.get(9999)])).sign(k) success, gas, logs = apply_transaction(s, t) s.commit() g = s.to_snapshot() print 'Genesis state created' validators = [Validator(g, k, n, Env(config=casper_config), time_offset=4) for k in keys] n.agents = validators n.generate_peers() for i in range(100000): # print 'ticking' n.tick() if i % 100 == 0: print 'Validator heads:', [v.chain.head.header.number if v.chain.head else None for v in validators] print 'Total blocks created:', casper.global_block_counter print 'Dunkle count:', call_casper(validators[0].chain.state, 'getTotalDunklesIncluded', [])
def call_casper(self, fun, args=[]): return call_casper(self.chain.state, fun, args)
def tick(self): # Try to create a block # Conditions: # (i) you are an active validator, # (ii) you have not yet made a block with this parent if self.indices and self.chain.head_hash not in self.used_parents: t = self.get_timestamp() # Is it early enough to create the block? if t >= self.next_skip_timestamp and ( not self.chain.head or t > self.chain.head.header.timestamp): # Wrong validator; in this case, just wait for the next skip count if not check_skips(self.chain, self.indices, self.next_skip_count): self.next_skip_count += 1 self.next_skip_timestamp = get_timestamp( self.chain, self.next_skip_count) # print 'Incrementing proposed timestamp for block %d to %d' % \ # (self.chain.head.header.number + 1 if self.chain.head else 0, self.next_skip_timestamp) return self.used_parents[self.chain.head_hash] = True # Simulated 15% chance of validator failure to make a block if random.random() > 0.999: print 'Simulating validator failure, block %d not created' % ( self.chain.head.header.number + 1 if self.chain.head else 0) return # Make the block, make sure it's valid pre_dunkle_count = call_casper(self.chain.state, 'getTotalDunklesIncluded', []) dunkle_txs = [] for i, u in enumerate(self.get_uncles()[:4]): start_nonce = self.chain.state.get_nonce(self.address) txdata = casper_ct.encode('includeDunkle', [rlp.encode(u)]) dunkle_txs.append( Transaction(start_nonce + i, 0, 650000, self.chain.config['CASPER_ADDR'], 0, txdata).sign(self.key)) for dtx in dunkle_txs[::-1]: self.chain.add_transaction(dtx, force=True) blk = make_block(self.chain, self.key, self.randao, self.indices, self.next_skip_count) global global_block_counter global_block_counter += 1 for dtx in dunkle_txs: assert dtx in blk.transactions, (dtx, blk.transactions) print 'made block with timestamp %d and %d dunkles' % ( blk.timestamp, len(dunkle_txs)) assert blk.timestamp >= self.next_skip_timestamp assert self.chain.add_block(blk) self.update_head() post_dunkle_count = call_casper(self.chain.state, 'getTotalDunklesIncluded', []) assert post_dunkle_count - pre_dunkle_count == len(dunkle_txs) self.received_objects[blk.hash] = True print 'Validator %d making block %d (%s)' % ( self.id, blk.header.number, blk.header.hash[:8].encode('hex')) self.network.broadcast(self, blk) # Sometimes we received blocks too early or out of order; # run an occasional loop that processes these if random.random() < 0.02: self.chain.process_time_queue() self.chain.process_parent_queue() self.update_head()
n.agents = validators n.generate_peers() lowest_shared_height = -1 made_101_check = 0 for i in range(100000): # print 'ticking' n.tick() if i % 100 == 0: print '%d ticks passed' % i print 'Validator heads:', [ v.chain.head.header.number if v.chain.head else None for v in validators ] print 'Total blocks created:', casper.global_block_counter print 'Dunkle count:', call_casper(validators[0].chain.state, 'getTotalDunklesIncluded', []) lowest_shared_height = min([ v.chain.head.header.number if v.chain.head else -1 for v in validators ]) if lowest_shared_height >= 101 and not made_101_check: made_101_check = True print 'Checking that withdrawn validators are inactive' assert len([v for v in validators if v.active]) == len(validators) - 5, len( [v for v in validators if v.active]) print 'Check successful' break if i == 1: print 'Checking that all validators are active' assert len([v for v in validators if v.active]) == len(validators)
print 'Genesis state created' validators = [Validator(g, k, n, Env(config=casper_config), time_offset=4) for k in keys] n.agents = validators n.generate_peers() lowest_shared_height = -1 made_101_check = 0 for i in range(100000): # print 'ticking' n.tick() if i % 100 == 0: print '%d ticks passed' % i print 'Validator heads:', [v.chain.head.header.number if v.chain.head else None for v in validators] print 'Total blocks created:', casper.global_block_counter print 'Dunkle count:', call_casper(validators[0].chain.state, 'getTotalDunklesIncluded', []) lowest_shared_height = min([v.chain.head.header.number if v.chain.head else -1 for v in validators]) if lowest_shared_height >= 101 and not made_101_check: made_101_check = True print 'Checking that withdrawn validators are inactive' assert len([v for v in validators if v.active]) == len(validators) - 5, len([v for v in validators if v.active]) print 'Check successful' break if i == 1: print 'Checking that all validators are active' assert len([v for v in validators if v.active]) == len(validators) print 'Check successful' if i == 2000: print 'Withdrawing a few validators' for v in validators[:5]: v.withdraw()