diff --git a/casper/contracts/simple_casper.v.py b/casper/contracts/simple_casper.v.py index 9182ada..4dc43ed 100644 --- a/casper/contracts/simple_casper.v.py +++ b/casper/contracts/simple_casper.v.py @@ -10,7 +10,6 @@ Slash: event({_from: indexed(address), _offender: indexed(address), _offender_index: indexed(int128), _bounty: int128(wei), _destroyed: int128(wei)}) Epoch: event({_number: indexed(int128), _checkpoint_hash: indexed(bytes32), _is_justified: bool, _is_finalized: bool}) -# Information about validators validators: public({ # Used to determine the amount of wei the validator holds. To get the actual # amount of wei, multiply this by the deposit_scale_factor. @@ -21,15 +20,15 @@ end_dynasty: int128, # The address which the validator's signatures must verify to (to be later replaced with validation code) addr: address, - # Addess to withdraw to + # The address to withdraw to withdrawal_addr: address }[int128]) -# Historical checkoint hashes +# Historical checkpoint hashes checkpoint_hashes: public(bytes32[int128]) # Number of validators -nextValidatorIndex: public(int128) +next_validator_index: public(int128) # Mapping of validator's signature address to their index number validator_indexes: public(int128[address]) @@ -52,7 +51,6 @@ # Mapping of epoch to what dynasty it is dynasty_in_epoch: public(int128[int128]) -# Information for use in processing cryptoeconomic commitments votes: public({ # How many votes are there for this source epoch from the current dynasty cur_dyn_votes: decimal(wei / m)[int128], @@ -72,11 +70,22 @@ # Value used to calculate the per-epoch fee that validators should be charged deposit_scale_factor: public(decimal(m)[int128]) -# For debug purposes -# TODO: Remove this when ready. last_nonvoter_rescale: public(decimal) last_voter_rescale: public(decimal) +current_epoch: public(int128) +last_finalized_epoch: public(int128) +last_justified_epoch: public(int128) + +# Expected source epoch for a vote +expected_source_epoch: public(int128) + +# Total deposits destroyed +total_destroyed: wei_value + + +# ***** Parameters ***** + # Length of an epoch in blocks epoch_length: public(int128) @@ -86,24 +95,9 @@ # Logout delay in dynasties dynasty_logout_delay: public(int128) -# Current epoch -current_epoch: public(int128) - -# Last finalized epoch -last_finalized_epoch: public(int128) - -# Last justified epoch -last_justified_epoch: public(int128) - -# Expected source epoch for a vote -expected_source_epoch: public(int128) - -# Can withdraw destroyed deposits +# [backdoor] Can withdraw destroyed deposits owner: address -# Total deposits destroyed -total_destroyed: wei_value - # Sighash calculator library address sighasher: address @@ -113,10 +107,7 @@ # Reward for voting as fraction of deposit size reward_factor: public(decimal) -# Base interest factor base_interest_factor: public(decimal) - -# Base penalty factor base_penalty_factor: public(decimal) # Minimum deposit size if no one else is validating @@ -133,9 +124,9 @@ def __init__( _min_deposit_size: wei_value): self.epoch_length = _epoch_length - self.withdrawal_delay = _withdrawal_delay # delay in epochs - self.dynasty_logout_delay = _dynasty_logout_delay # delay in dynasties - self.owner = _owner # temporary backdoor for testing + self.withdrawal_delay = _withdrawal_delay + self.dynasty_logout_delay = _dynasty_logout_delay + self.owner = _owner self.base_interest_factor = _base_interest_factor self.base_penalty_factor = _base_penalty_factor self.min_deposit_size = _min_deposit_size @@ -145,7 +136,7 @@ def __init__( self.purity_checker = _purity_checker # Start validator index counter at 1 because validator_indexes[] requires non-zero values - self.nextValidatorIndex = 1 + self.next_validator_index = 1 self.deposit_scale_factor[0] = 10000000000.0 self.dynasty = 0 @@ -168,12 +159,12 @@ def deposit_size(validator_index: int128) -> int128(wei): @public @constant -def get_total_curdyn_deposits() -> wei_value: +def total_curdyn_deposits_scaled() -> wei_value: return floor(self.total_curdyn_deposits * self.deposit_scale_factor[self.current_epoch]) @public @constant -def get_total_prevdyn_deposits() -> wei_value: +def total_prevdyn_deposits_scaled() -> wei_value: return floor(self.total_prevdyn_deposits * self.deposit_scale_factor[self.current_epoch]) # Helper functions that clients can call to know what to vote @@ -262,9 +253,8 @@ def initialize_epoch(epoch: int128): # Setup self.current_epoch = epoch - # Reward if finalized at least in the last two epochs - self.last_nonvoter_rescale = (1 + self.collective_reward()) /(1 + self.reward_factor) - self.last_voter_rescale = self.last_nonvoter_rescale * (1 + self.reward_factor) + self.last_voter_rescale = 1 + self.collective_reward() + self.last_nonvoter_rescale = self.last_voter_rescale / (1 + self.reward_factor) self.deposit_scale_factor[epoch] = self.deposit_scale_factor[epoch - 1] * self.last_nonvoter_rescale if self.deposit_exists(): @@ -274,7 +264,8 @@ def initialize_epoch(epoch: int128): # ESF is only thing that is changing and reward_factor is being used above. assert self.reward_factor > 0 else: - self.insta_finalize() # TODO: comment on why. + # Before the first validator deposits, new epochs are finalized instantly. + self.insta_finalize() self.reward_factor = 0 # Increment the dynasty if finalized @@ -285,7 +276,6 @@ def initialize_epoch(epoch: int128): # Log new epoch creation log.Epoch(epoch, self.checkpoint_hashes[epoch], False, False) -# Send a deposit to join the validator set @public @payable def deposit(validation_addr: address, withdrawal_addr: address): @@ -295,22 +285,19 @@ def deposit(validation_addr: address, withdrawal_addr: address): assert msg.value >= self.min_deposit_size start_dynasty: int128 = self.dynasty + 2 scaled_deposit: decimal(wei/m) = msg.value / self.deposit_scale_factor[self.current_epoch] - self.validators[self.nextValidatorIndex] = { + self.validators[self.next_validator_index] = { deposit: scaled_deposit, start_dynasty: start_dynasty, end_dynasty: self.default_end_dynasty, addr: validation_addr, withdrawal_addr: withdrawal_addr } - self.validator_indexes[withdrawal_addr] = self.nextValidatorIndex - self.nextValidatorIndex += 1 + self.validator_indexes[withdrawal_addr] = self.next_validator_index + self.next_validator_index += 1 self.dynasty_wei_delta[start_dynasty] += scaled_deposit # Log deposit event log.Deposit(withdrawal_addr, self.validator_indexes[withdrawal_addr], validation_addr, self.validators[self.validator_indexes[withdrawal_addr]].start_dynasty, msg.value) -# Log in or log out from the validator set. A logged out validator can log -# back in later, if they do not log in for an entire withdrawal period, -# they can get their money out @public def logout(logout_msg: bytes <= 1024): assert self.current_epoch == floor(block.number / self.epoch_length) @@ -363,7 +350,7 @@ def withdraw(validator_index: int128): # Reward the given validator & miner, and reflect this in total deposit figured @private def proc_reward(validator_index: int128, reward: int128(wei/m)): - start_epoch: int128 = self.dynasty_start_epoch[self.validators[validator_index].start_dynasty] + # Reward validator self.validators[validator_index].deposit += reward start_dynasty: int128 = self.validators[validator_index].start_dynasty end_dynasty: int128 = self.validators[validator_index].end_dynasty @@ -375,6 +362,7 @@ def proc_reward(validator_index: int128, reward: int128(wei/m)): self.total_prevdyn_deposits += reward if end_dynasty < self.default_end_dynasty: # validator has submit `logout` self.dynasty_wei_delta[end_dynasty] -= reward + # Reward miner send(block.coinbase, floor(reward * self.deposit_scale_factor[self.current_epoch] / 8)) # Process a vote message diff --git a/tests/conftest.py b/tests/conftest.py index 2dd4651..0fdd01f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -372,7 +372,7 @@ def induct_validator(privkey, value): @pytest.fixture def induct_validators(casper_chain, casper, deposit_validator, new_epoch): def induct_validators(privkeys, values): - start_index = casper.nextValidatorIndex() + start_index = casper.next_validator_index() if casper.current_epoch() == 0: new_epoch() for privkey, value in zip(privkeys, values): diff --git a/tests/test_chain_initialization.py b/tests/test_chain_initialization.py index 5d17115..95178b9 100644 --- a/tests/test_chain_initialization.py +++ b/tests/test_chain_initialization.py @@ -36,10 +36,10 @@ def test_sig_hasher_is_pure( # sanity check on casper contract basic functionality def test_init_first_epoch(casper, new_epoch): assert casper.current_epoch() == 0 - assert casper.nextValidatorIndex() == 1 + assert casper.next_validator_index() == 1 new_epoch() assert casper.dynasty() == 0 - assert casper.nextValidatorIndex() == 1 + assert casper.next_validator_index() == 1 assert casper.current_epoch() == 1 diff --git a/tests/test_deposit.py b/tests/test_deposit.py index bfff379..be0f471 100644 --- a/tests/test_deposit.py +++ b/tests/test_deposit.py @@ -21,10 +21,10 @@ def test_deposit_sets_validator_deposit(casper, funded_privkey, deposit_amount, def test_deposit_updates_next_val_index(casper, funded_privkey, deposit_amount, deposit_validator): - next_validator_index = casper.nextValidatorIndex() + next_validator_index = casper.next_validator_index() validator_index = deposit_validator(funded_privkey, deposit_amount) assert validator_index == next_validator_index - assert casper.nextValidatorIndex() == next_validator_index + 1 + assert casper.next_validator_index() == next_validator_index + 1 def test_deposit_sets_start_dynasty(casper, funded_privkey, deposit_amount, @@ -56,20 +56,20 @@ def test_deposit_updates_dynasty_wei_delta(casper, funded_privkey, deposit_amoun def test_deposit_updates_total_deposits(casper, funded_privkey, deposit_amount, induct_validator, mk_suggested_vote, new_epoch): - assert casper.get_total_curdyn_deposits() == 0 - assert casper.get_total_prevdyn_deposits() == 0 + assert casper.total_curdyn_deposits_scaled() == 0 + assert casper.total_prevdyn_deposits_scaled() == 0 # note, full induction validator_index = induct_validator(funded_privkey, deposit_amount) - assert casper.get_total_curdyn_deposits() == deposit_amount - assert casper.get_total_prevdyn_deposits() == 0 + assert casper.total_curdyn_deposits_scaled() == deposit_amount + assert casper.total_prevdyn_deposits_scaled() == 0 casper.vote(mk_suggested_vote(validator_index, funded_privkey)) new_epoch() - assert casper.get_total_curdyn_deposits() == deposit_amount - assert casper.get_total_prevdyn_deposits() == deposit_amount + assert casper.total_curdyn_deposits_scaled() == deposit_amount + assert casper.total_prevdyn_deposits_scaled() == deposit_amount diff --git a/tests/test_logout.py b/tests/test_logout.py index 2918cc7..29f5891 100644 --- a/tests/test_logout.py +++ b/tests/test_logout.py @@ -30,7 +30,7 @@ def test_logout_with_multiple_validators(casper, funded_privkeys, mk_suggested_vote, logout_validator): validator_indexes = induct_validators(funded_privkeys, [deposit_amount] * len(funded_privkeys)) num_validators = len(validator_indexes) - assert casper.get_total_curdyn_deposits() == deposit_amount * len(funded_privkeys) + assert casper.total_curdyn_deposits_scaled() == deposit_amount * len(funded_privkeys) # finalize 3 epochs to get to a stable state for _ in range(3): @@ -59,8 +59,8 @@ def test_logout_with_multiple_validators(casper, funded_privkeys, 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.get_total_curdyn_deposits()) < num_validators - assert abs(total_deposit_size - casper.get_total_prevdyn_deposits()) < num_validators + assert abs(logged_in_deposit_size - casper.total_curdyn_deposits_scaled()) < num_validators + assert abs(total_deposit_size - casper.total_prevdyn_deposits_scaled()) < num_validators # validator no longer in prev or cur dyn for i, validator_index in enumerate(logged_in_indexes): @@ -69,8 +69,8 @@ def test_logout_with_multiple_validators(casper, funded_privkeys, logged_in_deposit_size = sum(map(casper.deposit_size, logged_in_indexes)) - assert abs(logged_in_deposit_size - casper.get_total_curdyn_deposits()) < num_validators - assert abs(logged_in_deposit_size - casper.get_total_prevdyn_deposits()) < num_validators + assert abs(logged_in_deposit_size - casper.total_curdyn_deposits_scaled()) < num_validators + assert abs(logged_in_deposit_size - casper.total_prevdyn_deposits_scaled()) < num_validators # validator can withdraw after delay for i in range(casper.withdrawal_delay()): diff --git a/tests/test_logs.py b/tests/test_logs.py index 5df1bbd..d279087 100644 --- a/tests/test_logs.py +++ b/tests/test_logs.py @@ -5,9 +5,9 @@ def test_logs(casper, funded_privkey, new_epoch, get_logs, deposit_validator, mk_suggested_vote, get_last_log, casper_chain, logout_validator): new_epoch() assert casper.current_epoch() == 1 - assert casper.nextValidatorIndex() == 1 + assert casper.next_validator_index() == 1 - validator_index = casper.nextValidatorIndex() + validator_index = casper.next_validator_index() deposit_validator(funded_privkey, 1900 * 10**18) # Deposit log log1 = get_last_log(casper_chain, casper) diff --git a/tests/test_multiple_validators.py b/tests/test_multiple_validators.py index 78ffa35..ca17313 100644 --- a/tests/test_multiple_validators.py +++ b/tests/test_multiple_validators.py @@ -1,7 +1,7 @@ def test_deposits(casper, funded_privkeys, deposit_amount, new_epoch, induct_validators): induct_validators(funded_privkeys, [deposit_amount] * len(funded_privkeys)) - assert casper.get_total_curdyn_deposits() == deposit_amount * len(funded_privkeys) - assert casper.get_total_prevdyn_deposits() == 0 + assert casper.total_curdyn_deposits_scaled() == deposit_amount * len(funded_privkeys) + assert casper.total_prevdyn_deposits_scaled() == 0 def test_deposits_on_staggered_dynasties(casper, funded_privkeys, deposit_amount, new_epoch, @@ -17,21 +17,21 @@ def test_deposits_on_staggered_dynasties(casper, funded_privkeys, deposit_amount for privkey in funded_privkeys[1:]: deposit_validator(privkey, deposit_amount) - assert casper.deposit_size(initial_validator) == casper.get_total_curdyn_deposits() + assert casper.deposit_size(initial_validator) == casper.total_curdyn_deposits_scaled() casper.vote(mk_suggested_vote(initial_validator, funded_privkeys[0])) new_epoch() - assert casper.deposit_size(initial_validator) == casper.get_total_curdyn_deposits() + assert casper.deposit_size(initial_validator) == casper.total_curdyn_deposits_scaled() casper.vote(mk_suggested_vote(initial_validator, funded_privkeys[0])) new_epoch() - assert casper.deposit_size(initial_validator) == casper.get_total_prevdyn_deposits() + assert casper.deposit_size(initial_validator) == casper.total_prevdyn_deposits_scaled() def test_justification_and_finalization(casper, funded_privkeys, deposit_amount, new_epoch, induct_validators, mk_suggested_vote): validator_indexes = induct_validators(funded_privkeys, [deposit_amount] * len(funded_privkeys)) - assert casper.get_total_curdyn_deposits() == deposit_amount * len(funded_privkeys) + assert casper.total_curdyn_deposits_scaled() == deposit_amount * len(funded_privkeys) prev_dynasty = casper.dynasty() for _ in range(10): @@ -47,7 +47,7 @@ def test_justification_and_finalization(casper, funded_privkeys, deposit_amount, def test_voters_make_more(casper, funded_privkeys, deposit_amount, new_epoch, induct_validators, mk_suggested_vote): validator_indexes = induct_validators(funded_privkeys, [deposit_amount] * len(funded_privkeys)) - assert casper.get_total_curdyn_deposits() == deposit_amount * len(funded_privkeys) + assert casper.total_curdyn_deposits_scaled() == deposit_amount * len(funded_privkeys) nonvoting_index = validator_indexes[0] voting_indexes = validator_indexes[1:] @@ -72,7 +72,7 @@ def test_voters_make_more(casper, funded_privkeys, deposit_amount, new_epoch, def test_partial_online(casper, funded_privkeys, deposit_amount, new_epoch, induct_validators, mk_suggested_vote): validator_indexes = induct_validators(funded_privkeys, [deposit_amount] * len(funded_privkeys)) - assert casper.get_total_curdyn_deposits() == deposit_amount * len(funded_privkeys) + assert casper.total_curdyn_deposits_scaled() == deposit_amount * len(funded_privkeys) half_index = int(len(validator_indexes) / 2) online_indexes = validator_indexes[0:half_index] @@ -80,14 +80,14 @@ def test_partial_online(casper, funded_privkeys, deposit_amount, new_epoch, offline_indexes = validator_indexes[half_index:-1] total_online_deposits = sum(map(casper.deposit_size, online_indexes)) - prev_ovp = total_online_deposits / casper.get_total_curdyn_deposits() + prev_ovp = total_online_deposits / casper.total_curdyn_deposits_scaled() for i in range(100): for i, validator_index in enumerate(online_indexes): casper.vote(mk_suggested_vote(validator_index, online_privkeys[i])) total_online_deposits = sum(map(casper.deposit_size, online_indexes)) - ovp = total_online_deposits / casper.get_total_curdyn_deposits() + ovp = total_online_deposits / casper.total_curdyn_deposits_scaled() # after two non-finalized epochs, offline voters should start losing more if i >= 2: diff --git a/tests/test_slashing.py b/tests/test_slashing.py index 563e68b..3a9c344 100644 --- a/tests/test_slashing.py +++ b/tests/test_slashing.py @@ -4,7 +4,7 @@ def test_slash_no_dbl_prepare(casper, funded_privkey, deposit_amount, get_last_log, induct_validator, mk_vote, fake_hash, casper_chain): validator_index = induct_validator(funded_privkey, deposit_amount) - assert casper.get_total_curdyn_deposits() == deposit_amount + assert casper.total_curdyn_deposits_scaled() == deposit_amount vote_1 = mk_vote( validator_index, @@ -41,7 +41,7 @@ def test_slash_no_dbl_prepare(casper, funded_privkey, deposit_amount, get_last_l def test_slash_no_surround(casper, funded_privkey, deposit_amount, new_epoch, induct_validator, mk_vote, fake_hash, assert_tx_failed): validator_index = induct_validator(funded_privkey, deposit_amount) - assert casper.get_total_curdyn_deposits() == deposit_amount + assert casper.total_curdyn_deposits_scaled() == deposit_amount vote_1 = mk_vote( validator_index, diff --git a/tests/test_voting.py b/tests/test_voting.py index 6662913..c317997 100644 --- a/tests/test_voting.py +++ b/tests/test_voting.py @@ -20,7 +20,7 @@ def test_deposit(casper_chain, casper, privkey, amount, success, deposit_validator, new_epoch, assert_tx_failed): new_epoch() assert casper.current_epoch() == 1 - assert casper.nextValidatorIndex() == 1 + assert casper.next_validator_index() == 1 if not success: assert_tx_failed(lambda: deposit_validator(privkey, amount)) @@ -28,7 +28,7 @@ def test_deposit(casper_chain, casper, privkey, amount, deposit_validator(privkey, amount) - assert casper.nextValidatorIndex() == 2 + assert casper.next_validator_index() == 2 assert casper.validator_indexes(utils.privtoaddr(privkey)) == 1 assert casper.deposit_size(1) == amount @@ -36,14 +36,14 @@ def test_deposit(casper_chain, casper, privkey, amount, new_epoch() assert casper.dynasty() == 2 - assert casper.get_total_curdyn_deposits() == amount - assert casper.get_total_prevdyn_deposits() == 0 + assert casper.total_curdyn_deposits_scaled() == amount + assert casper.total_prevdyn_deposits_scaled() == 0 def test_vote_single_validator(casper, funded_privkey, deposit_amount, new_epoch, induct_validator, mk_suggested_vote): validator_index = induct_validator(funded_privkey, deposit_amount) - assert casper.get_total_curdyn_deposits() == deposit_amount + assert casper.total_curdyn_deposits_scaled() == deposit_amount prev_dynasty = casper.dynasty() for i in range(10): @@ -58,7 +58,7 @@ def test_vote_single_validator(casper, funded_privkey, deposit_amount, def test_vote_target_epoch_twice(casper, funded_privkey, deposit_amount, new_epoch, induct_validator, mk_suggested_vote, assert_tx_failed): validator_index = induct_validator(funded_privkey, deposit_amount) - assert casper.get_total_curdyn_deposits() == deposit_amount + assert casper.total_curdyn_deposits_scaled() == deposit_amount casper.vote(mk_suggested_vote(validator_index, funded_privkey)) # second vote on same target epoch fails @@ -68,7 +68,7 @@ def test_vote_target_epoch_twice(casper, funded_privkey, deposit_amount, new_epo def test_non_finalization_loss(casper, funded_privkey, deposit_amount, new_epoch, induct_validator, mk_suggested_vote, assert_tx_failed): validator_index = induct_validator(funded_privkey, deposit_amount) - assert casper.get_total_curdyn_deposits() == deposit_amount + assert casper.total_curdyn_deposits_scaled() == deposit_amount casper.vote(mk_suggested_vote(validator_index, funded_privkey)) new_epoch() @@ -86,7 +86,7 @@ def test_non_finalization_loss(casper, funded_privkey, deposit_amount, new_epoch def test_mismatched_epoch_and_hash(casper, funded_privkey, deposit_amount, induct_validator, mk_vote, new_epoch, assert_tx_failed): validator_index = induct_validator(funded_privkey, deposit_amount) - assert casper.get_total_curdyn_deposits() == deposit_amount + assert casper.total_curdyn_deposits_scaled() == deposit_amount # step forward one epoch to ensure that validator is allowed # to vote on (current_epoch - 1) @@ -111,7 +111,7 @@ def test_consensus_after_non_finalization_streak(casper, funded_privkey, deposit induct_validator, mk_suggested_vote, assert_tx_failed): validator_index = induct_validator(funded_privkey, deposit_amount) - assert casper.get_total_curdyn_deposits() == deposit_amount + assert casper.total_curdyn_deposits_scaled() == deposit_amount # finalize an epoch as a base to the test casper.vote(mk_suggested_vote(validator_index, funded_privkey))