def __init__(self, genesis, key, network, env, time_offset=5): # Create a chain object self.chain = Chain(genesis, env=env) # Use the validator's time as the chain's time self.chain.time = lambda: self.get_timestamp() # My private key self.key = key # My address self.address = privtoaddr(key) # My randao self.randao = RandaoManager(sha3(self.key)) # Pointer to the test p2p network self.network = network # Record of objects already received and processed self.received_objects = {} # The minimum eligible timestamp given a particular number of skips self.next_skip_count = 0 self.next_skip_timestamp = 0 # This validator's indices in the state self.indices = None # Is this validator active? self.active = False # Code that verifies signatures from this validator self.validation_code = generate_validation_code(privtoaddr(key)) # Parents that this validator has already built a block on self.used_parents = {} # This validator's clock offset (for testing purposes) self.time_offset = random.randrange(time_offset) - (time_offset // 2) # Determine the epoch length self.epoch_length = self.call_casper('getEpochLength') # Give this validator a unique ID self.id = len(ids) ids.append(self.id) self.find_my_indices() self.cached_head = self.chain.head_hash
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 __init__(self, genesis, key, network, env, time_offset=5): # Create a chain object self.chain = Chain(genesis, env=env) # Create a transaction queue self.txqueue = TransactionQueue() # Use the validator's time as the chain's time self.chain.time = lambda: self.get_timestamp() # My private key self.key = key # My address self.address = privtoaddr(key) # My randao self.randao = RandaoManager(sha3(self.key)) # Pointer to the test p2p network self.network = network # Record of objects already received and processed self.received_objects = {} # The minimum eligible timestamp given a particular number of skips self.next_skip_count = 0 self.next_skip_timestamp = 0 # Is this validator active? self.active = False # Code that verifies signatures from this validator self.validation_code = generate_validation_code(privtoaddr(key)) # Validation code hash self.vchash = sha3(self.validation_code) # Parents that this validator has already built a block on self.used_parents = {} # This validator's clock offset (for testing purposes) self.time_offset = random.randrange(time_offset) - (time_offset // 2) # Determine the epoch length self.epoch_length = self.call_casper('getEpochLength') # My minimum gas price self.mingasprice = 20 * 10**9 # Give this validator a unique ID self.id = len(ids) ids.append(self.id) self.update_activity_status() self.cached_head = self.chain.head_hash
from ethereum.config import default_config, Env import copy import time import rlp # config_string = ':info,eth.vm.log:trace,eth.vm.op:trace,eth.vm.stack:trace,eth.vm.exit:trace,eth.pb.msg:trace,eth.pb.tx:debug' config_string = ':info,eth.vm.log:trace' configure_logging(config_string=config_string) NUM_PARTICIPANTS = 10 BLOCK_MAKING_PPB = 10 print('Initializing privkeys, addresses and randaos for validators') privkeys = [utils.sha3(str(i)) for i in range(NUM_PARTICIPANTS)] addrs = [utils.privtoaddr(k) for k in privkeys] randaos = [RandaoManager(utils.sha3(str(i))) for i in range(NUM_PARTICIPANTS)] deposit_sizes = [i * 500 + 500 for i in range(NUM_PARTICIPANTS)] 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')
get_hash_without_ed_code, make_casper_genesis from ethereum.utils import sha3, privtoaddr from ethereum.transactions import Transaction from ethereum.state_transition import apply_transaction from ethereum.slogging import LogRecorder, configure_logging, set_level # config_string = ':info,eth.vm.log:trace,eth.vm.op:trace,eth.vm.stack:trace,eth.vm.exit:trace,eth.pb.msg:trace,eth.pb.tx:debug' config_string = ':info,eth.vm.log:trace' configure_logging(config_string=config_string) n = networksim.NetworkSimulator(latency=150) n.time = 2 print 'Generating keys' keys = [sha3(str(i)) for i in range(20)] print 'Initializing randaos' randaos = [RandaoManager(sha3(k)) for k in keys] deposit_sizes = [128] * 15 + [256] * 5 print 'Creating genesis state' s = make_casper_genesis( validators=[(generate_validation_code(privtoaddr(k)), ds * 10**18, r.get(9999)) for k, ds, r in zip(keys, deposit_sizes, randaos)], alloc={privtoaddr(k): { 'balance': 10**18 } for k in keys}, timestamp=2, epoch_length=50) g = s.to_snapshot() print 'Genesis state created'
class Validator(): def __init__(self, genesis, key, network, env, time_offset=5): # Create a chain object self.chain = Chain(genesis, env=env) # Create a transaction queue self.txqueue = TransactionQueue() # Use the validator's time as the chain's time self.chain.time = lambda: self.get_timestamp() # My private key self.key = key # My address self.address = privtoaddr(key) # My randao self.randao = RandaoManager(sha3(self.key)) # Pointer to the test p2p network self.network = network # Record of objects already received and processed self.received_objects = {} # The minimum eligible timestamp given a particular number of skips self.next_skip_count = 0 self.next_skip_timestamp = 0 # Is this validator active? self.active = False # Code that verifies signatures from this validator self.validation_code = generate_validation_code(privtoaddr(key)) # Validation code hash self.vchash = sha3(self.validation_code) # Parents that this validator has already built a block on self.used_parents = {} # This validator's clock offset (for testing purposes) self.time_offset = random.randrange(time_offset) - (time_offset // 2) # Determine the epoch length self.epoch_length = self.call_casper('getEpochLength') # My minimum gas price self.mingasprice = 20 * 10**9 # Give this validator a unique ID self.id = len(ids) ids.append(self.id) self.update_activity_status() self.cached_head = self.chain.head_hash def call_casper(self, fun, args=[]): return call_casper(self.chain.state, fun, args) def update_activity_status(self): start_epoch = self.call_casper('getStartEpoch', [self.vchash]) now_epoch = self.call_casper('getEpoch') end_epoch = self.call_casper('getEndEpoch', [self.vchash]) if start_epoch <= now_epoch < end_epoch: self.active = True self.next_skip_count = 0 self.next_skip_timestamp = get_timestamp(self.chain, self.next_skip_count) print 'In current validator set' else: self.active = False def get_timestamp(self): return int(self.network.time * 0.01) + self.time_offset def on_receive(self, obj): if isinstance(obj, list): for _obj in obj: self.on_receive(_obj) return if obj.hash in self.received_objects: return if isinstance(obj, Block): print 'Receiving block', obj assert obj.hash not in self.chain block_success = self.chain.add_block(obj) self.network.broadcast(self, obj) self.network.broadcast(self, ChildRequest(obj.header.hash)) self.update_head() elif isinstance(obj, Transaction): print 'Receiving transaction', obj if obj.gasprice >= self.mingasprice: self.txqueue.add_transaction(obj) print 'Added transaction, txqueue size %d' % len( self.txqueue.txs) self.network.broadcast(self, obj) else: print 'Gasprice too low' self.received_objects[obj.hash] = True for x in self.chain.get_chain(): assert x.hash in self.received_objects 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.active 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.vchash, 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 s1 = self.chain.state.trie.root_hash pre_dunkle_count = self.call_casper('getTotalDunklesIncluded') dunkle_txs = get_dunkle_candidates(self.chain, self.chain.state) blk = make_head_candidate(self.chain, self.txqueue) randao = self.randao.get_parent( self.call_casper('getRandao', [self.vchash])) blk = sign_block(blk, self.key, randao, self.vchash, self.next_skip_count) # Make sure it's valid 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)) s2 = self.chain.state.trie.root_hash assert s1 == s2 assert blk.timestamp >= self.next_skip_timestamp assert self.chain.add_block(blk) self.update_head() post_dunkle_count = self.call_casper('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 update_head(self): if self.cached_head == self.chain.head_hash: return self.cached_head = self.chain.head_hash if self.chain.state.block_number % self.epoch_length == 0: self.update_activity_status() if self.active: self.next_skip_count = 0 self.next_skip_timestamp = get_timestamp(self.chain, self.next_skip_count) print 'Head changed: %s, will attempt creating a block at %d' % ( self.chain.head_hash.encode('hex'), self.next_skip_timestamp) def withdraw(self, gasprice=20 * 10**9): sigdata = make_withdrawal_signature(self.key) txdata = casper_ct.encode('startWithdrawal', [self.vchash, sigdata]) tx = Transaction(self.chain.state.get_nonce(self.address), gasprice, 650000, self.chain.config['CASPER_ADDR'], 0, txdata).sign(self.key) self.txqueue.add_transaction(tx, force=True) self.network.broadcast(self, tx) print 'Withdrawing!' def deposit(self, gasprice=20 * 10**9): assert value * 10**18 >= self.chain.state.get_balance( self.address) + gasprice * 1000000 tx = Transaction( self.chain.state.get_nonce(self.address) * 10**18, gasprice, 1000000, casper_config['CASPER_ADDR'], value * 10**18, ct.encode('deposit', [self.validation_code, self.randao.get(9999)]))
class Validator(): def __init__(self, genesis, key, network, env, time_offset=5): # Create a chain object self.chain = Chain(genesis, env=env) # Create a transaction queue self.txqueue = TransactionQueue() # Use the validator's time as the chain's time self.chain.time = lambda: self.get_timestamp() # My private key self.key = key # My address self.address = privtoaddr(key) # My randao self.randao = RandaoManager(sha3(self.key)) # Pointer to the test p2p network self.network = network # Record of objects already received and processed self.received_objects = {} # The minimum eligible timestamp given a particular number of skips self.next_skip_count = 0 self.next_skip_timestamp = 0 # Is this validator active? self.active = False # Code that verifies signatures from this validator self.validation_code = generate_validation_code(privtoaddr(key)) # Validation code hash self.vchash = sha3(self.validation_code) # Parents that this validator has already built a block on self.used_parents = {} # This validator's clock offset (for testing purposes) self.time_offset = random.randrange(time_offset) - (time_offset // 2) # Determine the epoch length self.epoch_length = self.call_casper('getEpochLength') # My minimum gas price self.mingasprice = 20 * 10**9 # Give this validator a unique ID self.id = len(ids) ids.append(self.id) self.update_activity_status() self.cached_head = self.chain.head_hash def call_casper(self, fun, args=[]): return call_casper(self.chain.state, fun, args) def update_activity_status(self): start_epoch = self.call_casper('getStartEpoch', [self.vchash]) now_epoch = self.call_casper('getEpoch') end_epoch = self.call_casper('getEndEpoch', [self.vchash]) if start_epoch <= now_epoch < end_epoch: self.active = True self.next_skip_count = 0 self.next_skip_timestamp = get_timestamp(self.chain, self.next_skip_count) print 'In current validator set' else: self.active = False def get_timestamp(self): return int(self.network.time * 0.01) + self.time_offset def on_receive(self, obj): if isinstance(obj, list): for _obj in obj: self.on_receive(_obj) return if obj.hash in self.received_objects: return if isinstance(obj, Block): print 'Receiving block', obj assert obj.hash not in self.chain block_success = self.chain.add_block(obj) self.network.broadcast(self, obj) self.network.broadcast(self, ChildRequest(obj.header.hash)) self.update_head() elif isinstance(obj, Transaction): print 'Receiving transaction', obj if obj.gasprice >= self.mingasprice: self.txqueue.add_transaction(obj) print 'Added transaction, txqueue size %d' % len(self.txqueue.txs) self.network.broadcast(self, obj) else: print 'Gasprice too low' self.received_objects[obj.hash] = True for x in self.chain.get_chain(): assert x.hash in self.received_objects 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.active 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.vchash, 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 s1 = self.chain.state.trie.root_hash pre_dunkle_count = self.call_casper('getTotalDunklesIncluded') dunkle_txs = get_dunkle_candidates(self.chain, self.chain.state) blk = make_head_candidate(self.chain, self.txqueue) randao = self.randao.get_parent(self.call_casper('getRandao', [self.vchash])) blk = sign_block(blk, self.key, randao, self.vchash, self.next_skip_count) # Make sure it's valid 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)) s2 = self.chain.state.trie.root_hash assert s1 == s2 assert blk.timestamp >= self.next_skip_timestamp assert self.chain.add_block(blk) self.update_head() post_dunkle_count = self.call_casper('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 update_head(self): if self.cached_head == self.chain.head_hash: return self.cached_head = self.chain.head_hash if self.chain.state.block_number % self.epoch_length == 0: self.update_activity_status() if self.active: self.next_skip_count = 0 self.next_skip_timestamp = get_timestamp(self.chain, self.next_skip_count) print 'Head changed: %s, will attempt creating a block at %d' % (self.chain.head_hash.encode('hex'), self.next_skip_timestamp) def withdraw(self, gasprice=20 * 10**9): sigdata = make_withdrawal_signature(self.key) txdata = casper_ct.encode('startWithdrawal', [self.vchash, sigdata]) tx = Transaction(self.chain.state.get_nonce(self.address), gasprice, 650000, self.chain.config['CASPER_ADDR'], 0, txdata).sign(self.key) self.txqueue.add_transaction(tx, force=True) self.network.broadcast(self, tx) print 'Withdrawing!' def deposit(self, gasprice=20 * 10**9): assert value * 10**18 >= self.chain.state.get_balance(self.address) + gasprice * 1000000 tx = Transaction(self.chain.state.get_nonce(self.address) * 10**18, gasprice, 1000000, casper_config['CASPER_ADDR'], value * 10**18, ct.encode('deposit', [self.validation_code, self.randao.get(9999)]))