def test_deregister_then_register(smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) # Register notary 0 and fast forward to next period smc_handler.register_notary(private_key=notary_0.private_key) fast_forward(smc_handler, 1) # Deregister notary 0 first # NOTE: Deregistration would also invoke update_notary_sample_size function smc_handler.deregister_notary(private_key=notary_0.private_key) mine(w3, 1) # Check that current_period_notary_sample_size is updated current_period_notary_sample_size = smc_handler.current_period_notary_sample_size( ) assert current_period_notary_sample_size == 1 notary_1 = NotaryAccount(1) # Then register notary 1 smc_handler.register_notary(private_key=notary_1.private_key) mine(w3, 1) _, notary_1_pool_index = smc_handler.get_notary_info( notary_1.checksum_address) assert notary_1_pool_index == 0 # Check that next_period_notary_sample_size remains the same next_period_notary_sample_size = smc_handler.next_period_notary_sample_size( ) assert (notary_1_pool_index + 1) == next_period_notary_sample_size
def test_committee_change_with_deregister_then_register( smc_handler): # noqa: F811 w3 = smc_handler.web3 # Register notary 0~8 and fast forward to next period batch_register(smc_handler, 0, 8) fast_forward(smc_handler, 1) # Update notary sample size update_notary_sample_size(smc_handler) notary_pool_list = get_notary_pool_list(smc_handler) # Choose the first sampled notary and deregister it notary = get_committee_list(smc_handler, 0)[0] notary_index = notary_pool_list.index(notary) smc_handler.deregister_notary( private_key=NotaryAccount(notary_index).private_key) mine(w3, 1) # Check that first slot in committee is now empty assert smc_handler.get_member_of_committee(0, 0) == b'\x00' * 20 # Register notary 9 smc_handler.register_notary(private_key=NotaryAccount(9).private_key) mine(w3, 1) # Check that first slot in committee is replaced by notary 9 assert smc_handler.get_member_of_committee( 0, 0) == NotaryAccount(9).canonical_address
def test_submit_vote_with_invalid_args(smc_handler, period, shard_id, chunk_root, sample_index): w3 = smc_handler.web3 # Register notary 0~8 and fast forward to next period batch_register(smc_handler, 0, 8) fast_forward(smc_handler, 1) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] assert current_period == 1 # Add correct collation record smc_handler.add_header( shard_id=0, period=current_period, chunk_root=b'\x10' * 32, private_key=NotaryAccount(index=0).private_key, ) mine(w3, 1) pool_index = sampling(smc_handler, 0)[0] # Vote with provided incorrect arguments tx_hash = smc_handler.submit_vote( shard_id=shard_id, period=period, chunk_root=chunk_root, index=sample_index, private_key=NotaryAccount(index=pool_index).private_key, ) mine(w3, 1) # Check that transaction failed and vote count remains the same # and no logs has been emitted assert len(w3.eth.getTransactionReceipt(tx_hash)['logs']) == 0 assert smc_handler.get_vote_count(shard_id) == 0 assert not smc_handler.has_notary_voted(shard_id, sample_index)
def test_submit_vote_then_deregister(smc_handler): # noqa: F811 w3 = smc_handler.web3 # We only vote in shard 0 for ease of testing shard_id = 0 # Register notary 0~8 and fast forward to next period batch_register(smc_handler, 0, 8) fast_forward(smc_handler, 1) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] assert current_period == 1 # Add collation record CHUNK_ROOT_1_0 = b'\x10' * 32 smc_handler.add_header( shard_id=shard_id, period=current_period, chunk_root=CHUNK_ROOT_1_0, private_key=NotaryAccount(index=0).private_key, ) mine(w3, 1) sample_index = 0 pool_index = sampling(smc_handler, shard_id)[sample_index] smc_handler.submit_vote( shard_id=shard_id, period=current_period, chunk_root=CHUNK_ROOT_1_0, index=sample_index, private_key=NotaryAccount(index=pool_index).private_key, ) mine(w3, 1) # Check that vote has been casted successfully assert smc_handler.get_vote_count(shard_id) == 1 assert smc_handler.has_notary_voted(shard_id, sample_index) # The notary deregisters smc_handler.deregister_notary( private_key=NotaryAccount(pool_index).private_key) mine(w3, 1) # Check that vote was not effected by deregistration assert smc_handler.get_vote_count(shard_id) == 1 assert smc_handler.has_notary_voted(shard_id, sample_index) # Notary 9 registers and takes retired notary's place in pool smc_handler.register_notary(private_key=NotaryAccount(9).private_key) # Attempt to vote tx_hash = smc_handler.submit_vote( shard_id=shard_id, period=current_period, chunk_root=CHUNK_ROOT_1_0, index=sample_index, private_key=NotaryAccount(index=9).private_key, ) mine(w3, 1) # Check that transaction failed and vote count remains the same # and no logs has been emitted assert len(w3.eth.getTransactionReceipt(tx_hash)['logs']) == 0 assert smc_handler.get_vote_count(shard_id) == 1
def test_normal_add_header(smc_handler): # noqa: F811 w3 = smc_handler.web3 # Register notary 0~2 and fast forward to next period batch_register(smc_handler, 0, 2) fast_forward(smc_handler, 1) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] assert current_period == 1 # Check that collation records of shard 0 and shard 1 have not been updated before assert smc_handler.records_updated_period(0) == 0 assert smc_handler.records_updated_period(1) == 0 CHUNK_ROOT_1_0 = b'\x10' * 32 smc_handler.add_header( shard_id=0, period=1, chunk_root=CHUNK_ROOT_1_0, private_key=NotaryAccount(index=0).private_key, ) mine(w3=w3, num_blocks=1) # Check that collation record of shard 0 has been updated assert smc_handler.records_updated_period(0) == 1 assert smc_handler.get_collation_chunk_root(shard_id=0, period=1) == CHUNK_ROOT_1_0 fast_forward(smc_handler, 1) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] assert current_period == 2 CHUNK_ROOT_2_0 = b'\x20' * 32 smc_handler.add_header( shard_id=0, period=2, chunk_root=CHUNK_ROOT_2_0, private_key=NotaryAccount(index=0).private_key, ) mine(w3=w3, num_blocks=1) # Check that collation record of shard 0 has been updated assert smc_handler.records_updated_period(0) == 2 assert smc_handler.get_collation_chunk_root(shard_id=0, period=2) == CHUNK_ROOT_2_0 # Check that collation record of shard 1 has never been updated assert smc_handler.records_updated_period(1) == 0 CHUNK_ROOT_2_1 = b'\x21' * 32 smc_handler.add_header( shard_id=1, period=2, chunk_root=CHUNK_ROOT_2_1, private_key=NotaryAccount(index=0).private_key, ) mine(w3=w3, num_blocks=1) # Check that collation record of shard 1 has been updated assert smc_handler.records_updated_period(1) == 2 assert smc_handler.get_collation_chunk_root(shard_id=1, period=2) == CHUNK_ROOT_2_1
def test_deregister_and_new_notary_register(smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) # Register notary 0 smc_handler.register_notary(private_key=notary_0.private_key) mine(w3, 1) notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 1 notary_2 = NotaryAccount(2) # Register notary 1~3 batch_register(smc_handler, 1, 3) notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 4 # Check that empty_slots_stack is empty empty_slots_stack_top = smc_handler.empty_slots_stack_top() assert empty_slots_stack_top == 0 # Fast foward fast_forward(smc_handler, 1) # Deregister notary 2 smc_handler.deregister_notary(private_key=notary_2.private_key) mine(w3, 1) notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 3 # Check that empty_slots_stack is not empty empty_slots_stack_top = smc_handler.empty_slots_stack_top() assert empty_slots_stack_top == 1 _, notary_2_pool_index = smc_handler.get_notary_info( notary_2.checksum_address) empty_slots = smc_handler.empty_slots_stack(0) # Check that the top empty_slots entry point to notary 2 assert empty_slots == notary_2_pool_index notary_4 = NotaryAccount(4) # Register notary 4 smc_handler.register_notary(private_key=notary_4.private_key) mine(w3, 1) notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 4 # Check that empty_slots_stack is empty empty_slots_stack_top = smc_handler.empty_slots_stack_top() assert empty_slots_stack_top == 0 _, notary_4_pool_index = smc_handler.get_notary_info( notary_4.checksum_address) # Check that notary fill in notary 2's spot assert notary_4_pool_index == notary_2_pool_index
def test_add_header_wrong_shard(smc_handler): # noqa: F811 w3 = smc_handler.web3 shard_count = smc_handler.config['SHARD_COUNT'] # Register notary 0~2 and fast forward to next period batch_register(smc_handler, 0, 2) fast_forward(smc_handler, 1) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] assert current_period == 1 BLANK_CHUNK_ROOT = b'\x00' * 32 CHUNK_ROOT_1_0 = b'\x10' * 32 # Attempt to add collation record with illegal shard_id specified tx_hash = smc_handler.add_header( shard_id=shard_count + 1, period=1, chunk_root=CHUNK_ROOT_1_0, private_key=NotaryAccount(index=0).private_key, ) mine(w3, 1) # Check that collation record of shard 0 has not been updated and transaction consume all gas # and no logs has been emitted assert smc_handler.records_updated_period(0) == 0 assert smc_handler.get_collation_chunk_root(shard_id=0, period=1) == BLANK_CHUNK_ROOT assert len(w3.eth.getTransactionReceipt(tx_hash)['logs']) == 0 # Second attempt to add collation record with illegal shard_id specified tx_hash = smc_handler.add_header( shard_id=-1, period=1, chunk_root=CHUNK_ROOT_1_0, private_key=NotaryAccount(index=0).private_key, ) mine(w3, 1) # Check that collation record of shard 0 has not been updated and transaction consume all gas # and no logs has been emitted assert smc_handler.records_updated_period(0) == 0 assert smc_handler.get_collation_chunk_root(shard_id=0, period=1) == BLANK_CHUNK_ROOT assert len(w3.eth.getTransactionReceipt(tx_hash)['logs']) == 0 # Add correct collation record smc_handler.add_header( shard_id=0, period=1, chunk_root=CHUNK_ROOT_1_0, private_key=NotaryAccount(index=0).private_key, ) mine(w3=w3, num_blocks=1) # Check that collation record of shard 0 has been updated assert smc_handler.records_updated_period(0) == 1 assert smc_handler.get_collation_chunk_root(shard_id=0, period=1) == CHUNK_ROOT_1_0
def test_series_of_deregister_starting_from_bottom_of_the_stack( smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) notary_1 = NotaryAccount(1) notary_2 = NotaryAccount(2) # Register notary 0~2 batch_register(smc_handler, 0, 2) # Fast forward to next period fast_forward(smc_handler, 1) # Deregister from notary 0 to notary 2 # Deregister notary 0 smc_handler.deregister_notary(private_key=notary_0.private_key) mine(w3, 1) _, notary_0_pool_index = smc_handler.get_notary_info( notary_0.checksum_address) next_period_notary_sample_size = smc_handler.next_period_notary_sample_size( ) # Check that next_period_notary_sample_size remains the same assert next_period_notary_sample_size == 3 # Deregister notary 1 smc_handler.deregister_notary(private_key=notary_1.private_key) mine(w3, 1) _, notary_1_pool_index = smc_handler.get_notary_info( notary_1.checksum_address) next_period_notary_sample_size = smc_handler.next_period_notary_sample_size( ) # Check that next_period_notary_sample_size remains the same assert next_period_notary_sample_size == 3 # Deregister notary 2 smc_handler.deregister_notary(private_key=notary_2.private_key) mine(w3, 1) # Check that current_period_notary_sample_size is updated current_period_notary_sample_size = smc_handler.current_period_notary_sample_size( ) assert current_period_notary_sample_size == 3 _, notary_2_pool_index = smc_handler.get_notary_info( notary_2.checksum_address) next_period_notary_sample_size = smc_handler.next_period_notary_sample_size( ) assert next_period_notary_sample_size == 3 # Fast forward to next period fast_forward(smc_handler, 1) # Update notary sample size update_notary_sample_size(smc_handler) current_period_notary_sample_size = smc_handler.current_period_notary_sample_size( ) assert current_period_notary_sample_size == next_period_notary_sample_size
def test_series_of_deregister_starting_from_top_of_the_stack( smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) notary_1 = NotaryAccount(1) notary_2 = NotaryAccount(2) # Register notary 0~2 batch_register(smc_handler, 0, 2) next_period_notary_sample_size = smc_handler.next_period_notary_sample_size( ) assert next_period_notary_sample_size == 3 # Fast forward to next period fast_forward(smc_handler, 1) # Deregister from notary 2 to notary 0 # Deregister notary 2 smc_handler.deregister_notary(private_key=notary_2.private_key) mine(w3, 1) # Check that current_period_notary_sample_size is updated current_period_notary_sample_size = smc_handler.current_period_notary_sample_size( ) assert current_period_notary_sample_size == 3 # Check that next_period_notary_sample_size remains the samev next_period_notary_sample_size = smc_handler.next_period_notary_sample_size( ) assert next_period_notary_sample_size == 3 # Deregister notary 1 smc_handler.deregister_notary(private_key=notary_1.private_key) mine(w3, 1) # Check that next_period_notary_sample_size remains the same next_period_notary_sample_size = smc_handler.next_period_notary_sample_size( ) assert next_period_notary_sample_size == 3 # Deregister notary 0 smc_handler.deregister_notary(private_key=notary_0.private_key) mine(w3, 1) # Check that next_period_notary_sample_size remains the same next_period_notary_sample_size = smc_handler.next_period_notary_sample_size( ) assert next_period_notary_sample_size == 3 # Fast forward to next period fast_forward(smc_handler, 1) # Update notary sample size update_notary_sample_size(smc_handler) current_period_notary_sample_size = smc_handler.current_period_notary_sample_size( ) assert current_period_notary_sample_size == next_period_notary_sample_size
def test_submit_vote_without_add_header_first(smc_handler): # noqa: F811 w3 = smc_handler.web3 # We only vote in shard 0 for ease of testing shard_id = 0 # Register notary 0~8 and fast forward to next period batch_register(smc_handler, 0, 8) fast_forward(smc_handler, 1) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] assert current_period == 1 CHUNK_ROOT_1_0 = b'\x10' * 32 # Get the first notary in the sample list in this period and vote sample_index = 0 pool_index = sampling(smc_handler, shard_id)[sample_index] tx_hash = smc_handler.submit_vote( shard_id=shard_id, period=current_period, chunk_root=CHUNK_ROOT_1_0, index=sample_index, private_key=NotaryAccount(index=pool_index).private_key, ) mine(w3, 1) # Check that transaction failed and vote count remains the same # and no logs has been emitted assert len(w3.eth.getTransactionReceipt(tx_hash)['logs']) == 0 assert smc_handler.get_vote_count(shard_id) == 0 assert not smc_handler.has_notary_voted(shard_id, sample_index)
def test_register_without_enough_ether(smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert not does_notary_exist # Register without enough ether smc_handler._send_transaction( func_name='register_notary', args=[], private_key=notary_0.private_key, value=smc_handler.config['NOTARY_DEPOSIT'] // 10000, gas=smc_handler._estimate_gas_dict['register_notary'], ) mine(w3, 1) # Check that the registration failed does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert not does_notary_exist notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 0
def test_instant_release_notary(smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) # Register notary 0 smc_handler.register_notary(private_key=notary_0.private_key) mine(w3, 1) does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert does_notary_exist notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 1 # Fast foward fast_forward(smc_handler, 1) # Deregister notary 0 smc_handler.deregister_notary(private_key=notary_0.private_key) mine(w3, 1) notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 0 # Instant release notary 0 tx_hash = smc_handler.release_notary(private_key=notary_0.private_key) mine(w3, 1) # Check registry remain the same and the transaction consume all gas # and no logs has been emitted does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert does_notary_exist assert len(w3.eth.getTransactionReceipt(tx_hash)['logs']) == 0
def test_normal_release_notary(smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) # Register notary 0 smc_handler.register_notary(private_key=notary_0.private_key) mine(w3, 1) does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert does_notary_exist notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 1 # Fast foward fast_forward(smc_handler, 1) # Deregister notary 0 smc_handler.deregister_notary(private_key=notary_0.private_key) mine(w3, 1) notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 0 # Fast foward to end of lock up fast_forward(smc_handler, smc_handler.config['NOTARY_LOCKUP_LENGTH'] + 1) # Release notary 0 smc_handler.release_notary(private_key=notary_0.private_key) mine(w3, 1) does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert not does_notary_exist
def test_normal_deregister(smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) # Register notary 0 smc_handler.register_notary(private_key=notary_0.private_key) mine(w3, 1) does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert does_notary_exist notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 1 # Fast foward fast_forward(smc_handler, 1) # Deregister notary 0 smc_handler.deregister_notary(private_key=notary_0.private_key) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] mine(w3, 1) does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert does_notary_exist notary_deregistered_period, notary_pool_index = smc_handler.get_notary_info( notary_0.checksum_address) assert notary_deregistered_period == current_period notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 0
def test_get_sample_result(smc_handler): # noqa: F811 w3 = smc_handler.web3 # Register notary 0~8 and fast forward to next period batch_register(smc_handler, 0, 8) fast_forward(smc_handler, 1) # Update notary sample size current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] update_notary_sample_size(smc_handler) # Get all committee of current period committee_group = [] for shard_id in range(smc_handler.config['SHARD_COUNT']): committee_group.append(get_committee_list(smc_handler, shard_id)) # Get sampling result for notary 0 notary_0 = NotaryAccount(0) _, notary_0_pool_index = smc_handler.get_notary_info( notary_0.checksum_address) notary_0_sampling_result = get_sample_result(smc_handler, notary_0_pool_index) for (period, shard_id, sampling_index) in notary_0_sampling_result: assert period == current_period # Check that notary is correctly sampled in get_committee_list assert committee_group[shard_id][ sampling_index] == notary_0.canonical_address # Check that notary is correctly sampled in SMC assert smc_handler.get_member_of_committee(shard_id, sampling_index) \ == notary_0.canonical_address
def test_double_add_header(smc_handler): # noqa: F811 w3 = smc_handler.web3 # Register notary 0~2 and fast forward to next period batch_register(smc_handler, 0, 2) fast_forward(smc_handler, 1) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] assert current_period == 1 CHUNK_ROOT_1_0 = b'\x10' * 32 smc_handler.add_header( shard_id=0, period=1, chunk_root=CHUNK_ROOT_1_0, private_key=NotaryAccount(index=0).private_key, ) mine(w3=w3, num_blocks=1) # Check that collation record of shard 0 has been updated assert smc_handler.records_updated_period(0) == 1 assert smc_handler.get_collation_chunk_root(shard_id=0, period=1) == CHUNK_ROOT_1_0 # Attempt to add collation record again with same collation record tx_hash = smc_handler.add_header( shard_id=0, period=1, chunk_root=CHUNK_ROOT_1_0, private_key=NotaryAccount(index=0).private_key, ) mine(w3, 1) # Check that transaction consume all gas and no logs has been emitted assert len(w3.eth.getTransactionReceipt(tx_hash)['logs']) == 0 # Attempt to add collation record again with different chunk root tx_hash = smc_handler.add_header( shard_id=0, period=1, chunk_root=b'\x56' * 32, private_key=NotaryAccount(index=0).private_key, ) mine(w3, 1) # Check that collation record of shard 0 remains the same and transaction consume all gas # and no logs has been emitted assert smc_handler.records_updated_period(0) == 1 assert smc_handler.get_collation_chunk_root(shard_id=0, period=1) == CHUNK_ROOT_1_0 assert len(w3.eth.getTransactionReceipt(tx_hash)['logs']) == 0
def update_notary_sample_size(smc_handler): smc_handler._send_transaction( func_name='update_notary_sample_size', args=[], private_key=NotaryAccount(0).private_key, gas=smc_handler.config['DEFAULT_GAS'], ) mine(smc_handler.web3, 1)
def test_submit_vote_by_notary_sampled_multiple_times( smc_handler): # noqa: F811 w3 = smc_handler.web3 # We only vote in shard 0 for ease of testing shard_id = 0 # Here we only register 5 notaries so it's guaranteed that at least # one notary is going to be sampled twice. # Register notary 0~4 and fast forward to next period batch_register(smc_handler, 0, 4) fast_forward(smc_handler, 1) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] assert current_period == 1 # Add collation record CHUNK_ROOT_1_0 = b'\x10' * 32 smc_handler.add_header( shard_id=shard_id, period=current_period, chunk_root=CHUNK_ROOT_1_0, private_key=NotaryAccount(index=0).private_key, ) mine(w3, 1) # Find the notary that's sampled more than one time for pool_index in range(5): sample_index_list = [ sample_index for (_, _shard_id, sample_index) in get_sample_result(smc_handler, pool_index) if _shard_id == shard_id ] if len(sample_index_list) > 1: vote_count = len(sample_index_list) for sample_index in sample_index_list: smc_handler.submit_vote( shard_id=shard_id, period=current_period, chunk_root=CHUNK_ROOT_1_0, index=sample_index, private_key=NotaryAccount(index=pool_index).private_key, ) mine(w3, 1) # Check that every vote is successfully casted even by the same notary assert smc_handler.get_vote_count(shard_id) == vote_count break
def update_notary_sample_size(smc_handler): smc_handler._send_transaction( func_name='update_notary_sample_size', args=[], private_key=NotaryAccount(0).private_key, gas=smc_handler._estimate_gas_dict['update_notary_sample_size'], ) mine(smc_handler.web3, 1)
def test_normal_register(smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert not does_notary_exist # Register notary 0 smc_handler.register_notary(private_key=notary_0.private_key) mine(w3, 1) does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert does_notary_exist notary_deregistered_period, notary_pool_index = smc_handler.get_notary_info( notary_0.checksum_address) assert notary_deregistered_period == 0 and notary_pool_index == 0 notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 1 notary_1 = NotaryAccount(1) notary_2 = NotaryAccount(2) # Register notary 1 and notary 2 batch_register(smc_handler, 0, 2) does_notary_exist = smc_handler.does_notary_exist( notary_1.checksum_address) assert does_notary_exist notary_deregistered_period, notary_pool_index = smc_handler.get_notary_info( notary_1.checksum_address) assert notary_deregistered_period == 0 and notary_pool_index == 1 does_notary_exist = smc_handler.does_notary_exist( notary_2.checksum_address) assert does_notary_exist notary_deregistered_period, notary_pool_index = smc_handler.get_notary_info( notary_2.checksum_address) assert notary_deregistered_period == 0 and notary_pool_index == 2 notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 3
def test_submit_vote_by_non_eligible_notary(smc_handler): # noqa: F811 w3 = smc_handler.web3 # We only vote in shard 0 for ease of testing shard_id = 0 # Register notary 0~8 and fast forward to next period batch_register(smc_handler, 0, 8) fast_forward(smc_handler, 1) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] assert current_period == 1 # Add collation record CHUNK_ROOT_1_0 = b'\x10' * 32 smc_handler.add_header( shard_id=shard_id, period=current_period, chunk_root=CHUNK_ROOT_1_0, private_key=NotaryAccount(index=0).private_key, ) mine(w3, 1) sample_index = 0 pool_index = sampling(smc_handler, shard_id)[sample_index] wrong_pool_index = 0 if pool_index != 0 else 1 tx_hash = smc_handler.submit_vote( shard_id=shard_id, period=current_period, chunk_root=CHUNK_ROOT_1_0, index=sample_index, # Vote by non-eligible notary private_key=NotaryAccount(wrong_pool_index).private_key, ) mine(w3, 1) # Check that transaction failed and vote count remains the same # and no logs has been emitted assert len(w3.eth.getTransactionReceipt(tx_hash)['logs']) == 0 assert smc_handler.get_vote_count(shard_id) == 0 assert not smc_handler.has_notary_voted(shard_id, sample_index)
def test_register_then_deregister(smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) # Register notary 0 first smc_handler.register_notary(private_key=notary_0.private_key) mine(w3, 1) _, notary_0_pool_index = smc_handler.get_notary_info( notary_0.checksum_address) assert notary_0_pool_index == 0 next_period_notary_sample_size = smc_handler.next_period_notary_sample_size( ) assert (notary_0_pool_index + 1) == next_period_notary_sample_size # Then deregister notary 0 smc_handler.deregister_notary(private_key=notary_0.private_key) mine(w3, 1) # Check that next_period_notary_sample_size remains the same next_period_notary_sample_size = smc_handler.next_period_notary_sample_size( ) assert (notary_0_pool_index + 1) == next_period_notary_sample_size
def test_double_register(smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) # Register notary 0 smc_handler.register_notary(private_key=notary_0.private_key) mine(w3, 1) does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert does_notary_exist notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 1 # Try register notary 0 again tx_hash = smc_handler.register_notary(private_key=notary_0.private_key) mine(w3, 1) # Check pool remain the same and the transaction consume all gas # and no logs has been emitted notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 1 assert len(w3.eth.getTransactionReceipt(tx_hash)['logs']) == 0
def test_deregister_then_register(smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) # Register notary 0 smc_handler.register_notary(private_key=notary_0.private_key) mine(w3, 1) does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert does_notary_exist notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 1 # Fast foward fast_forward(smc_handler, 1) # Deregister notary 0 smc_handler.deregister_notary(private_key=notary_0.private_key) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] mine(w3, 1) does_notary_exist = smc_handler.does_notary_exist( notary_0.checksum_address) assert does_notary_exist notary_deregistered_period, notary_pool_index = smc_handler.get_notary_info( notary_0.checksum_address) assert notary_deregistered_period == current_period notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 0 # Register again right away tx_hash = smc_handler.register_notary(private_key=notary_0.private_key) mine(w3, 1) # Check pool remain the same and the transaction consume all gas # and no logs has been emitted notary_pool_length = smc_handler.notary_pool_len() assert notary_pool_length == 0 assert len(w3.eth.getTransactionReceipt(tx_hash)['logs']) == 0
def test_status_checking_functions(smc_handler, smc_testing_config): # noqa: F811 w3 = smc_handler.web3 config = smc_testing_config shard_tracker = ShardTracker( w3=w3, config=config, shard_id=0, smc_handler_address=smc_handler.address, ) # Register nine notaries batch_register(smc_handler, 0, 8) # Check that registration log was/was not emitted accordingly assert shard_tracker.is_notary_registered( notary=NotaryAccount(0).checksum_address) assert shard_tracker.is_notary_registered( notary=NotaryAccount(5).checksum_address) assert not shard_tracker.is_notary_registered( notary=NotaryAccount(9).checksum_address) fast_forward(smc_handler, 1) # Check that add header log has not been emitted yet current_period = w3.eth.blockNumber // config['PERIOD_LENGTH'] assert not shard_tracker.is_new_header_added(period=current_period) # Add header in multiple shards CHUNK_ROOT_1_0 = b'\x10' * 32 smc_handler.add_header( shard_id=0, period=current_period, chunk_root=CHUNK_ROOT_1_0, private_key=NotaryAccount(0).private_key, ) CHUNK_ROOT_1_7 = b'\x17' * 32 smc_handler.add_header( shard_id=7, period=current_period, chunk_root=CHUNK_ROOT_1_7, private_key=NotaryAccount(7).private_key, ) CHUNK_ROOT_1_3 = b'\x13' * 32 smc_handler.add_header( shard_id=3, period=current_period, chunk_root=CHUNK_ROOT_1_3, private_key=NotaryAccount(3).private_key, ) mine(w3, 1) # Check that add header log was successfully emitted assert shard_tracker.is_new_header_added(period=current_period) # Check that there has not been enough votes yet in shard 0 assert not shard_tracker.has_enough_vote(period=current_period) # Submit three votes in shard 0 and one vote in shard 7 for sample_index in range(3): pool_index = sampling(smc_handler, 0)[sample_index] smc_handler.submit_vote( shard_id=0, period=current_period, chunk_root=CHUNK_ROOT_1_0, index=sample_index, private_key=NotaryAccount(pool_index).private_key, ) mine(w3, 1) sample_index = 0 pool_index = sampling(smc_handler, 7)[sample_index] smc_handler.submit_vote( shard_id=7, period=current_period, chunk_root=CHUNK_ROOT_1_7, index=sample_index, private_key=NotaryAccount(pool_index).private_key, ) mine(w3, 1) # Check that there has not been enough votes yet in shard 0 # Only three votes in shard 0 while four is required assert not shard_tracker.has_enough_vote(period=current_period) # Cast the fourth vote sample_index = 3 pool_index = sampling(smc_handler, 0)[sample_index] smc_handler.submit_vote( shard_id=0, period=current_period, chunk_root=CHUNK_ROOT_1_0, index=sample_index, private_key=NotaryAccount(pool_index).private_key, ) mine(w3, 1) # Check that there are enough votes now in shard 0 assert shard_tracker.has_enough_vote(period=current_period) # Proceed to next period fast_forward(smc_handler, 1) # Go back and check the status of header and vote counts in last period current_period = w3.eth.blockNumber // config['PERIOD_LENGTH'] assert shard_tracker.is_new_header_added(period=(current_period - 1)) assert shard_tracker.has_enough_vote(period=(current_period - 1)) # Deregister smc_handler.deregister_notary(private_key=NotaryAccount(0).private_key) mine(w3, 1) # Check that deregistration log was/was not emitted accordingly assert shard_tracker.is_notary_deregistered( NotaryAccount(0).checksum_address) assert not shard_tracker.is_notary_deregistered( NotaryAccount(5).checksum_address) # Fast foward to end of lock up fast_forward(smc_handler, smc_handler.config['NOTARY_LOCKUP_LENGTH'] + 1) # Release smc_handler.release_notary(private_key=NotaryAccount(0).private_key) mine(w3, 1) # Check that log was successfully emitted assert shard_tracker.is_notary_released(NotaryAccount(0).checksum_address)
def test_normal_update_notary_sample_size(smc_handler): # noqa: F811 w3 = smc_handler.web3 notary_0 = NotaryAccount(0) # Register notary 0 smc_handler.register_notary(private_key=notary_0.private_key) mine(w3, 1) _, notary_0_pool_index = smc_handler.get_notary_info( notary_0.checksum_address) assert notary_0_pool_index == 0 next_period_notary_sample_size = smc_handler.next_period_notary_sample_size( ) assert (notary_0_pool_index + 1) == next_period_notary_sample_size notary_1 = NotaryAccount(1) # Register notary 1 smc_handler.register_notary(private_key=notary_1.private_key) mine(w3, 1) _, notary_1_pool_index = smc_handler.get_notary_info( notary_1.checksum_address) assert notary_1_pool_index == 1 next_period_notary_sample_size = smc_handler.next_period_notary_sample_size( ) assert (notary_1_pool_index + 1) == next_period_notary_sample_size # Check that it's not yet the time to update notary sample size, # i.e., current period is the same as latest period the notary sample size was updated. current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] notary_sample_size_updated_period = smc_handler.notary_sample_size_updated_period( ) assert current_period == notary_sample_size_updated_period # Check that current_period_notary_sample_size has not been updated before current_period_notary_sample_size = smc_handler.current_period_notary_sample_size( ) assert 0 == current_period_notary_sample_size # Try updating notary sample size update_notary_sample_size(smc_handler) # Check that current_period_notary_sample_size is not updated, # i.e., updating notary sample size failed. assert 0 == current_period_notary_sample_size # fast forward to next period fast_forward(smc_handler, 1) # Register notary 2 # NOTE: Registration would also invoke update_notary_sample_size function notary_2 = NotaryAccount(2) smc_handler.register_notary(private_key=notary_2.private_key) mine(w3, 1) # Check that current_period_notary_sample_size is updated, # i.e., it is assigned the value of next_period_notary_sample_size. current_period_notary_sample_size = smc_handler.current_period_notary_sample_size( ) assert next_period_notary_sample_size == current_period_notary_sample_size # Check that notary sample size is updated in this period current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] notary_sample_size_updated_period = smc_handler.notary_sample_size_updated_period( ) assert current_period == notary_sample_size_updated_period
def test_log_emission(smc_handler): # noqa: F811 w3 = smc_handler.web3 log_handler = LogHandler(w3, smc_handler.config['PERIOD_LENGTH']) shard_tracker = ShardTracker( config=smc_handler.config, shard_id=0, log_handler=log_handler, smc_handler_address=smc_handler.address, ) notary = NotaryAccount(0) # Register smc_handler.register_notary(private_key=notary.private_key) mine(w3, 1) # Check that log was successfully emitted log = shard_tracker.get_register_notary_logs()[0] assert getattr(log, 'index_in_notary_pool') == 0 and \ getattr(log, 'notary') == notary.checksum_address fast_forward(smc_handler, 1) # Add header CHUNK_ROOT_1_0 = b'\x10' * 32 smc_handler.add_header( shard_id=0, period=1, chunk_root=CHUNK_ROOT_1_0, private_key=notary.private_key, ) mine(w3, 1) # Check that log was successfully emitted log = shard_tracker.get_add_header_logs()[0] assert getattr(log, 'period') == 1 and getattr(log, 'shard_id') == 0 and \ getattr(log, 'chunk_root') == CHUNK_ROOT_1_0 # Submit vote sample_index = 0 pool_index = sampling(smc_handler, 0)[sample_index] smc_handler.submit_vote( shard_id=0, period=1, chunk_root=CHUNK_ROOT_1_0, index=sample_index, private_key=NotaryAccount(pool_index).private_key, ) mine(w3, 1) # Check that log was successfully emitted log = shard_tracker.get_submit_vote_logs()[0] assert getattr(log, 'period') == 1 and getattr(log, 'shard_id') == 0 and \ getattr(log, 'chunk_root') == CHUNK_ROOT_1_0 and \ getattr(log, 'notary') == NotaryAccount(pool_index).checksum_address fast_forward(smc_handler, 1) # Deregister smc_handler.deregister_notary(private_key=notary.private_key) mine(w3, 1) # Check that log was successfully emitted log = shard_tracker.get_deregister_notary_logs()[0] assert getattr(log, 'index_in_notary_pool') == 0 and \ getattr(log, 'notary') == notary.checksum_address and \ getattr(log, 'deregistered_period') == 2 # Fast foward to end of lock up fast_forward(smc_handler, smc_handler.config['NOTARY_LOCKUP_LENGTH'] + 1) # Release smc_handler.release_notary(private_key=notary.private_key) mine(w3, 1) # Check that log was successfully emitted log = shard_tracker.get_release_notary_logs()[0] assert getattr(log, 'index_in_notary_pool') == 0 and \ getattr(log, 'notary') == notary.checksum_address # Test fetching logs in past period assert shard_tracker.get_register_notary_logs(from_period=0, to_period=0) assert shard_tracker.get_add_header_logs(from_period=1, to_period=1) assert shard_tracker.get_submit_vote_logs(from_period=1, to_period=1) assert shard_tracker.get_deregister_notary_logs(from_period=2, to_period=2) assert shard_tracker.get_release_notary_logs( from_period=(3 + smc_handler.config['NOTARY_LOCKUP_LENGTH']), to_period=(3 + smc_handler.config['NOTARY_LOCKUP_LENGTH']) )
def test_normal_submit_vote(smc_handler): # noqa: F811 w3 = smc_handler.web3 # We only vote in shard 0 for ease of testing shard_id = 0 # Register notary 0~8 and fast forward to next period batch_register(smc_handler, 0, 8) fast_forward(smc_handler, 1) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] assert current_period == 1 # Add collation record CHUNK_ROOT_1_0 = b'\x10' * 32 smc_handler.add_header( shard_id=shard_id, period=current_period, chunk_root=CHUNK_ROOT_1_0, private_key=NotaryAccount(index=0).private_key, ) mine(w3, 1) # Get the first notary in the sample list in this period sample_index = 0 pool_index = sampling(smc_handler, shard_id)[sample_index] # Check that voting record does not exist prior to voting assert smc_handler.get_vote_count(shard_id) == 0 assert not smc_handler.has_notary_voted(shard_id, sample_index) # First notary vote smc_handler.submit_vote( shard_id=shard_id, period=current_period, chunk_root=CHUNK_ROOT_1_0, index=sample_index, private_key=NotaryAccount(index=pool_index).private_key, ) mine(w3, 1) # Check that vote has been casted successfully assert smc_handler.get_vote_count(shard_id) == 1 assert smc_handler.has_notary_voted(shard_id, sample_index) # Check that collation is not elected and forward to next period assert not smc_handler.get_collation_is_elected(shard_id=shard_id, period=current_period) fast_forward(smc_handler, 1) current_period = w3.eth.blockNumber // smc_handler.config['PERIOD_LENGTH'] assert current_period == 2 # Add collation record CHUNK_ROOT_2_0 = b'\x20' * 32 smc_handler.add_header( shard_id=shard_id, period=current_period, chunk_root=CHUNK_ROOT_2_0, private_key=NotaryAccount(index=0).private_key, ) mine(w3, 1) # Check that vote count is zero assert smc_handler.get_vote_count(shard_id) == 0 # Keep voting until the collation is elected. for (sample_index, pool_index) in enumerate(sampling(smc_handler, shard_id)): if smc_handler.get_collation_is_elected(shard_id=shard_id, period=current_period): assert smc_handler.get_vote_count( shard_id) == smc_handler.config['QUORUM_SIZE'] break # Check that voting record does not exist prior to voting assert not smc_handler.has_notary_voted(shard_id, sample_index) # Vote smc_handler.submit_vote( shard_id=shard_id, period=current_period, chunk_root=CHUNK_ROOT_2_0, index=sample_index, private_key=NotaryAccount(index=pool_index).private_key, ) mine(w3, 1) # Check that vote has been casted successfully assert smc_handler.has_notary_voted(shard_id, sample_index) # Check that the collation is indeed elected. assert smc_handler.get_collation_is_elected(shard_id=shard_id, period=current_period)
def batch_register(smc_handler, start, end): assert start <= end for i in range(start, end + 1): notary = NotaryAccount(i) smc_handler.register_notary(private_key=notary.private_key) mine(smc_handler.web3, 1)