From 294fe110ad8bce52b92bd1b57b55ad9c7ddfd3c7 Mon Sep 17 00:00:00 2001 From: vub Date: Wed, 22 Mar 2017 06:58:50 -0400 Subject: [PATCH] Made simple casper kinda work in some places --- casper4/fixed_address_creator.py | 18 ++++ casper4/rlp_decoder.se | 64 ------------- casper4/{sighash.se => sighash.se.py} | 0 casper4/simple_casper.v.py | 129 ++++++++++++++------------ iceage.py | 6 +- 5 files changed, 89 insertions(+), 128 deletions(-) create mode 100644 casper4/fixed_address_creator.py delete mode 100644 casper4/rlp_decoder.se rename casper4/{sighash.se => sighash.se.py} (100%) diff --git a/casper4/fixed_address_creator.py b/casper4/fixed_address_creator.py new file mode 100644 index 0000000..ee282d1 --- /dev/null +++ b/casper4/fixed_address_creator.py @@ -0,0 +1,18 @@ +from ethereum import transactions, utils +import serpent +import rlp + +sighash = serpent.compile('sighash.se.py') + +# Create transaction +t = transactions.Transaction(0, 30 * 10**9, 2999999, '', 0, sighash) +t.startgas = t.intrinsic_gas_used + 50000 + 200 * len(sighash) +t.v = 27 +t.r = 45 +t.s = 79 +print("Sighash") +print('Send %d wei to %s' % (t.startgas * t.gasprice, + '0x'+utils.encode_hex(t.sender))) + +print('Contract address: 0x'+utils.encode_hex(utils.mk_contract_address(t.sender, 0))) +print('Code: 0x'+utils.encode_hex(rlp.encode(t))) diff --git a/casper4/rlp_decoder.se b/casper4/rlp_decoder.se deleted file mode 100644 index 2f2c65d..0000000 --- a/casper4/rlp_decoder.se +++ /dev/null @@ -1,64 +0,0 @@ -macro calldatachar($x): - div(calldataload($x), 2**248) - -macro calldatabytes_as_int($x, $b): - div(calldataload($x), 256**(32-$b)) - -def any(): - positions = array(32) - positionIndex = 0 - data = string(1024) - dataPos = 0 - # Can only parse lists - c = calldatachar(0) - if c < 192: - ~invalid() - if c < 248: - if ~calldatasize() != 1 + (c - 192): - ~invalid() - i = 1 - else: - L = calldatabytes_as_int(i + 1, c - 247) - if ~calldatasize() != 1 + (c - 247) + L: - ~invalid() - i = 1 + (c - 247) - while i < ~calldatasize(): - c = calldatachar(i) - positions[positionIndex] = dataPos - positionIndex += 1 - if c < 128: - calldatacopy(data + dataPos, i, 1) - i += 1 - dataPos += 1 - elif c < 184: - calldatacopy(data + dataPos, i + 1, c - 128) - # Output could have been in single-byte format - if c == 129: - if calldatachar(i + 1) < 128: - ~invalid() - i += c - 128 + 1 - dataPos += (c - 128) - elif c < 192: - L = calldatabytes_as_int(i + 1, c - 183) - # Forbid leading zero byte - if calldatachar(i + 1) == 0: - ~invalid() - # Forbid too short values - if L < 56: - ~invalid() - calldatacopy(data + dataPos, i + 1 + c - 183, L) - i += (c - 183) + 1 + L - dataPos += L - else: - # Not handling nested arrays - ~invalid() - if dataPos > 1024 or positionIndex > 32: - ~invalid() - positions[positionIndex] = dataPos - output = string(2048) - i = 0 - while i <= positionIndex: - output[i] = positions[i] + positionIndex * 32 + 32 - i += 1 - mcopy(output + positionIndex * 32 + 32, data, dataPos) - ~return(output, positionIndex * 32 + dataPos + 32) diff --git a/casper4/sighash.se b/casper4/sighash.se.py similarity index 100% rename from casper4/sighash.se rename to casper4/sighash.se.py diff --git a/casper4/simple_casper.v.py b/casper4/simple_casper.v.py index a8d3c7f..5153c99 100644 --- a/casper4/simple_casper.v.py +++ b/casper4/simple_casper.v.py @@ -1,5 +1,5 @@ # Information about validators -validators: { +validators: public({ # Amount of wei the validator holds deposit: wei_value, # The dynasty the validator is joining @@ -16,20 +16,20 @@ validators: { max_prepared: num, # The max epoch at which the validator committed max_committed: num -}[num] +}[num]) # The current dynasty (validator set changes between dynasties) -dynasty: num +dynasty: public(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] +total_deposits: public(wei_value[num]) # Information for use in processing cryptoeconomic commitments -consensus_messages: { +consensus_messages: public({ # 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 @@ -42,13 +42,13 @@ consensus_messages: { prev_dyn_commits: wei_value[bytes32], # Was the block committed? committed: bool -}[num] # index: epoch +}[num]) # index: epoch # ancestry[x][y] = k > 0: x is a kth generation ancestor of y ancestry: num[bytes32][bytes32] # Number of validators -nextValidatorIndex: num +nextValidatorIndex: public(num) # Constant that guides the size of validator rewards interest_rate: decimal(1 / sec) @@ -66,7 +66,7 @@ withdrawal_delay: timedelta insufficiency_slash_delay: timedelta # Current epoch -current_epoch: num +current_epoch: public(num) # Can withdraw destroyed deposits owner: address @@ -74,8 +74,8 @@ owner: address # Total deposits destroyed total_destroyed: wei_value -# RLP decoder address -rlp_decoder: address +# Sighash calculator library address +sighasher: address def __init__(): # Set Casper parameters @@ -88,7 +88,7 @@ def __init__(): self.owner = 0x1db3439a222c519ab44bb1144fc28167b4fa6ee6 # Add an initial validator self.validators[0] = { - deposit: as_wei(3, finney), + deposit: as_wei_value(3, finney), dynasty_start: 0, dynasty_end: 1000000000000000000000000000000, withdrawal_time: 1000000000000000000000000000000, @@ -97,21 +97,22 @@ def __init__(): max_prepared: 0, max_committed: 0 } + self.nextValidatorIndex = 1 # Initialize the epoch counter self.current_epoch = block.number / self.epoch_length - # Set the RLP decoder address - self.rlp_decoder = 0x38920146f10f3956fc09970beededcb2d9638711 + # Set the sighash calculator address + self.sighasher = 0x38920146f10f3956fc09970beededcb2d9638712 # 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.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 + assert epoch <= computed_current_epoch and epoch == self.current_epoch + 1 + 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): @@ -145,12 +146,12 @@ def start_withdrawal(index: num, sig: bytes <= 96): 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 + #self.validators[index].withdrawal_time = block.timestamp + self.withdrawal_delay # Withdraw deposited ether def withdraw(index: num): # Check that we can withdraw - assert block.timestamp >= self.validators[index].withdrawal_time + #assert block.timestamp >= self.validators[index].withdrawal_time # Withdraw send(self.validators[index].withdrawal_addr, self.validators[index].deposit) self.validators[index] = { @@ -165,96 +166,102 @@ def withdraw(index: num): } # 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): +def prepare(validator_index: num, prepare_msg: bytes <= 1024): # Get hash for signature, and implicitly assert that it is an RLP list # consisting solely of RLP elements - sighash = extract32(raw_call(self.sighasher, self.prepare_msg, gas=50000, outsize=32), 0) - values = raw_call(self.rlp_decoder, self.prepare_msg, gas=50000, outsize=2048) + sighash = extract32(raw_call(self.sighasher, prepare_msg, gas=200000, outsize=32), 0) # Extract parameters - epoch = extract32(values, extract32(value, 0, type=num128), type=num128) - hash = extract32(values, extract32(value, 32, type=num128), type=bytes32) - ancestry_hash = extract32(values, extract32(value, 64, type=num128), type=bytes32) - source_epoch = extract32(values, extract32(value, 96, type=num128), type=num128) - source_ancestry_hash = extract32(values, extract32(value, 128, type=num128), type=bytes32) - sig = slice(values, start=extract32(value, 160, type=num128), end=extract32(value, 192, type=num128)) - # Assert that there are only 6 elements - assert as_num128(extract32(value, 0)) == 224 + values = RLPList(prepare_msg, [num, bytes32, bytes32, num, bytes32, bytes]) + epoch = values[0] + hash = values[1] + ancestry_hash = values[2] + source_epoch = values[3] + source_ancestry_hash = values[4] + sig = values[5] # For now, the sig is a simple ECDSA sig assert len(sig) == 96 assert ecrecover(sighash, - as_num256(extract32(sig, 0)), - as_num256(extract32(sig, 32)), - as_num256(extract32(sig, 64))) == self.validators[index].addr + extract32(sig, 0, type=num256), + extract32(sig, 32, type=num256), + extract32(sig, 64, type=num256)) == self.validators[validator_index].addr # Check that we are in the right epoch assert self.current_epoch == block.number / self.epoch_length assert self.current_epoch == epoch # 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 + ds = self.validators[validator_index].dynasty_start + de = self.validators[validator_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 + assert self.validators[validator_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 + reward = floor(self.validators[validator_index].deposit * self.interest_rate * self.block_time) + self.validators[validator_index].deposit += reward self.total_deposits[self.dynasty] += reward # Can't prepare for this epoch again - self.validators[index].max_prepared = epoch + self.validators[validator_index].max_prepared = epoch # Record that this prepare took place new_ancestry_hash = sha3(concat(hash, ancestry_hash)) if in_current_dynasty: - self.consensus_messages[epoch].prepares[sighash] += self.validators[index].deposit + self.consensus_messages[epoch].prepares[sighash] += self.validators[validator_index].deposit if in_prev_dynasty: - self.consensus_messages[epoch].prev_dyn_prepares[sighash] += self.validators[index].deposit + self.consensus_messages[epoch].prev_dyn_prepares[sighash] += self.validators[validator_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.total_deposits[self.dynasty] * 2 / 3 and \ - self.consensus_messages[epoch].prev_dyn_prepares[sighash] >= self.total_deposits[self.dynasty] * 2 / 3) and \ + self.consensus_messages[epoch].prev_dyn_prepares[sighash] >= self.total_deposits[self.dynasty - 1] * 2 / 3) and \ not self.consensus_messages[epoch].justified[new_ancestry_hash]: self.consensus_messages[epoch].justified[new_ancestry_hash] = True + self.consensus_messages[epoch].justified[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)) +def commit(validator_index: num, commit_msg: bytes <= 1024): + sighash = extract32(raw_call(self.sighasher, commit_msg, gas=200000, outsize=32), 0) + # Extract parameters + values = RLPList(commit_msg, [num, bytes32, bytes]) + epoch = values[0] + hash = values[1] + sig = values[2] + # For now, the sig is a simple ECDSA sig assert len(sig) == 96 assert ecrecover(sighash, - as_num256(extract32(sig, 0)), - as_num256(extract32(sig, 32)), - as_num256(extract32(sig, 64))) == self.validators[index].addr + extract32(sig, 0, type=num256), + extract32(sig, 32, type=num256), + extract32(sig, 64, type=num256)) == self.validators[validator_index].addr # Check that we are in the right epoch assert self.current_epoch == block.number / self.epoch_length assert self.current_epoch == epoch + # Check that the commit is justified + assert self.consensus_messages[epoch].justified[hash] # 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 + ds = self.validators[validator_index].dynasty_start + de = self.validators[validator_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 + assert self.validators[validator_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 + reward = floor(self.validators[validator_index].deposit * self.interest_rate * self.block_time) + self.validators[validator_index].deposit += reward self.total_deposits[self.dynasty] += reward # Can't commit for this epoch again - self.validators[index].max_committed = epoch + self.validators[validator_index].max_committed = epoch # Record that this commit took place if in_current_dynasty: - self.consensus_messages[epoch].commits[hash] += self.validators[index].deposit + self.consensus_messages[epoch].commits[hash] += self.validators[validator_index].deposit if in_prev_dynasty: - self.consensus_messages[epoch].prev_dyn_commits[hash] += self.validators[index].deposit + self.consensus_messages[epoch].prev_dyn_commits[hash] += self.validators[validator_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 \ + if (self.consensus_messages[epoch].commits[hash] >= self.total_deposits[self.dynasty] * 2 / 3 and \ + self.consensus_messages[epoch].prev_dyn_commits[hash] >= self.total_deposits[self.dynasty - 1] * 2 / 3) and \ not self.consensus_messages[epoch].committed: self.consensus_messages[epoch].committed = True diff --git a/iceage.py b/iceage.py index 8fb7fad..242ef32 100644 --- a/iceage.py +++ b/iceage.py @@ -1,12 +1,12 @@ import random import datetime -hashpower = 11 * 10**12. +hashpower = 14 * 10**12. diffs = [hashpower * 14.15] -times = [1488553221] +times = [1489762567] -for i in range(3284988, 6010000): +for i in range(3368795, 6010000): blocktime = random.expovariate(hashpower / diffs[-1]) adjfac = max(1 - int(blocktime / 10), -99) / 2048. newdiff = diffs[-1] * (1 + adjfac)