Skip to content

Commit

Permalink
Merge pull request #131 from sigp/withdrawal-addr-logout
Browse files Browse the repository at this point in the history
Withdrawal addr should be able to call logout #121
  • Loading branch information
djrtwo authored May 10, 2018
2 parents 8d8df61 + dde89bc commit dcf4caf
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 27 deletions.
3 changes: 2 additions & 1 deletion casper/contracts/simple_casper.v.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,8 @@ def logout(logout_msg: bytes <= 1024):
sig: bytes <= 1024 = values[2]

assert self.current_epoch >= epoch
assert self.validate_signature(msg_hash, sig, validator_index)
from_withdrawal: bool = msg.sender == self.validators[validator_index].withdrawal_addr
assert from_withdrawal or self.validate_signature(msg_hash, sig, validator_index)

# Check that we haven't already withdrawn
end_dynasty: int128 = self.dynasty + self.DYNASTY_LOGOUT_DELAY
Expand Down
38 changes: 30 additions & 8 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,21 +365,43 @@ def mk_slash_votes(validator_index, privkey):


@pytest.fixture
def mk_logout():
def mk_logout(validator_index, epoch, key):
def mk_logout_msg_signed():
def mk_logout_msg_signed(validator_index, epoch, key):
msg_hash = utils.sha3(rlp.encode([validator_index, epoch]))
v, r, s = utils.ecdsa_raw_sign(msg_hash, key)
sig = utils.encode_int32(v) + utils.encode_int32(r) + utils.encode_int32(s)
return rlp.encode([validator_index, epoch, sig])
return mk_logout
return mk_logout_msg_signed


@pytest.fixture
def logout_validator(casper, mk_logout):
def logout_validator(validator_index, key):
logout_tx = mk_logout(validator_index, casper.current_epoch(), key)
casper.logout(logout_tx)
return logout_validator
def mk_logout_msg_unsigned():
def mk_logout_msg_unsigned(validator_index, epoch):
v, r, s = (0, 0, 0)
sig = utils.encode_int32(v) + utils.encode_int32(r) + utils.encode_int32(s)
return rlp.encode([validator_index, epoch, sig])
return mk_logout_msg_unsigned


@pytest.fixture
def logout_validator_via_signed_msg(casper, mk_logout_msg_signed):
def logout_validator_via_signed_msg(validator_index, msg_signing_key,
tx_sender_key=42):
logout_tx = mk_logout_msg_signed(
validator_index,
casper.current_epoch(),
msg_signing_key
)
casper.logout(logout_tx, sender=tx_sender_key)
return logout_validator_via_signed_msg


@pytest.fixture
def logout_validator_via_unsigned_msg(casper, mk_logout_msg_unsigned):
def logout_validator_via_unsigned_msg(validator_index, tx_sender_key):
logout_tx = mk_logout_msg_unsigned(validator_index, casper.current_epoch())
casper.logout(logout_tx, sender=tx_sender_key)
return logout_validator_via_unsigned_msg


@pytest.fixture
Expand Down
90 changes: 82 additions & 8 deletions tests/test_logout.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,47 @@


def test_logout_sets_end_dynasty(casper, funded_privkey, deposit_amount,
induct_validator, logout_validator):
induct_validator,
logout_validator_via_signed_msg):
validator_index = induct_validator(funded_privkey, deposit_amount)

expected_end_dynasty = casper.dynasty() + casper.DYNASTY_LOGOUT_DELAY()
assert casper.validators__end_dynasty(validator_index) == 1000000000000000000000000000000

logout_validator(validator_index, funded_privkey)
logout_validator_via_signed_msg(validator_index, funded_privkey)

assert casper.validators__end_dynasty(validator_index) == expected_end_dynasty


def test_logout_sets_total_deposits_at_logout(casper, funded_privkey, deposit_amount,
induct_validator, logout_validator):
induct_validator,
logout_validator_via_signed_msg):
validator_index = induct_validator(funded_privkey, deposit_amount)
assert casper.validators__total_deposits_at_logout(validator_index) == 0

logout_validator(validator_index, funded_privkey)
logout_validator_via_signed_msg(validator_index, funded_privkey)

