def test_withdraw_after_majority_slash(casper, casper_chain, funded_privkeys, deposit_amount, new_epoch, induct_validators, mk_suggested_vote, mk_slash_votes): validator_indexes = induct_validators(funded_privkeys, [deposit_amount] * len(funded_privkeys)) # 0th gets slashed slashed_indexes = validator_indexes[:-1] slashed_privkeys = funded_privkeys[:-1] slashed_public_keys = [ utils.privtoaddr(slashed_privkey) for slashed_privkey in slashed_privkeys ] # the rest remain logged_in_index = validator_indexes[-1] logged_in_privkey = funded_privkeys[-1] assert len(slashed_indexes) / float(len(funded_privkeys)) >= 1 / 3.0 for slashed_index, slashed_privkey in zip(slashed_indexes, slashed_privkeys): vote_1, vote_2 = mk_slash_votes(slashed_index, slashed_privkey) casper.slash(vote_1, vote_2) current_epoch = casper.current_epoch() assert casper.total_slashed( current_epoch) == deposit_amount * len(slashed_indexes) assert casper.total_slashed(current_epoch + 1) == 0 # artificially simulate the slashed validators voting # normally if this occured, the validators would likely stop # voting and their deposits would have to bleed out. for i, validator_index in enumerate(validator_indexes): casper.vote(mk_suggested_vote(validator_index, funded_privkeys[i])) new_epoch() # slashed validators can withdraw after end_dynasty plus delay for i in range(casper.WITHDRAWAL_DELAY() + 1): casper.vote(mk_suggested_vote(logged_in_index, logged_in_privkey)) new_epoch() assert casper.dynasty() > casper.validators__end_dynasty( slashed_indexes[0]) prev_balances = [ casper_chain.head_state.get_balance(slashed_public_key) for slashed_public_key in slashed_public_keys ] for slashed_index in slashed_indexes: casper.withdraw(slashed_index) for slashed_public_key, prev_balance in zip(slashed_public_keys, prev_balances): balance = casper_chain.head_state.get_balance(slashed_public_key) assert balance == prev_balance for slashed_index in slashed_indexes: assert_validator_empty(casper, slashed_index)
def test_logout_with_multiple_validators(casper, funded_privkeys, deposit_amount, new_epoch, induct_validators, mk_suggested_vote, logout_validator): validator_indexes = induct_validators(funded_privkeys, [deposit_amount] * len(funded_privkeys)) num_validators = len(validator_indexes) assert casper.total_curdyn_deposits_in_wei() == deposit_amount * len(funded_privkeys) # finalize 3 epochs to get to a stable state for _ in range(3): for i, validator_index in enumerate(validator_indexes): casper.vote(mk_suggested_vote(validator_index, funded_privkeys[i])) new_epoch() # 0th logs out logged_out_index = validator_indexes[0] logged_out_privkey = funded_privkeys[0] # the rest remain logged_in_indexes = validator_indexes[1:] logged_in_privkeys = funded_privkeys[1:] logout_validator(logged_out_index, logged_out_privkey) # enter validator's end_dynasty (validator in prevdyn) dynasty_logout_delay = casper.DYNASTY_LOGOUT_DELAY() for _ in range(dynasty_logout_delay): for i, validator_index in enumerate(validator_indexes): casper.vote(mk_suggested_vote(validator_index, funded_privkeys[i])) new_epoch() assert casper.validators__end_dynasty(logged_out_index) == casper.dynasty() logged_in_deposit_size = sum(map(casper.deposit_size, logged_in_indexes)) logging_out_deposit_size = casper.deposit_size(logged_out_index) total_deposit_size = logged_in_deposit_size + logging_out_deposit_size assert abs(logged_in_deposit_size - casper.total_curdyn_deposits_in_wei()) < num_validators assert abs(total_deposit_size - casper.total_prevdyn_deposits_in_wei()) < num_validators # validator no longer in prev or cur dyn for i, validator_index in enumerate(logged_in_indexes): casper.vote(mk_suggested_vote(validator_index, logged_in_privkeys[i])) new_epoch() logged_in_deposit_size = sum(map(casper.deposit_size, logged_in_indexes)) assert abs(logged_in_deposit_size - casper.total_curdyn_deposits_in_wei()) < num_validators assert abs(logged_in_deposit_size - casper.total_prevdyn_deposits_in_wei()) < num_validators # validator can withdraw after delay for i in range(casper.WITHDRAWAL_DELAY()): for i, validator_index in enumerate(logged_in_indexes): casper.vote(mk_suggested_vote(validator_index, logged_in_privkeys[i])) new_epoch() withdrawal_amount = casper.deposit_size(logged_out_index) assert withdrawal_amount > 0 casper.withdraw(logged_out_index) assert_validator_empty(casper, logged_out_index)
def test_withdraw_after_majority_slash(w3, casper, concise_casper, funded_accounts, validation_keys, deposit_amount, new_epoch, induct_validators, mk_suggested_vote, mk_slash_votes): validator_indexes = induct_validators(funded_accounts, validation_keys, [deposit_amount] * len(funded_accounts)) # 0th gets slashed slashed_indexes = validator_indexes[:-1] slashed_keys = validation_keys[:-1] slashed_addrs = funded_accounts[:-1] # the rest remain logged_in_index = validator_indexes[-1] logged_in_key = validation_keys[-1] assert len(slashed_indexes) / float(len(funded_accounts)) >= 1 / 3.0 for slashed_index, slashed_key in zip(slashed_indexes, slashed_keys): vote_1, vote_2 = mk_slash_votes(slashed_index, slashed_key) casper.functions.slash(vote_1, vote_2).transact() current_epoch = concise_casper.current_epoch() assert concise_casper.total_slashed( current_epoch) == deposit_amount * len(slashed_indexes) assert concise_casper.total_slashed(current_epoch + 1) == 0 # artificially simulate the slashed validators voting # normally if this occured, the validators would likely stop # voting and their deposits would have to bleed out. for i, validator_index in enumerate(validator_indexes): casper.functions.vote( mk_suggested_vote(validator_index, validation_keys[i])).transact() new_epoch() # slashed validators can withdraw after end_dynasty plus delay for _ in range(concise_casper.WITHDRAWAL_DELAY() + 1): casper.functions.vote(mk_suggested_vote(logged_in_index, logged_in_key)).transact() new_epoch() assert concise_casper.dynasty() > concise_casper.validators__end_dynasty( slashed_indexes[0]) prev_balances = [ w3.eth.getBalance(slashed_addr) for slashed_addr in slashed_addrs ] for slashed_index in slashed_indexes: casper.functions.withdraw(slashed_index).transact() for slashed_addr, prev_balance in zip(slashed_addrs, prev_balances): balance = w3.eth.getBalance(slashed_addr) assert balance == prev_balance for slashed_index in slashed_indexes: assert_validator_empty(concise_casper, slashed_index)
def test_withdraw_after_slash(w3, casper, concise_casper, funded_accounts, validation_keys, deposit_amount, new_epoch, induct_validators, mk_suggested_vote, mk_slash_votes): validator_indexes = induct_validators(funded_accounts, validation_keys, [deposit_amount] * len(funded_accounts)) slashed_fraction_of_total_deposits = 1.0 / len(funded_accounts) # 0th gets slashed slashed_index = validator_indexes[0] slashed_key = validation_keys[0] slashed_addr = funded_accounts[0] # the rest remain logged_in_indexes = validator_indexes[1:] logged_in_keys = validation_keys[1:] vote_1, vote_2 = mk_slash_votes(slashed_index, slashed_key) casper.functions.slash(vote_1, vote_2).transact() current_epoch = concise_casper.current_epoch() assert concise_casper.total_slashed(current_epoch) == deposit_amount assert concise_casper.total_slashed(current_epoch + 1) == 0 # slashed validator can withdraw after end_dynasty plus delay for _ in range(concise_casper.WITHDRAWAL_DELAY() + 2): for i, validator_index in enumerate(logged_in_indexes): casper.functions.vote( mk_suggested_vote(validator_index, logged_in_keys[i])).transact() new_epoch() end_dynasty = concise_casper.validators__end_dynasty(slashed_index) end_epoch = concise_casper.dynasty_start_epoch(end_dynasty + 1) withdrawal_epoch = end_epoch + concise_casper.WITHDRAWAL_DELAY() assert concise_casper.current_epoch() == withdrawal_epoch prev_balance = w3.eth.getBalance(slashed_addr) casper.functions.withdraw(slashed_index).transact() balance = w3.eth.getBalance(slashed_addr) assert concise_casper.current_epoch( ) == end_epoch + concise_casper.WITHDRAWAL_DELAY() assert balance > prev_balance expected_slashed_fraction = slashed_fraction_of_total_deposits * 3 expected_withdrawal_fraction = 1 - expected_slashed_fraction expected_withdrawal_amount = expected_withdrawal_fraction * deposit_amount withdrawal_amount = balance - prev_balance assert withdrawal_amount < deposit_amount # should be less than because of some loss due to inactivity during withdrawal period assert withdrawal_amount < expected_withdrawal_amount # ensure within proximity to expected_withdrawal_amount assert withdrawal_amount > expected_withdrawal_amount * 0.9 assert_validator_empty(concise_casper, slashed_index)
def test_withdraw_after_slash(casper, casper_chain, funded_privkeys, deposit_amount, new_epoch, induct_validators, mk_suggested_vote, mk_slash_votes): validator_indexes = induct_validators(funded_privkeys, [deposit_amount] * len(funded_privkeys)) slashed_fraction_of_total_deposits = 1.0 / len(funded_privkeys) # 0th gets slashed slashed_index = validator_indexes[0] slashed_privkey = funded_privkeys[0] slashed_public_key = utils.privtoaddr(slashed_privkey) # the rest remain logged_in_indexes = validator_indexes[1:] logged_in_privkeys = funded_privkeys[1:] vote_1, vote_2 = mk_slash_votes(slashed_index, slashed_privkey) casper.slash(vote_1, vote_2) current_epoch = casper.current_epoch() assert casper.total_slashed(current_epoch) == deposit_amount assert casper.total_slashed(current_epoch + 1) == 0 # slashed validator can withdraw after end_dynasty plus delay for i in range(casper.WITHDRAWAL_DELAY() + 2): for i, validator_index in enumerate(logged_in_indexes): casper.vote( mk_suggested_vote(validator_index, logged_in_privkeys[i])) new_epoch() prev_balance = casper_chain.head_state.get_balance(slashed_public_key) casper.withdraw(slashed_index) balance = casper_chain.head_state.get_balance(slashed_public_key) assert balance > prev_balance expected_slashed_fraction = slashed_fraction_of_total_deposits * 3 expected_withdrawal_fraction = 1 - expected_slashed_fraction expected_withdrawal_amount = expected_withdrawal_fraction * deposit_amount withdrawal_amount = balance - prev_balance assert withdrawal_amount < deposit_amount # should be less than because of some loss due to inactivity during withdrawal period assert withdrawal_amount < expected_withdrawal_amount # ensure within proximity to expected_withdrawal_amount assert withdrawal_amount > expected_withdrawal_amount * 0.9 assert_validator_empty(casper, slashed_index)
def test_logout_with_multiple_validators(w3, casper, concise_casper, funded_accounts, validation_keys, deposit_amount, new_epoch, induct_validators, send_vote, mk_suggested_vote, logout_validator_via_signed_msg): validator_indexes = induct_validators(funded_accounts, validation_keys, [deposit_amount] * len(funded_accounts)) num_validators = len(validator_indexes) assert concise_casper.total_curdyn_deposits_in_wei( ) == deposit_amount * len(funded_accounts) # finalize 3 epochs to get to a stable state for _ in range(3): for key, validator_index in zip(validation_keys, validator_indexes): send_vote(mk_suggested_vote(validator_index, key)) new_epoch() # 0th logs out logged_out_index = validator_indexes[0] logged_out_key = validation_keys[0] logged_out_addr = funded_accounts[0] # the rest remain logged_in_indexes = validator_indexes[1:] logged_in_keys = validation_keys[1:] logout_validator_via_signed_msg(logged_out_index, logged_out_key) # enter validator's end_dynasty (validator in prevdyn) dynasty_logout_delay = concise_casper.DYNASTY_LOGOUT_DELAY() for _ in range(dynasty_logout_delay): for key, validator_index in zip(validation_keys, validator_indexes): send_vote(mk_suggested_vote(validator_index, key)) new_epoch() assert concise_casper.validators__end_dynasty( logged_out_index) == concise_casper.dynasty() logged_in_deposit_size = sum( map(concise_casper.deposit_size, logged_in_indexes)) logging_out_deposit_size = concise_casper.deposit_size(logged_out_index) total_deposit_size = logged_in_deposit_size + logging_out_deposit_size curdyn_deposits = concise_casper.total_curdyn_deposits_in_wei() prevdyn_deposits = concise_casper.total_prevdyn_deposits_in_wei() assert abs(logged_in_deposit_size - curdyn_deposits) < num_validators assert abs(total_deposit_size - prevdyn_deposits) < num_validators # validator no longer in prev or cur dyn for key, validator_index in zip(logged_in_keys, logged_in_indexes): send_vote(mk_suggested_vote(validator_index, key)) new_epoch() logged_in_deposit_size = sum( map(concise_casper.deposit_size, logged_in_indexes)) curdyn_deposits = concise_casper.total_curdyn_deposits_in_wei() prevdyn_deposits = concise_casper.total_prevdyn_deposits_in_wei() assert abs(logged_in_deposit_size - curdyn_deposits) < num_validators assert abs(logged_in_deposit_size - prevdyn_deposits) < num_validators # validator can withdraw after delay for _ in range(concise_casper.WITHDRAWAL_DELAY()): for key, validator_index in zip(logged_in_keys, logged_in_indexes): send_vote(mk_suggested_vote(validator_index, key)) new_epoch() current_epoch = concise_casper.current_epoch() end_dynasty = concise_casper.validators__end_dynasty(logged_out_index) assert concise_casper.dynasty() > end_dynasty end_epoch = concise_casper.dynasty_start_epoch(end_dynasty + 1) # Allowed to withdraw assert current_epoch == end_epoch + concise_casper.WITHDRAWAL_DELAY() withdrawal_amount = int( concise_casper.validators__deposit(logged_out_index) * \ concise_casper.deposit_scale_factor(end_epoch) ) assert withdrawal_amount > 0 # ensure withdrawal went to the addr prev_balance = w3.eth.getBalance(logged_out_addr) casper.functions.withdraw(logged_out_index).transact() balance = w3.eth.getBalance(logged_out_addr) assert balance > prev_balance assert balance - prev_balance == withdrawal_amount assert_validator_empty(concise_casper, logged_out_index)