def mine_next_block(parent, coinbase=None, transactions=[]): if coinbase: c = Chain(env=parent.env, genesis=parent, coinbase=coinbase) else: c = Chain(env=parent.env, genesis=parent) for tx in transactions: c.add_transaction(tx) block = mine_on_chain(c) return block
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 test_add_longer_side_chain(db, alt_db): """" Local: L0, L1, L2 Remote: R0, R1, R2, R3 """ k, v, k2, v2 = accounts() # Remote: mine one block blk = mkquickgenesis({v: {"balance": utils.denoms.ether * 1}}, db=db) store_block(blk) remote_blocks = [blk] for i in range(3): tx = get_transaction(nonce=i) blk = mine_next_block(remote_blocks[-1], transactions=[tx]) store_block(blk) remote_blocks.append(blk) # Local: mine two blocks L0 = mkquickgenesis({v: {"balance": utils.denoms.ether * 1}}, db=alt_db) chain = Chain(env=env(L0.db), genesis=L0) tx0 = get_transaction(nonce=0) L1 = mine_next_block(L0, transactions=[tx0]) chain.add_block(L1) tx1 = get_transaction(nonce=1) L2 = mine_next_block(L1, transactions=[tx1]) chain.add_block(L2) # receive serialized remote blocks, newest first rlp_blocks = [rlp.encode(x) for x in remote_blocks] for rlp_block in rlp_blocks: block = blocks.Block.deserialize(rlp.decode(rlp_block), env=chain.env) chain.add_block(block) assert chain.head == remote_blocks[-1]
def test_reward_uncles(db): """ B0 B1 B2 B0 Uncle We raise the block's coinbase account by Rb, the block reward, and also add uncle and nephew rewards """ k, v, k2, v2 = accounts() blk0 = mkquickgenesis(db=db) local_coinbase = decode_hex('1' * 40) uncle_coinbase = decode_hex('2' * 40) chain = Chain(env=env(blk0.db), genesis=blk0) uncle = mine_on_chain(chain, blk0, coinbase=uncle_coinbase) assert uncle.get_balance(uncle_coinbase) == 1 * chain.env.config['BLOCK_REWARD'] blk1 = mine_on_chain(chain, blk0, coinbase=local_coinbase) assert blk1.hash in chain assert uncle.hash in chain assert uncle.hash != blk1.hash assert chain.head == blk1 assert chain.head.get_balance(local_coinbase) == 1 * chain.env.config['BLOCK_REWARD'] assert chain.head.get_balance(uncle_coinbase) == 0 # next block should reward uncles blk2 = mine_on_chain(chain, coinbase=local_coinbase) assert blk2.get_parent().prevhash == uncle.prevhash assert len(blk2.uncles) == 1 assert blk2 == chain.head assert chain.head.get_balance(local_coinbase) == \ 2 * chain.env.config['BLOCK_REWARD'] + chain.env.config['NEPHEW_REWARD'] assert chain.head.get_balance(uncle_coinbase) == chain.env.config['BLOCK_REWARD'] * 7 // 8
def get_chain(data_dir=default_data_dir): """ returns an ethereum.chain.Chain instance """ dbfile = os.path.join(data_dir, 'leveldb') db = LevelDB(dbfile) return Chain(Env(db))
def test_add_side_chain(db, alt_db): """" Local: L0, L1, L2 add Remote: R0, R1 """ k, v, k2, v2 = accounts() # Remote: mine one block R0 = mkquickgenesis({v: {"balance": utils.denoms.ether * 1}}, db=db) store_block(R0) tx0 = get_transaction(nonce=0) R1 = mine_next_block(R0, transactions=[tx0]) store_block(R1) assert tx0.hash in [x.hash for x in R1.get_transactions()] # Local: mine two blocks L0 = mkquickgenesis({v: {"balance": utils.denoms.ether * 1}}, alt_db) chain = Chain(env=env(L0.db), genesis=L0) tx0 = get_transaction(nonce=0) L1 = mine_next_block(L0, transactions=[tx0]) chain.add_block(L1) tx1 = get_transaction(nonce=1) L2 = mine_next_block(L1, transactions=[tx1]) chain.add_block(L2) # receive serialized remote blocks, newest first rlp_blocks = [rlp.encode(R0), rlp.encode(R1)] for rlp_block in rlp_blocks: block = blocks.Block.deserialize(rlp.decode(rlp_block), env=chain.env) chain.add_block(block) assert L2.hash in chain
def __init__(self, app): self.config = app.config sce = self.config['eth'] if int(sce['pruning']) >= 0: self.db = RefcountDB(app.services.db) if "I am not pruning" in self.db.db: raise RuntimeError( "The database in '{}' was initialized as non-pruning. " "Can not enable pruning now.".format( self.config['data_dir'])) self.db.ttl = int(sce['pruning']) self.db.db.put("I am pruning", "1") else: self.db = app.services.db if "I am pruning" in self.db: raise RuntimeError( "The database in '{}' was initialized as pruning. " "Can not disable pruning now".format( self.config['data_dir'])) self.db.put("I am not pruning", "1") if 'network_id' in self.db: db_network_id = self.db.get('network_id') if db_network_id != str(sce['network_id']): raise RuntimeError( "The database in '{}' was initialized with network id {} and can not be used " "when connecting to network id {}. Please choose a different data directory." .format(self.config['data_dir'], db_network_id, sce['network_id'])) else: self.db.put('network_id', str(sce['network_id'])) self.db.commit() assert self.db is not None super(ChainService, self).__init__(app) log.info('initializing chain') coinbase = app.services.accounts.coinbase env = Env(self.db, sce['block']) self.chain = Chain(env, new_head_cb=self._on_new_head, coinbase=coinbase) log.info('chain at', number=self.chain.head.number) if 'genesis_hash' in sce: assert sce['genesis_hash'] == self.chain.genesis.hex_hash(), \ "Genesis hash mismatch.\n Expected: %s\n Got: %s" % ( sce['genesis_hash'], self.chain.genesis.hex_hash()) self.synchronizer = Synchronizer(self, force_sync=None) self.block_queue = Queue(maxsize=self.block_queue_size) self.transaction_queue = Queue(maxsize=self.transaction_queue_size) self.add_blocks_lock = False self.add_transaction_lock = gevent.lock.Semaphore() self.broadcast_filter = DuplicatesFilter() self.on_new_head_cbs = [] self.on_new_head_candidate_cbs = [] self.newblock_processing_times = deque(maxlen=1000)
def __init__(self, app): self.config = app.config sce = self.config['eth'] if int(sce['pruning']) >= 0: self.db = RefcountDB(app.services.db) if "I am not pruning" in self.db.db: raise Exception("This database was initialized as non-pruning." " Kinda hard to start pruning now.") self.db.ttl = int(sce['pruning']) self.db.db.put("I am pruning", "1") else: self.db = app.services.db if "I am pruning" in self.db: raise Exception("This database was initialized as pruning." " Kinda hard to stop pruning now.") self.db.put("I am not pruning", "1") if 'network_id' in self.db: db_network_id = self.db.get('network_id') if db_network_id != str(sce['network_id']): raise Exception( "This database was initialized with network_id {} " "and can not be used when connecting to network_id {}". format(db_network_id, sce['network_id'])) else: self.db.put('network_id', str(sce['network_id'])) self.db.commit() assert self.db is not None super(ChainService, self).__init__(app) log.info('initializing chain') coinbase = app.services.accounts.coinbase env = Env(self.db, sce['block']) self.chain = Chain(env, new_head_cb=self._on_new_head, coinbase=coinbase) log.info('chain at', number=self.chain.head.number) if 'genesis_hash' in sce: assert sce['genesis_hash'] == self.chain.genesis.hex_hash() self.synchronizer = Synchronizer(self, force_sync=None) self.block_queue = Queue(maxsize=self.block_queue_size) self.transaction_queue = Queue(maxsize=self.transaction_queue_size) self.add_blocks_lock = False self.add_transaction_lock = gevent.lock.Semaphore() self.broadcast_filter = DuplicatesFilter() self.on_new_head_cbs = [] self.on_new_head_candidate_cbs = [] self.newblock_processing_times = deque(maxlen=1000)
def __init__(self, app): self.config = app.config self.db = app.services.db assert self.db is not None super(ChainService, self).__init__(app) log.info('initializing chain') self.chain = Chain(self.db, new_head_cb=self._on_new_head) self.synchronizer = Synchronizer(self, force_sync=None) self.chain.coinbase = privtoaddr( self.config['eth']['privkey_hex'].decode('hex')) self.block_queue = Queue(maxsize=self.block_queue_size) self.transaction_queue = Queue(maxsize=self.transaction_queue_size) self.add_blocks_lock = False self.broadcast_filter = DuplicatesFilter()
def __init__(self, app): self.config = app.config self.db = app.services.db assert self.db is not None super(ChainService, self).__init__(app) log.info('initializing chain') coinbase = app.services.accounts.coinbase self.chain = Chain(self.db, new_head_cb=self._on_new_head, coinbase=coinbase) log.info('chain at', number=self.chain.head.number) self.synchronizer = Synchronizer(self, force_sync=None) self.block_queue = Queue(maxsize=self.block_queue_size) self.transaction_queue = Queue(maxsize=self.transaction_queue_size) self.add_blocks_lock = False self.add_transaction_lock = gevent.lock.Semaphore() self.broadcast_filter = DuplicatesFilter()
def __init__(self, app): self.config = app.config sce = self.config['eth'] if int(sce['pruning']) >= 0: self.db = RefcountDB(app.services.db) if "I am not pruning" in self.db.db: raise Exception("This database was initialized as non-pruning." " Kinda hard to start pruning now.") self.db.ttl = int(sce['pruning']) self.db.db.put("I am pruning", "1") else: self.db = app.services.db if "I am pruning" in self.db: raise Exception("This database was initialized as pruning." " Kinda hard to stop pruning now.") self.db.put("I am not pruning", "1") assert self.db is not None super(ChainService, self).__init__(app) log.info('initializing chain') coinbase = app.services.accounts.coinbase if sce['genesis']: log.info('loading genesis', path=sce['genesis']) _json = json.load(open(sce['genesis'])) else: log.info('loaded default genesis alloc') _json = None _genesis = genesis(self.db, json=_json) log.info('created genesis block', hash=encode_hex(_genesis.hash)) self.chain = Chain(self.db, genesis=_genesis, new_head_cb=self._on_new_head, coinbase=coinbase) log.info('chain at', number=self.chain.head.number) self.synchronizer = Synchronizer(self, force_sync=None) self.block_queue = Queue(maxsize=self.block_queue_size) self.transaction_queue = Queue(maxsize=self.transaction_queue_size) self.add_blocks_lock = False self.add_transaction_lock = gevent.lock.Semaphore() self.broadcast_filter = DuplicatesFilter() self.on_new_head_cbs = [] self.on_new_head_candidate_cbs = [] self.newblock_processing_times = deque(maxlen=1000)
def test_genesis_chain(db): k, v, k2, v2 = accounts() blk = mkquickgenesis({v: {"balance": utils.denoms.ether * 1}}, db=db) chain = Chain(env=env(blk.db), genesis=blk) assert chain.has_block(blk.hash) assert blk.hash in chain assert chain.get(blk.hash) == blk assert chain.head == blk assert chain.get_children(blk) == [] assert chain.get_uncles(blk) == [] assert chain.get_chain() == [blk] assert chain.get_chain(blk.hash) == [blk] assert chain.get_descendants(blk, count=10) == [] assert chain.index.has_block_by_number(0) assert not chain.index.has_block_by_number(1) assert chain.index.get_block_by_number(0) == blk.hash with pytest.raises(KeyError): chain.index.get_block_by_number(1)
def test_simple_chain(db): k, v, k2, v2 = accounts() blk = mkquickgenesis({v: {"balance": utils.denoms.ether * 1}}, db=db) store_block(blk) chain = Chain(env=env(blk.db), genesis=blk) tx = get_transaction() blk2 = mine_next_block(blk, transactions=[tx]) store_block(blk2) chain.add_block(blk2) assert blk.hash in chain assert blk2.hash in chain assert chain.has_block(blk2.hash) assert chain.get(blk2.hash) == blk2 assert chain.head == blk2 assert chain.get_children(blk) == [blk2] assert chain.get_uncles(blk2) == [] assert chain.get_chain() == [blk2, blk] assert chain.get_chain(count=0) == [] assert chain.get_chain(count=1) == [blk2] assert chain.get_chain(count=2) == [blk2, blk] assert chain.get_chain(count=100) == [blk2, blk] assert chain.get_chain(blk.hash) == [blk] assert chain.get_chain(blk.hash, 0) == [] assert chain.get_chain(blk2.hash) == [blk2, blk] assert chain.get_chain(blk2.hash, 1) == [blk2] assert chain.get_descendants(blk, count=10) == [blk2] assert chain.get_descendants(blk, count=1) == [blk2] assert chain.get_descendants(blk, count=0) == [] assert chain.index.has_block_by_number(1) assert not chain.index.has_block_by_number(2) assert chain.index.get_block_by_number(1) == blk2.hash with pytest.raises(KeyError): chain.index.get_block_by_number(2) assert chain.index.get_transaction(tx.hash) == (tx, blk2, 0)
def __init__(self, app): self.config = app.config sce = self.config['eth'] if int(sce['pruning']) >= 0: self.db = RefcountDB(app.services.db) if "I am not pruning" in self.db.db: raise Exception("This database was initialized as non-pruning." " Kinda hard to start pruning now.") self.db.ttl = int(sce['pruning']) self.db.db.put("I am pruning", "1") else: self.db = app.services.db if "I am pruning" in self.db: raise Exception("This database was initialized as pruning." " Kinda hard to stop pruning now.") self.db.put("I am not pruning", "1") if 'network_id' in self.db: db_network_id = self.db.get('network_id') if db_network_id != str(sce['network_id']): raise Exception( "This database was initialized with network_id {} " "and can not be used when connecting to network_id {}". format(db_network_id, sce['network_id'])) else: self.db.put('network_id', str(sce['network_id'])) self.db.commit() assert self.db is not None WiredService.__init__(self, app) log.info('initializing chain') coinbase = app.services.accounts.coinbase env = Env(self.db, sce['block']) self.chain = Chain(env, new_head_cb=self._on_new_head, coinbase=coinbase) log.info('chain at', number=self.chain.head.number) if 'genesis_hash' in sce: assert sce['genesis_hash'] == self.chain.genesis.hex_hash() self.transaction_queue = Queue(maxsize=self.transaction_queue_size) self.add_blocks_lock = False self.add_transaction_lock = gevent.lock.BoundedSemaphore() self.broadcast_filter = DuplicatesFilter() self.on_new_head_cbs = [] self.on_new_head_candidate_cbs = [] self.newblock_processing_times = deque(maxlen=1000) # Consensus self.consensus_contract = ConsensusContract( validators=self.config['hdc']['validators']) self.consensus_manager = ConsensusManager(self, self.consensus_contract, self.consensus_privkey) # lock blocks that where proposed, so they don't get mutated self.proposal_lock = ProposalLock() assert not self.proposal_lock.is_locked()
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') 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)
def test_prevhash(db): g = mkquickgenesis({}, db=db) chain = Chain(env(g.db), g) L1 = mine_on_chain(chain) L1.get_ancestor_list(2)