def test_handle_ignored_collation(): """Test handle_ignored_collation(self, collation, period_start_prevblock, handle_ignored_collation) """ shard_id = 1 # Collator: create and apply collation sequentially t1 = tester.Chain(env='sharding') t1.chain.init_shard(shard_id) t1.mine(5) # collation1 collation1 = t1.generate_collation(shard_id=1, coinbase=tester.a1, key=tester.k1, txqueue=None) period_start_prevblock = t1.chain.get_block( collation1.header.period_start_prevhash) t1.chain.shards[shard_id].add_collation(collation1, period_start_prevblock, t1.chain.handle_ignored_collation) assert t1.chain.shards[shard_id].get_score(collation1) == 1 # collation2 collation2 = t1.generate_collation( shard_id=1, coinbase=tester.a2, key=tester.k2, txqueue=None, parent_collation_hash=collation1.header.hash) period_start_prevblock = t1.chain.get_block( collation2.header.period_start_prevhash) t1.chain.shards[shard_id].add_collation(collation2, period_start_prevblock, t1.chain.handle_ignored_collation) assert t1.chain.shards[shard_id].get_score(collation2) == 2 # collation3 collation3 = t1.generate_collation( shard_id=1, coinbase=tester.a2, key=tester.k2, txqueue=None, parent_collation_hash=collation2.header.hash) period_start_prevblock = t1.chain.get_block( collation3.header.period_start_prevhash) t1.chain.shards[shard_id].add_collation(collation3, period_start_prevblock, t1.chain.handle_ignored_collation) assert t1.chain.shards[shard_id].get_score(collation3) == 3 # Validator: apply collation2, collation3 and collation1 t2 = tester.Chain(env='sharding') t2.chain.init_shard(shard_id) t2.mine(5) # append collation2 t2.chain.shards[shard_id].add_collation(collation2, period_start_prevblock, t2.chain.handle_ignored_collation) # append collation3 t2.chain.shards[shard_id].add_collation(collation3, period_start_prevblock, t2.chain.handle_ignored_collation) # append collation1 now t2.chain.shards[shard_id].add_collation(collation1, period_start_prevblock, t2.chain.handle_ignored_collation) assert t2.chain.shards[shard_id].get_score(collation1) == 1 assert t2.chain.shards[shard_id].get_score(collation2) == 2 assert t2.chain.shards[shard_id].get_score(collation3) == 3
def test_add_collation_error(): """Test add_collation(self, collation, period_start_prevblock, handle_ignored_collation) """ shard_id = 1 t = tester.Chain(env='sharding') t.chain.init_shard(shard_id) t.mine(5) # parent = empty collation1 = t.generate_collation(shard_id=1, coinbase=tester.a1, key=tester.k1, txqueue=None) period_start_prevblock = t.chain.get_block( collation1.header.period_start_prevhash) t.chain.shards[shard_id].add_collation(collation1, period_start_prevblock, t.chain.handle_ignored_collation) # parent = collation1 collation2 = t.generate_collation( shard_id=1, coinbase=tester.a2, key=tester.k1, txqueue=None, parent_collation_hash=collation1.header.hash) period_start_prevblock = t.chain.get_block( collation2.header.period_start_prevhash) collation2.header.post_state_root = trie.BLANK_ROOT # apply_collation error assert not t.chain.shards[shard_id].add_collation( collation2, period_start_prevblock, t.chain.handle_ignored_collation)
def test_get_parent(): """Test get_parent(self, collation) """ t = tester.Chain(env='sharding') shard_id = 1 t.chain.init_shard(shard_id) t.mine(5) collation = t.generate_collation(shard_id=1, coinbase=tester.a1, key=tester.k1, txqueue=None) period_start_prevblock = t.chain.get_block( collation.header.period_start_prevhash) t.chain.shards[shard_id].add_collation(collation, period_start_prevblock, t.chain.handle_ignored_collation) assert t.chain.shards[shard_id].is_first_collation(collation) # append to previous collation collation = t.generate_collation( shard_id=1, coinbase=tester.a1, key=tester.k1, txqueue=None, parent_collation_hash=collation.header.hash) period_start_prevblock = t.chain.get_block( collation.header.period_start_prevhash) t.chain.shards[shard_id].add_collation(collation, period_start_prevblock, t.chain.handle_ignored_collation) assert not t.chain.shards[shard_id].is_first_collation(collation) assert t.chain.shards[shard_id].get_parent( collation).header.hash == collation.header.parent_collation_hash
def chain(): """A initialized chain from ethereum.tester.Chain """ c = t.Chain() c.head_state.set_balance(address=t.a0, value=DEPOSIT_SIZE * 10) c.head_state.set_balance(address=t.a1, value=DEPOSIT_SIZE * 10) c.mine(number_of_blocks=num_blocks - 1, coinbase=t.a0) c.deploy_initializing_contracts(t.k0) c.mine(number_of_blocks=1, coinbase=t.a0) return c
def test_add_shard(): """Test add_shard(self, shard) """ shard_id = 1 t = tester.Chain(env='sharding') shard = ShardChain(shard_id=shard_id) assert t.chain.add_shard(shard) assert len(t.chain.shard_id_list) == 1 assert not t.chain.add_shard(shard)
def test_init_shard(): """Test init_shard(self, shard_id) """ t = tester.Chain(env='sharding') assert t.chain.init_shard(1) assert len(t.chain.shard_id_list) == 1 assert t.chain.init_shard(2) assert len(t.chain.shard_id_list) == 2 assert not t.chain.init_shard(2) assert len(t.chain.shard_id_list) == 2
def test_add_collation(): """Test add_collation(self, collation, period_start_prevblock, handle_ignored_collation) """ shard_id = 1 t = tester.Chain(env='sharding') t.chain.init_shard(shard_id) t.mine(5) # parent = empty collation1 = t.generate_collation(shard_id=1, coinbase=tester.a1, key=tester.k1, txqueue=None) period_start_prevblock = t.chain.get_block( collation1.header.period_start_prevhash) t.chain.shards[shard_id].add_collation(collation1, period_start_prevblock, t.chain.handle_ignored_collation) assert t.chain.shards[shard_id].get_score(collation1) == 1 # parent = empty collation2 = t.generate_collation(shard_id=1, coinbase=tester.a2, key=tester.k1, txqueue=None) period_start_prevblock = t.chain.get_block( collation2.header.period_start_prevhash) t.chain.shards[shard_id].add_collation(collation2, period_start_prevblock, t.chain.handle_ignored_collation) assert t.chain.shards[shard_id].get_score(collation2) == 1 # parent = collation1 collation3 = t.generate_collation( shard_id=1, coinbase=tester.a2, key=tester.k1, txqueue=None, parent_collation_hash=collation1.header.hash) period_start_prevblock = t.chain.get_block( collation3.header.period_start_prevhash) t.chain.shards[shard_id].add_collation(collation3, period_start_prevblock, t.chain.handle_ignored_collation) assert t.chain.shards[shard_id].get_score(collation3) == 2 # parent = collation3 collation4 = t.generate_collation( shard_id=1, coinbase=tester.a2, key=tester.k1, txqueue=None, parent_collation_hash=collation3.header.hash) period_start_prevblock = t.chain.get_block( collation4.header.period_start_prevhash) t.chain.shards[shard_id].add_collation(collation4, period_start_prevblock, t.chain.handle_ignored_collation) assert t.chain.shards[shard_id].get_score(collation4) == 3
def chain(shard_id, k0_deposit=True): c = tester.Chain(env='sharding', deploy_sharding_contracts=True) c.mine(5) # make validation code privkey = tester.k0 valcode_addr = c.sharding_valcode_addr(privkey) if k0_deposit: # deposit c.sharding_deposit(privkey, valcode_addr) c.mine(1) c.add_test_shard(shard_id) return c
def test_get_period_start_prevhash(): """Test get_period_start_prevhash(self, expected_period_number) """ shard_id = 1 t = tester.Chain(env='sharding') t.chain.init_shard(shard_id) t.mine(5) expected_period_number = 1 assert t.chain.get_period_start_prevhash(expected_period_number) expected_period_number = 2 assert t.chain.get_period_start_prevhash(expected_period_number) is None
def test_get_expected_period_number(): """Test get_expected_period_number(self) """ shard_id = 1 t = tester.Chain(env='sharding') t.chain.init_shard(shard_id) t.mine(5) # block number = 5 assert t.chain.get_expected_period_number() == 1 t.mine(4) # block number = 9 assert t.chain.get_expected_period_number() == 2 t.mine(1) # block number = 10 assert t.chain.get_expected_period_number() == 2
def test_cb_function(): shard_id = 1 t = tester.Chain(env='sharding') shard = ShardChain(shard_id=shard_id, new_head_cb=cb_function, env=t.chain.env) assert t.chain.add_shard(shard) t.mine(5) collation1 = t.generate_collation(shard_id=shard_id, coinbase=tester.a1, key=tester.k1, txqueue=None) period_start_prevblock = t.chain.get_block( collation1.header.period_start_prevhash) assert t.chain.shards[shard_id].add_collation( collation1, period_start_prevblock, t.chain.handle_ignored_collation) global cb_function_is_called assert cb_function_is_called
def chain(shard_id): c = t.Chain(env='sharding', deploy_sharding_contracts=True) c.mine(5) c.add_test_shard(shard_id) return c
def chain(shard_id): t = tester.Chain(env='sharding') t.mine(5) t.add_test_shard(shard_id) return t
def c(): chain = t.Chain(env='sharding', deploy_sharding_contracts=True) chain.mine(5) return chain
def test_validator_manager(): # Must pay 100 ETH to become a validator c = t.Chain(env='sharding', deploy_sharding_contracts=True) k0_valcode_addr = c.tx(t.k0, '', 0, mk_validation_code(t.a0)) k1_valcode_addr = c.tx(t.k1, '', 0, mk_validation_code(t.a1)) num_blocks = 11 c.mine(num_blocks - 1, coinbase=t.a0) c.head_state.gas_limit = 10 ** 12 # deploy valmgr and its prerequisite contracts and transactions x = t.ABIContract(c, get_valmgr_ct(), get_valmgr_addr()) # test deposit: fails when msg.value != DEPOSIT_SIZE with pytest.raises(t.TransactionFailed): # gas == GASLIMIT x.deposit(k0_valcode_addr, k0_valcode_addr) # test withdraw: fails when no validator record assert not x.withdraw(0, sign(WITHDRAW_HASH, t.k0)) # test deposit: works fine return_addr = utils.privtoaddr(utils.sha3("return_addr")) assert 0 == x.deposit(k0_valcode_addr, return_addr, value=DEPOSIT_SIZE, sender=t.k0) assert 1 == x.deposit(k1_valcode_addr, return_addr, value=DEPOSIT_SIZE, sender=t.k1) assert x.withdraw(0, sign(WITHDRAW_HASH, t.k0)) # test withdraw: see if the money is returned assert c.head_state.get_balance(return_addr) == DEPOSIT_SIZE # test deposit: make use of empty slots assert 0 == x.deposit(k0_valcode_addr, return_addr, value=DEPOSIT_SIZE, sender=t.k0) assert x.withdraw(1, sign(WITHDRAW_HASH, t.k1)) # test deposit: working fine in the edge condition assert 1 == x.deposit(k1_valcode_addr, return_addr, value=DEPOSIT_SIZE, sender=t.k1) # test deposit: fails when valcode_addr is deposited before with pytest.raises(t.TransactionFailed): x.deposit(k1_valcode_addr, return_addr, value=DEPOSIT_SIZE, sender=t.k1) # test withdraw: fails when the signature is not corret assert not x.withdraw(1, sign(WITHDRAW_HASH, t.k0)) # test sample: correctly sample the only one validator assert x.withdraw(0, sign(WITHDRAW_HASH, t.k0)) assert x.sample(0) == hex(utils.big_endian_to_int(k1_valcode_addr)) # test sample: sample returns zero_addr (i.e. 0x00) when there is no depositing validator assert x.withdraw(1, sign(WITHDRAW_HASH, t.k1)) assert x.sample(0) == "0x0000000000000000000000000000000000000000" def get_colhdr(shard_id, parent_collation_hash, collation_coinbase=t.a0): period_length = 5 expected_period_number = num_blocks // period_length b = c.chain.get_block_by_number(expected_period_number * period_length - 1) period_start_prevhash = b.header.hash tx_list_root = b"tx_list " * 4 post_state_root = b"post_sta" * 4 receipt_root = b"receipt " * 4 sighash = utils.sha3( rlp.encode([ shard_id, expected_period_number, period_start_prevhash, parent_collation_hash, tx_list_root, collation_coinbase, post_state_root, receipt_root ]) ) sig = sign(sighash, t.k0) return rlp.encode([ shard_id, expected_period_number, period_start_prevhash, parent_collation_hash, tx_list_root, collation_coinbase, post_state_root, receipt_root, sig ]) header_logs = [] add_header_topic = utils.big_endian_to_int(utils.sha3("add_header()")) def header_event_watcher(log): header_logs, add_header_topic # print the last log and store the recent received one if log.topics[0] == add_header_topic: # print(log.data) header_logs.append(log.data) if len(header_logs) > 1: last_log = header_logs.pop(0) # [num, num, bytes32, bytes32, bytes32, address, bytes32, bytes32, bytes] # use sedes to prevent integer 0 from being decoded as b'' sedes = List([utils.big_endian_int, utils.big_endian_int, utils.hash32, utils.hash32, utils.hash32, utils.address, utils.hash32, utils.hash32, binary]) values = rlp.decode(last_log, sedes) print("add_header: shard_id={}, expected_period_number={}, header_hash={}, parent_header_hash={}".format(values[0], values[1], utils.sha3(last_log), values[3])) c.head_state.log_listeners.append(header_event_watcher) shard_id = 0 shard0_genesis_colhdr_hash = utils.encode_int32(0) # test get_shard_head: returns genesis_colhdr_hash when there is no new header assert x.get_shard_head() == shard0_genesis_colhdr_hash h1 = get_colhdr(shard_id, shard0_genesis_colhdr_hash) h1_hash = utils.sha3(h1) # test add_header: fails when there is no collator in this period assert not x.add_header(h1) assert 1 == x.deposit(k0_valcode_addr, return_addr, value=DEPOSIT_SIZE, sender=t.k0) # test add_header: works normally with parent_collation_hash == GENESIS assert x.add_header(h1) # test add_header: fails when the header is added before with pytest.raises(t.TransactionFailed): h1 = get_colhdr(shard_id, shard0_genesis_colhdr_hash) x.add_header(h1) # test add_header: fails when the parent_collation_hash is not added before with pytest.raises(t.TransactionFailed): h2 = get_colhdr(shard_id, utils.sha3("123")) x.add_header(h2) # test add_header: the log is generated normally h2 = get_colhdr(shard_id, h1_hash) h2_hash = utils.sha3(h2) assert x.add_header(h2) latest_log_hash = utils.sha3(header_logs[-1]) assert h2_hash == latest_log_hash # test get_shard_head: get the correct head when a new header is added assert x.get_shard_head(0) == h2_hash # test get_shard_head: get the correct head when a fork happened h1_prime = get_colhdr(shard_id, shard0_genesis_colhdr_hash, collation_coinbase=t.a1) h1_prime_hash = utils.sha3(h1_prime) assert x.add_header(h1_prime) h2_prime = get_colhdr(shard_id, h1_prime_hash, collation_coinbase=t.a1) h2_prime_hash = utils.sha3(h2_prime) assert x.add_header(h2_prime) assert x.get_shard_head(0) == h2_hash h3_prime = get_colhdr(shard_id, h2_prime_hash, collation_coinbase=t.a1) h3_prime_hash = utils.sha3(h3_prime) assert x.add_header(h3_prime) assert x.get_shard_head(0) == h3_prime_hash ''' # test get_ancestor: h3_prime's height is too low so and it doesn't have a # 10000th ancestor. So it should fail. with pytest.raises(t.TransactionFailed): ancestor_10000th_hash = x.get_ancestor(shard_id, h3_prime_hash) # test get_ancestor: # TODO: figure out a better test instead of adding headers one by one. # This test takes few minutes. For now, you can adjust the `kth_ancestor` # to a smaller number here, and the same number of iterations of the `for` # loop in `get_ancestor` in the validator_manager contract. current_height = 3 # h3_prime kth_ancestor = 10000 current_colhdr_hash = h3_prime_hash # add (kth_ancestor - current_height) headers to get the genesis as the ancestor for i in range(kth_ancestor - current_height): current_colhdr = get_colhdr(shard_id, current_colhdr_hash, collation_coinbase=t.a1) assert x.add_header(current_colhdr) current_colhdr_hash = utils.sha3(current_colhdr) assert x.get_ancestor(shard_id, current_colhdr_hash) == shard0_genesis_colhdr_hash ''' # test tx_to_shard: add request tx and get the receipt id to_addr = utils.privtoaddr(utils.sha3("to_addr")) startgas = 100000 gasprice = 1 receipt_id0 = x.tx_to_shard(to_addr, 0, startgas, gasprice, b'', sender=t.k0, value=100) assert 0 == receipt_id0 # test tx_to_shard: see if receipt_id is incrementing when called # multiple times receipt_id1 = x.tx_to_shard(to_addr, 0, startgas, gasprice, b'', sender=t.k1, value=101) assert 1 == receipt_id1 assert 101 == x.get_receipts__value(receipt_id1) # test update_gasprice: fails when msg.sender doesn't match with pytest.raises(t.TransactionFailed): x.update_gasprice(receipt_id1, 2, sender=t.k0) # test update_gasprice: see if the gasprice updated successfully assert x.update_gasprice(receipt_id1, 2, sender=t.k1) assert 2 == x.get_receipts__tx_gasprice(receipt_id1) print(utils.checksum_encode(get_valmgr_addr()))