assert casper.validators__total_deposits_at_logout(validator_index) == deposit_amount


def test_logout_updates_dynasty_wei_delta(casper, funded_privkey, deposit_amount,
induct_validator, logout_validator):
induct_validator,
logout_validator_via_signed_msg):
validator_index = induct_validator(funded_privkey, deposit_amount)
scaled_deposit_size = casper.validators__deposit(validator_index)

expected_end_dynasty = casper.dynasty() + casper.DYNASTY_LOGOUT_DELAY()
assert casper.dynasty_wei_delta(expected_end_dynasty) == 0

logout_validator(validator_index, funded_privkey)
logout_validator_via_signed_msg(validator_index, funded_privkey)

assert casper.dynasty_wei_delta(expected_end_dynasty) == -scaled_deposit_size


def test_logout_with_multiple_validators(casper, funded_privkeys,
deposit_amount, new_epoch, induct_validators,
mk_suggested_vote, logout_validator):
mk_suggested_vote,
logout_validator_via_signed_msg):
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)
Expand All @@ -58,7 +62,7 @@ def test_logout_with_multiple_validators(casper, funded_privkeys,
logged_in_indexes = validator_indexes[1:]
logged_in_privkeys = funded_privkeys[1:]

logout_validator(logged_out_index, logged_out_privkey)
logout_validator_via_signed_msg(logged_out_index, logged_out_privkey)

# enter validator's end_dynasty (validator in prevdyn)
dynasty_logout_delay = casper.DYNASTY_LOGOUT_DELAY()
Expand Down Expand Up @@ -96,3 +100,73 @@ def test_logout_with_multiple_validators(casper, funded_privkeys,

casper.withdraw(logged_out_index)
assert_validator_empty(casper, logged_out_index)


def test_logout_from_withdrawal_address_without_signature(casper,
funded_privkey,
deposit_amount,
induct_validator,
logout_validator_via_unsigned_msg):
validator_index = induct_validator(funded_privkey, deposit_amount)
expected_end_dynasty = casper.dynasty() + casper.DYNASTY_LOGOUT_DELAY()

logout_validator_via_unsigned_msg(validator_index, funded_privkey)

assert casper.validators__end_dynasty(validator_index) == expected_end_dynasty


def test_logout_from_withdrawal_address_with_signature(casper,
funded_privkey,
deposit_amount,
induct_validator,
logout_validator_via_signed_msg,
assert_tx_failed):
validator_index = induct_validator(funded_privkey, deposit_amount)
expected_end_dynasty = casper.dynasty() + casper.DYNASTY_LOGOUT_DELAY()

logout_validator_via_signed_msg(
validator_index,
funded_privkey,
funded_privkey
)

assert casper.validators__end_dynasty(validator_index) == expected_end_dynasty


def test_logout_from_non_withdrawal_address_without_signature(casper,
funded_privkeys,
deposit_amount,
induct_validator,
logout_validator_via_unsigned_msg,
assert_tx_failed):
validator_key = funded_privkeys[0]
non_validator_key = funded_privkeys[1]
assert validator_key != non_validator_key

validator_index = induct_validator(validator_key, deposit_amount)

assert_tx_failed(
lambda: logout_validator_via_unsigned_msg(validator_index, non_validator_key)
)


def test_logout_from_non_withdrawal_address_with_signature(casper,
funded_privkeys,
deposit_amount,
induct_validator,
logout_validator_via_signed_msg,
assert_tx_failed):
validator_key = funded_privkeys[0]
non_validator_key = funded_privkeys[1]
assert validator_key != non_validator_key

validator_index = induct_validator(validator_key, deposit_amount)
expected_end_dynasty = casper.dynasty() + casper.DYNASTY_LOGOUT_DELAY()

logout_validator_via_signed_msg(
validator_index,
validator_key,
non_validator_key
)

assert casper.validators__end_dynasty(validator_index) == expected_end_dynasty
15 changes: 9 additions & 6 deletions tests/test_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,9 @@ def test_vote_log(casper, funded_privkey, new_epoch, deposit_validator,
assert log['_source_epoch'] == casper.recommended_source_epoch()


def test_logout_log(casper, funded_privkey, new_epoch, deposit_validator, logout_validator,
deposit_amount, get_last_log, casper_chain, mk_suggested_vote):
def test_logout_log(casper, funded_privkey, new_epoch, deposit_validator,
logout_validator_via_signed_msg,
deposit_amount, get_last_log, casper_chain, mk_suggested_vote):
new_epoch()
validator_index = casper.next_validator_index()
deposit_validator(funded_privkey, deposit_amount)
Expand All @@ -139,7 +140,7 @@ def test_logout_log(casper, funded_privkey, new_epoch, deposit_validator, logout

casper.vote(mk_suggested_vote(validator_index, funded_privkey))

logout_validator(validator_index, funded_privkey)
logout_validator_via_signed_msg(validator_index, funded_privkey)
# Logout log
log = get_last_log(casper_chain, casper)
assert {'_event_type', '_from', '_validator_index', '_end_dyn'} == log.keys()
Expand All @@ -149,8 +150,10 @@ def test_logout_log(casper, funded_privkey, new_epoch, deposit_validator, logout
assert log['_end_dyn'] == casper.dynasty() + casper.DYNASTY_LOGOUT_DELAY()


def test_withdraw_log(casper, funded_privkey, new_epoch, deposit_validator, logout_validator,
deposit_amount, get_last_log, casper_chain, mk_suggested_vote):
def test_withdraw_log(casper, funded_privkey, new_epoch, deposit_validator,
logout_validator_via_signed_msg,
deposit_amount, get_last_log, casper_chain,
mk_suggested_vote):
new_epoch()
validator_index = casper.next_validator_index()
deposit_validator(funded_privkey, deposit_amount)
Expand All @@ -165,7 +168,7 @@ def test_withdraw_log(casper, funded_privkey, new_epoch, deposit_validator, logo
casper.vote(mk_suggested_vote(validator_index, funded_privkey))
new_epoch()

logout_validator(validator_index, funded_privkey)
logout_validator_via_signed_msg(validator_index, funded_privkey)
# Logout delay
for _ in range(casper.DYNASTY_LOGOUT_DELAY() + 1):
casper.vote(mk_suggested_vote(validator_index, funded_privkey))
Expand Down
10 changes: 6 additions & 4 deletions tests/test_slashing.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,14 @@ def test_slash_no_surround(casper, funded_privkey, deposit_amount, new_epoch,

def test_slash_after_logout_delay(casper, funded_privkey, deposit_amount,
induct_validator, mk_suggested_vote, mk_slash_votes,
new_epoch, logout_validator):
new_epoch, fake_hash,
logout_validator_via_signed_msg):
validator_index = induct_validator(funded_privkey, deposit_amount)
scaled_deposit_size = casper.validators__deposit(validator_index)

assert casper.total_curdyn_deposits_in_wei() == deposit_amount

logout_validator(validator_index, funded_privkey)
logout_validator_via_signed_msg(validator_index, funded_privkey)
end_dynasty = casper.validators__end_dynasty(validator_index)
assert casper.validators__total_deposits_at_logout(validator_index) == deposit_amount

Expand Down Expand Up @@ -117,13 +118,14 @@ def test_slash_after_logout_delay(casper, funded_privkey, deposit_amount,
def test_slash_after_logout_before_logout_delay(casper, funded_privkey, deposit_amount,
induct_validator,
mk_suggested_vote, mk_slash_votes,
new_epoch, logout_validator):
new_epoch, fake_hash,
logout_validator_via_signed_msg):
validator_index = induct_validator(funded_privkey, deposit_amount)
scaled_deposit_size = casper.validators__deposit(validator_index)

assert casper.total_curdyn_deposits_in_wei() == deposit_amount

logout_validator(validator_index, funded_privkey)
logout_validator_via_signed_msg(validator_index, funded_privkey)
end_dynasty = casper.validators__end_dynasty(validator_index)

assert casper.dynasty_wei_delta(end_dynasty) == -scaled_deposit_size
Expand Down

0 comments on commit dcf4caf

Please sign in to comment.