Updated Casper viper contract
This commit is contained in:
parent
d2d2b216df
commit
f7bc338e4b
|
@ -2,10 +2,10 @@
|
|||
validators: {
|
||||
# Amount of wei the validator holds
|
||||
deposit: wei_value,
|
||||
# The epoch the validator is joining
|
||||
epoch_start: num,
|
||||
# The epoch the validator is leaving
|
||||
epoch_end: num,
|
||||
# The dynasty the validator is joining
|
||||
dynasty_start: num,
|
||||
# The dynasty the validator is leaving
|
||||
dynasty_end: num,
|
||||
# The timestamp at which the validator can withdraw
|
||||
withdrawal_time: timestamp,
|
||||
# The address which the validator's signatures must verify to (to be later replaced with validation code)
|
||||
|
@ -18,14 +18,30 @@ validators: {
|
|||
max_committed: num
|
||||
}[num]
|
||||
|
||||
# The current dynasty (validator set changes between dynasties)
|
||||
dynasty: num
|
||||
# Amount of wei added to the total deposits in the next dynasty
|
||||
next_dynasty_wei_delta: wei_value
|
||||
# Amount of wei added to the total deposits in the dynasty after that
|
||||
second_next_dynasty_wei_delta: wei_value
|
||||
|
||||
# Total deposits during this dynasty
|
||||
total_deposits: wei_value[num]
|
||||
|
||||
# Information for use in processing cryptoeconomic commitments
|
||||
consensus_messages: {
|
||||
# Total deposits during this epoch
|
||||
total_deposits: wei_value,
|
||||
# How many prepares are there for this hash (hash of message hash + view source)
|
||||
# How many prepares are there for this hash (hash of message hash + view source) from the current dynasty
|
||||
prepares: wei_value[bytes32],
|
||||
# From the previous dynasty
|
||||
prev_dyn_prepares: wei_value[bytes32],
|
||||
# Is a commit on the given hash justified?
|
||||
justified: bool[bytes32],
|
||||
# How many commits are there for this hash
|
||||
commits: wei_value[bytes32],
|
||||
# And from the previous dynasty
|
||||
prev_dyn_commits: wei_value[bytes32],
|
||||
# Was the block committed?
|
||||
committed: bool
|
||||
}[num] # index: epoch
|
||||
|
||||
# ancestry[x][y] = k > 0: x is a kth generation ancestor of y
|
||||
|
@ -52,19 +68,48 @@ insufficiency_slash_delay: timedelta
|
|||
# Current epoch
|
||||
current_epoch: num
|
||||
|
||||
# Can withdraw destroyed deposits
|
||||
owner: address
|
||||
|
||||
# Total deposits destroyed
|
||||
total_destroyed: wei_value
|
||||
|
||||
def __init__():
|
||||
self.interest_rate = 0.000001
|
||||
self.block_time = 7
|
||||
self.epoch_length = 256
|
||||
self.withdrawal_delay = 2500000
|
||||
self.owner = 0x1db3439a222c519ab44bb1144fc28167b4fa6ee6
|
||||
self.validators[0] = {
|
||||
deposit: as_wei(3, finney),
|
||||
dynasty_start: 0,
|
||||
dynasty_end: 1000000000000000000000000000000,
|
||||
withdrawal_time: 1000000000000000000000000000000,
|
||||
addr: 0x1db3439a222c519ab44bb1144fc28167b4fa6ee6,
|
||||
withdrawal_addr: 0x1db3439a222c519ab44bb1144fc28167b4fa6ee6,
|
||||
max_prepared: 0,
|
||||
max_committed: 0
|
||||
}
|
||||
self.current_epoch = block.number / self.epoch_length
|
||||
|
||||
# Called at the start of any epoch
|
||||
def initialize_epoch(epoch: num):
|
||||
computed_current_epoch = block.number / self.epoch_length
|
||||
if epoch <= computed_current_epoch and epoch == self.current_epoch + 1:
|
||||
self.consensus_messages[epoch].total_deposits += self.consensus_messages[self.current_epoch].total_deposits
|
||||
self.current_epoch = epoch
|
||||
if self.consensus_messages[epoch - 1].committed:
|
||||
self.dynasty += 1
|
||||
self.total_deposits[self.dynasty] = self.total_deposits[self.dynasty - 1] + self.next_dynasty_wei_delta
|
||||
self.next_dynasty_wei_delta = self.second_next_dynasty_wei_delta
|
||||
self.second_next_dynasty_wei_delta = 0
|
||||
|
||||
# Send a deposit to join the validator set
|
||||
def deposit(validation_addr: address, withdrawal_addr: address):
|
||||
assert self.current_epoch == block.number / self.epoch_length
|
||||
start_epoch = (self.current_epoch - (self.current_epoch % 50)) + 100
|
||||
self.validators[self.nextValidatorIndex] = {
|
||||
deposit: msg.value,
|
||||
epoch_start: start_epoch,
|
||||
epoch_end: 1000000000000000000000000000000,
|
||||
dynasty_start: self.dynasty + 2,
|
||||
dynasty_end: 1000000000000000000000000000000,
|
||||
withdrawal_time: 1000000000000000000000000000000,
|
||||
addr: validation_addr,
|
||||
withdrawal_addr: withdrawal_addr,
|
||||
|
@ -72,14 +117,12 @@ def deposit(validation_addr: address, withdrawal_addr: address):
|
|||
max_committed: 0,
|
||||
}
|
||||
self.nextValidatorIndex += 1
|
||||
self.interest_rate = 0.000001
|
||||
self.block_time = 7
|
||||
self.epoch_length = 1024
|
||||
self.withdrawal_delay = 2500000
|
||||
self.insufficiency_slash_delay = self.withdrawal_delay / 2
|
||||
self.consensus_messages[start_epoch].total_deposits += msg.value
|
||||
self.second_next_dynasty_wei_delta += msg.value
|
||||
|
||||
# Exit the validator set, and start the withdrawal procedure
|
||||
def start_withdrawal(index: num, sig: bytes <= 96):
|
||||
assert self.current_epoch == block.number / self.epoch_length
|
||||
# Signature check
|
||||
assert len(sig) == 96
|
||||
assert ecrecover(sha3("withdraw"),
|
||||
|
@ -87,29 +130,31 @@ def start_withdrawal(index: num, sig: bytes <= 96):
|
|||
as_num256(extract32(sig, 32)),
|
||||
as_num256(extract32(sig, 64))) == self.validators[index].addr
|
||||
# Check that we haven't already withdrawn
|
||||
assert self.current_epoch == block.number / self.epoch_length
|
||||
end_epoch = (self.current_epoch - (self.current_epoch % 50)) + 100
|
||||
assert self.validators[index].epoch_end > end_epoch
|
||||
# Set the end epoch
|
||||
self.validators[index].epoch_end = end_epoch
|
||||
self.consensus_messages[end_epoch].total_deposits -= self.validators[index].deposit
|
||||
assert self.validators[index].dynasty_end >= self.dynasty + 2
|
||||
# Set the end dynasty
|
||||
self.validators[index].dynasty_end = self.dynasty + 2
|
||||
self.second_next_dynasty_wei_delta -= msg.value
|
||||
# Set the withdrawal date
|
||||
self.validators[index].withdrawal_time = block.timestamp + self.withdrawal_delay
|
||||
|
||||
# Withdraw deposited ether
|
||||
def withdraw(index: num):
|
||||
if block.timestamp >= self.validators[index].withdrawal_time:
|
||||
send(self.validators[index].withdrawal_addr, self.validators[index].deposit)
|
||||
self.validators[index] = {
|
||||
deposit: 0,
|
||||
epoch_start: 0,
|
||||
epoch_end: 0,
|
||||
withdrawal_time: 0,
|
||||
addr: None,
|
||||
withdrawal_addr: None,
|
||||
max_prepared: 0,
|
||||
max_committed: 0,
|
||||
}
|
||||
# Check that we can withdraw
|
||||
assert block.timestamp >= self.validators[index].withdrawal_time
|
||||
# Withdraw
|
||||
send(self.validators[index].withdrawal_addr, self.validators[index].deposit)
|
||||
self.validators[index] = {
|
||||
deposit: 0,
|
||||
dynasty_start: 0,
|
||||
dynasty_end: 0,
|
||||
withdrawal_time: 0,
|
||||
addr: None,
|
||||
withdrawal_addr: None,
|
||||
max_prepared: 0,
|
||||
max_committed: 0,
|
||||
}
|
||||
|
||||
# Process a prepare message
|
||||
def prepare(index: num, epoch: num, hash: bytes32, ancestry_hash: bytes32,
|
||||
epoch_source: num, source_ancestry_hash: bytes32, sig: bytes <= 96):
|
||||
# Signature check
|
||||
|
@ -122,28 +167,38 @@ def prepare(index: num, epoch: num, hash: bytes32, ancestry_hash: bytes32,
|
|||
# Check that we are in the right epoch
|
||||
assert self.current_epoch == block.number / self.epoch_length
|
||||
assert self.current_epoch == epoch
|
||||
assert self.validators[index].epoch_start <= epoch
|
||||
assert epoch < self.validators[index].epoch_end
|
||||
# Check that this validator was active in either the previous dynasty or the current one
|
||||
ds = self.validators[index].dynasty_start
|
||||
de = self.validators[index].dynasty_end
|
||||
dc = self.dynasty
|
||||
in_current_dynasty = (ds <= dc) and (dc < de)
|
||||
in_prev_dynasty = (ds <= (dc - 1)) and ((dc - 1) < de)
|
||||
assert in_current_dynasty or in_prev_dynasty
|
||||
# Check that we have not yet prepared for this epoch
|
||||
assert self.validators[index].max_prepared == epoch - 1
|
||||
# Pay the reward if the blockhash is correct
|
||||
if True: #~blockhash(epoch * self.epoch_length) == hash:
|
||||
reward = floor(self.validators[index].deposit * self.interest_rate * self.block_time)
|
||||
self.validators[index].deposit += reward
|
||||
self.consensus_messages[self.current_epoch].total_deposits += reward
|
||||
self.total_deposits[self.dynasty] += reward
|
||||
# Can't prepare for this epoch again
|
||||
self.validators[index].max_prepared = epoch
|
||||
# Record that this prepare took place
|
||||
new_ancestry_hash = sha3(concat(hash, ancestry_hash))
|
||||
self.consensus_messages[epoch].prepares[sighash] += self.validators[index].deposit
|
||||
if in_current_dynasty:
|
||||
self.consensus_messages[epoch].prepares[sighash] += self.validators[index].deposit
|
||||
if in_prev_dynasty:
|
||||
self.consensus_messages[epoch].prev_dyn_prepares[sighash] += self.validators[index].deposit
|
||||
# If enough prepares with the same epoch_source and hash are made,
|
||||
# then the hash value is justified for commitment
|
||||
if self.consensus_messages[epoch].prepares[sighash] >= self.consensus_messages[epoch].total_deposits * 2 / 3 and \
|
||||
if (self.consensus_messages[epoch].prepares[sighash] >= self.total_deposits[self.dynasty] * 2 / 3 and \
|
||||
self.consensus_messages[epoch].prev_dyn_prepares[sighash] >= self.total_deposits[self.dynasty] * 2 / 3) and \
|
||||
not self.consensus_messages[epoch].justified[new_ancestry_hash]:
|
||||
self.consensus_messages[epoch].justified[new_ancestry_hash] = True
|
||||
# Add a parent-child relation between ancestry hashes to the ancestry table
|
||||
self.ancestry[ancestry_hash][new_ancestry_hash] = 1
|
||||
|
||||
# Process a commit message
|
||||
def commit(index: num, epoch: num, hash: bytes32, sig: bytes <= 96):
|
||||
# Signature check
|
||||
sighash = sha3(concat("commit", as_bytes32(epoch), hash))
|
||||
|
@ -155,17 +210,31 @@ def commit(index: num, epoch: num, hash: bytes32, sig: bytes <= 96):
|
|||
# Check that we are in the right epoch
|
||||
assert self.current_epoch == block.number / self.epoch_length
|
||||
assert self.current_epoch == epoch
|
||||
assert self.validators[index].epoch_start <= epoch
|
||||
assert epoch < self.validators[index].epoch_end
|
||||
# Check that this validator was active in either the previous dynasty or the current one
|
||||
ds = self.validators[index].dynasty_start
|
||||
de = self.validators[index].dynasty_end
|
||||
dc = self.dynasty
|
||||
in_current_dynasty = (ds <= dc) and (dc < de)
|
||||
in_prev_dynasty = (ds <= (dc - 1)) and ((dc - 1) < de)
|
||||
assert in_current_dynasty or in_prev_dynasty
|
||||
# Check that we have not yet committed for this epoch
|
||||
assert self.validators[index].max_committed == epoch - 1
|
||||
# Pay the reward if the blockhash is correct
|
||||
if True: #~blockhash(epoch * self.epoch_length) == hash:
|
||||
reward = floor(self.validators[index].deposit * self.interest_rate * self.block_time)
|
||||
self.validators[index].deposit += reward
|
||||
self.consensus_messages[self.current_epoch].total_deposits += reward
|
||||
self.total_deposits[self.dynasty] += reward
|
||||
# Can't commit for this epoch again
|
||||
self.validators[index].max_committed = epoch
|
||||
# Record that this commit took place
|
||||
if in_current_dynasty:
|
||||
self.consensus_messages[epoch].commits[hash] += self.validators[index].deposit
|
||||
if in_prev_dynasty:
|
||||
self.consensus_messages[epoch].prev_dyn_commits[hash] += self.validators[index].deposit
|
||||
# Record if sufficient commits have been made for the block to be finalized
|
||||
if self.consensus_messages[epoch].commits[hash] >= self.total_deposits[self.dynasty] * 2 / 3 and \
|
||||
not self.consensus_messages[epoch].committed:
|
||||
self.consensus_messages[epoch].committed = True
|
||||
|
||||
# Cannot make two versions of the same message
|
||||
def intra_epoch_equivocation_slash(index: num, epoch: num, msgtype: bytes <= 16,
|
||||
|
@ -186,11 +255,12 @@ def intra_epoch_equivocation_slash(index: num, epoch: num, msgtype: bytes <= 16,
|
|||
# Delete the offending validator, and give a 4% "finder's fee"
|
||||
validator_deposit = self.validators[index].deposit
|
||||
send(msg.sender, validator_deposit / 25)
|
||||
self.consensus_messages[self.current_epoch].total_deposits -= (validator_deposit - validator_deposit / 25)
|
||||
self.total_destroyed += validator_deposit * 24 / 25
|
||||
self.total_deposits[self.dynasty] -= (validator_deposit - validator_deposit / 25)
|
||||
self.validators[index] = {
|
||||
deposit: 0,
|
||||
epoch_start: 0,
|
||||
epoch_end: 0,
|
||||
dynasty_start: 0,
|
||||
dynasty_end: 0,
|
||||
withdrawal_time: 0,
|
||||
addr: None,
|
||||
withdrawal_addr: None,
|
||||
|
@ -222,11 +292,12 @@ def prepare_commit_inconsistency_slash(index: num, prepare_epoch: num, prepare_h
|
|||
# Delete the offending validator, and give a 4% "finder's fee"
|
||||
validator_deposit = self.validators[index].deposit
|
||||
send(msg.sender, validator_deposit / 25)
|
||||
self.consensus_messages[self.current_epoch].total_deposits -= validator_deposit
|
||||
self.total_destroyed += validator_deposit * 24 / 25
|
||||
self.total_deposits[self.dynasty] -= validator_deposit
|
||||
self.validators[index] = {
|
||||
deposit: 0,
|
||||
epoch_start: 0,
|
||||
epoch_end: 0,
|
||||
dynasty_start: 0,
|
||||
dynasty_end: 0,
|
||||
withdrawal_time: 0,
|
||||
addr: None,
|
||||
withdrawal_addr: None,
|
||||
|
@ -248,11 +319,12 @@ def commit_non_justification_slash(index: num, epoch: num, hash: bytes32, sig: b
|
|||
# Delete the offending validator, and give a 4% "finder's fee"
|
||||
validator_deposit = self.validators[index].deposit
|
||||
send(msg.sender, validator_deposit / 25)
|
||||
self.consensus_messages[self.current_epoch].total_deposits -= validator_deposit
|
||||
self.total_destroyed += validator_deposit * 24 / 25
|
||||
self.total_deposits[self.dynasty] -= validator_deposit
|
||||
self.validators[index] = {
|
||||
deposit: 0,
|
||||
epoch_start: 0,
|
||||
epoch_end: 0,
|
||||
dynasty_start: 0,
|
||||
dynasty_end: 0,
|
||||
withdrawal_time: 0,
|
||||
addr: None,
|
||||
withdrawal_addr: None,
|
||||
|
@ -282,14 +354,19 @@ def prepare_non_justification_slash(index: num, epoch: num, hash: bytes32, epoch
|
|||
# Delete the offending validator, and give a 4% "finder's fee"
|
||||
validator_deposit = self.validators[index].deposit
|
||||
send(msg.sender, validator_deposit / 25)
|
||||
self.consensus_messages[self.current_epoch].total_deposits -= validator_deposit
|
||||
self.total_destroyed += validator_deposit * 24 / 25
|
||||
self.total_deposits[self.dynasty] -= validator_deposit
|
||||
self.validators[index] = {
|
||||
deposit: 0,
|
||||
epoch_start: 0,
|
||||
epoch_end: 0,
|
||||
dynasty_start: 0,
|
||||
dynasty_end: 0,
|
||||
withdrawal_time: 0,
|
||||
addr: None,
|
||||
withdrawal_addr: None,
|
||||
max_prepared: 0,
|
||||
max_committed: 0,
|
||||
}
|
||||
|
||||
def owner_withdraw():
|
||||
send(self.owner, self.total_destroyed)
|
||||
self.total_destroyed = 0
|
||||
|
|
|
@ -6,7 +6,7 @@ import random
|
|||
NODE_COUNT = 10
|
||||
BLOCK_TIME = 100
|
||||
EPOCH_LENGTH = 5
|
||||
AVG_LATENCY = 250
|
||||
AVG_LATENCY = 255
|
||||
|
||||
def poisson_latency(latency):
|
||||
return lambda: 1 + int(random.gammavariate(1, 1) * latency)
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import random
|
||||
import datetime
|
||||
|
||||
hashpower = 10 * 10**12.
|
||||
diffs = [hashpower * 14.2]
|
||||
times = [1487670523]
|
||||
hashpower = 11 * 10**12.
|
||||
diffs = [hashpower * 14.15]
|
||||
times = [1488553221]
|
||||
|
||||
|
||||
for i in range(3230000, 6010000):
|
||||
for i in range(3284988, 6010000):
|
||||
blocktime = random.expovariate(hashpower / diffs[-1])
|
||||
adjfac = max(1 - int(blocktime / 10), -99) / 2048.
|
||||
newdiff = diffs[-1] * (1 + adjfac)
|
||||
|
|
Loading…
Reference in New Issue