Added validation code mechanism
This commit is contained in:
parent
470e7671fd
commit
87520a39b1
|
@ -92,6 +92,8 @@ total_destroyed: wei_value
|
||||||
# Sighash calculator library address
|
# Sighash calculator library address
|
||||||
sighasher: address
|
sighasher: address
|
||||||
|
|
||||||
|
# Purity checker library address
|
||||||
|
purity_checker: address
|
||||||
|
|
||||||
# Reward for preparing or committing, as fraction of deposit size
|
# Reward for preparing or committing, as fraction of deposit size
|
||||||
reward_factor: public(decimal)
|
reward_factor: public(decimal)
|
||||||
|
@ -136,6 +138,8 @@ def initiate():
|
||||||
self.current_epoch = block.number / self.epoch_length
|
self.current_epoch = block.number / self.epoch_length
|
||||||
# Set the sighash calculator address
|
# Set the sighash calculator address
|
||||||
self.sighasher = 0x476c2cA9a7f3B16FeCa86512276271FAf63B6a24
|
self.sighasher = 0x476c2cA9a7f3B16FeCa86512276271FAf63B6a24
|
||||||
|
# Set the purity checker address
|
||||||
|
self.purity_checker = 0xD7a3BD6C9eA32efF147d067f907AE6b22d436F91
|
||||||
# Set an initial root of the epoch hash chain
|
# Set an initial root of the epoch hash chain
|
||||||
self.consensus_messages[0].ancestry_hash_justified[0x0000000000000000000000000000000000000000000000000000000000000000] = True
|
self.consensus_messages[0].ancestry_hash_justified[0x0000000000000000000000000000000000000000000000000000000000000000] = True
|
||||||
# self.consensus_messages[0].committed = True
|
# self.consensus_messages[0].committed = True
|
||||||
|
@ -182,6 +186,7 @@ def initialize_epoch(epoch: num):
|
||||||
# Send a deposit to join the validator set
|
# Send a deposit to join the validator set
|
||||||
def deposit(validation_addr: address, withdrawal_addr: address):
|
def deposit(validation_addr: address, withdrawal_addr: address):
|
||||||
assert self.current_epoch == block.number / self.epoch_length
|
assert self.current_epoch == block.number / self.epoch_length
|
||||||
|
assert extract32(raw_call(self.purity_checker, concat('\xa1\x90>\xab', as_bytes32(validation_addr)), gas=500000, outsize=32), 0) != as_bytes32(0)
|
||||||
self.validators[self.nextValidatorIndex] = {
|
self.validators[self.nextValidatorIndex] = {
|
||||||
deposit: msg.value,
|
deposit: msg.value,
|
||||||
dynasty_start: self.dynasty + 2,
|
dynasty_start: self.dynasty + 2,
|
||||||
|
@ -210,11 +215,7 @@ def flick_status(validator_index: num, logout_msg: bytes <= 1024):
|
||||||
sig = values[2]
|
sig = values[2]
|
||||||
assert self.current_epoch == epoch
|
assert self.current_epoch == epoch
|
||||||
# Signature check
|
# Signature check
|
||||||
assert len(sig) == 96
|
assert extract32(raw_call(self.validators[validator_index].addr, concat(sighash, sig), gas=500000, outsize=32), 0) == as_bytes32(1)
|
||||||
assert ecrecover(sighash,
|
|
||||||
as_num256(extract32(sig, 0)),
|
|
||||||
as_num256(extract32(sig, 32)),
|
|
||||||
as_num256(extract32(sig, 64))) == self.validators[validator_index].addr
|
|
||||||
# Logging in
|
# Logging in
|
||||||
if login_flag:
|
if login_flag:
|
||||||
# Check that we are logged out
|
# Check that we are logged out
|
||||||
|
@ -323,11 +324,7 @@ def prepare(validator_index: num, prepare_msg: bytes <= 1024):
|
||||||
sig = values[5]
|
sig = values[5]
|
||||||
# For now, the sig is a simple ECDSA sig
|
# For now, the sig is a simple ECDSA sig
|
||||||
# Check the signature
|
# Check the signature
|
||||||
assert len(sig) == 96
|
assert extract32(raw_call(self.validators[validator_index].addr, concat(sighash, sig), gas=500000, outsize=32), 0) == as_bytes32(1)
|
||||||
assert ecrecover(sighash,
|
|
||||||
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 an epoch after we started validating
|
# Check that we are in an epoch after we started validating
|
||||||
assert self.current_epoch >= self.dynasty_start_epoch[self.validators[validator_index].dynasty_start]
|
assert self.current_epoch >= self.dynasty_start_epoch[self.validators[validator_index].dynasty_start]
|
||||||
# Check that this prepare has not yet been made
|
# Check that this prepare has not yet been made
|
||||||
|
@ -386,11 +383,7 @@ def commit(validator_index: num, commit_msg: bytes <= 1024):
|
||||||
prev_commit_epoch = values[2]
|
prev_commit_epoch = values[2]
|
||||||
sig = values[3]
|
sig = values[3]
|
||||||
# Check the signature
|
# Check the signature
|
||||||
assert len(sig) == 96
|
assert extract32(raw_call(self.validators[validator_index].addr, concat(sighash, sig), gas=500000, outsize=32), 0) == as_bytes32(1)
|
||||||
assert ecrecover(sighash,
|
|
||||||
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
|
# Check that we are in the right epoch
|
||||||
assert self.current_epoch == block.number / self.epoch_length
|
assert self.current_epoch == block.number / self.epoch_length
|
||||||
assert self.current_epoch == epoch
|
assert self.current_epoch == epoch
|
||||||
|
@ -441,14 +434,8 @@ def double_prepare_slash(validator_index: num, prepare1: bytes <= 1000, prepare2
|
||||||
epoch2 = values2[0]
|
epoch2 = values2[0]
|
||||||
sig2 = values2[5]
|
sig2 = values2[5]
|
||||||
# Check the signatures
|
# Check the signatures
|
||||||
assert ecrecover(sighash1,
|
assert extract32(raw_call(self.validators[validator_index].addr, concat(sighash1, sig1), gas=500000, outsize=32), 0) == as_bytes32(1)
|
||||||
as_num256(extract32(sig1, 0)),
|
assert extract32(raw_call(self.validators[validator_index].addr, concat(sighash2, sig2), gas=500000, outsize=32), 0) == as_bytes32(1)
|
||||||
as_num256(extract32(sig1, 32)),
|
|
||||||
as_num256(extract32(sig1, 64))) == self.validators[validator_index].addr
|
|
||||||
assert ecrecover(sighash2,
|
|
||||||
as_num256(extract32(sig2, 0)),
|
|
||||||
as_num256(extract32(sig2, 32)),
|
|
||||||
as_num256(extract32(sig2, 64))) == self.validators[validator_index].addr
|
|
||||||
# Check that they're from the same epoch
|
# Check that they're from the same epoch
|
||||||
assert epoch1 == epoch2
|
assert epoch1 == epoch2
|
||||||
# Check that they're not the same message
|
# Check that they're not the same message
|
||||||
|
@ -474,14 +461,8 @@ def prepare_commit_inconsistency_slash(validator_index: num, prepare_msg: bytes
|
||||||
commit_epoch = values2[0]
|
commit_epoch = values2[0]
|
||||||
sig2 = values2[3]
|
sig2 = values2[3]
|
||||||
# Check the signatures
|
# Check the signatures
|
||||||
assert ecrecover(sighash1,
|
assert extract32(raw_call(self.validators[validator_index].addr, concat(sighash1, sig1), gas=500000, outsize=32), 0) == as_bytes32(1)
|
||||||
as_num256(extract32(sig1, 0)),
|
assert extract32(raw_call(self.validators[validator_index].addr, concat(sighash2, sig2), gas=500000, outsize=32), 0) == as_bytes32(1)
|
||||||
as_num256(extract32(sig1, 32)),
|
|
||||||
as_num256(extract32(sig1, 64))) == self.validators[validator_index].addr
|
|
||||||
assert ecrecover(sighash2,
|
|
||||||
as_num256(extract32(sig2, 0)),
|
|
||||||
as_num256(extract32(sig2, 32)),
|
|
||||||
as_num256(extract32(sig2, 64))) == self.validators[validator_index].addr
|
|
||||||
# Check that they're not the same message
|
# Check that they're not the same message
|
||||||
assert sighash1 != sighash2
|
assert sighash1 != sighash2
|
||||||
# Check that the prepare refers to something older than the commit
|
# Check that the prepare refers to something older than the commit
|
||||||
|
@ -504,10 +485,7 @@ def commit_non_justification_slash(validator_index: num, commit_msg: bytes <= 10
|
||||||
sig = values[3]
|
sig = values[3]
|
||||||
# Check the signature
|
# Check the signature
|
||||||
assert len(sig) == 96
|
assert len(sig) == 96
|
||||||
assert ecrecover(sighash,
|
assert extract32(raw_call(self.validators[validator_index].addr, concat(sighash, sig), gas=500000, outsize=32), 0) == as_bytes32(1)
|
||||||
extract32(sig, 0, type=num256),
|
|
||||||
extract32(sig, 32, type=num256),
|
|
||||||
extract32(sig, 64, type=num256)) == self.validators[validator_index].addr
|
|
||||||
# Check that the commit is old enough
|
# Check that the commit is old enough
|
||||||
assert self.current_epoch == block.number / self.epoch_length
|
assert self.current_epoch == block.number / self.epoch_length
|
||||||
assert (self.current_epoch - epoch) * self.epoch_length * self.block_time > self.insufficiency_slash_delay
|
assert (self.current_epoch - epoch) * self.epoch_length * self.block_time > self.insufficiency_slash_delay
|
||||||
|
@ -543,10 +521,7 @@ def prepare_non_justification_slash(validator_index: num, prepare_msg: bytes <=
|
||||||
source_ancestry_hash = values[4]
|
source_ancestry_hash = values[4]
|
||||||
sig = values[5]
|
sig = values[5]
|
||||||
# Check the signature
|
# Check the signature
|
||||||
assert ecrecover(sighash,
|
assert extract32(raw_call(self.validators[validator_index].addr, concat(sighash, sig), gas=500000, outsize=32), 0) == as_bytes32(1)
|
||||||
extract32(sig, 0, type=num256),
|
|
||||||
extract32(sig, 32, type=num256),
|
|
||||||
extract32(sig, 64, type=num256)) == self.validators[validator_index].addr
|
|
||||||
# Check that the view change is old enough
|
# Check that the view change is old enough
|
||||||
assert self.current_epoch == block.number / self.epoch_length
|
assert self.current_epoch == block.number / self.epoch_length
|
||||||
assert (self.current_epoch - epoch) * self.block_time * self.epoch_length > self.insufficiency_slash_delay
|
assert (self.current_epoch - epoch) * self.block_time * self.epoch_length > self.insufficiency_slash_delay
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from ethereum import tester as t
|
from ethereum import tester as t
|
||||||
from ethereum import utils, state_transition, transactions, abi
|
from ethereum import utils, state_transition, transactions, abi
|
||||||
from viper import compiler
|
from viper import compiler
|
||||||
|
import serpent
|
||||||
from ethereum.slogging import LogRecorder, configure_logging, set_level
|
from ethereum.slogging import LogRecorder, configure_logging, set_level
|
||||||
config_string = ':info,eth.vm.log:trace,eth.vm.op:trace,eth.vm.stack:trace,eth.vm.exit:trace,eth.pb.msg:trace,eth.pb.tx:debug'
|
config_string = ':info,eth.vm.log:trace,eth.vm.op:trace,eth.vm.stack:trace,eth.vm.exit:trace,eth.pb.msg:trace,eth.pb.tx:debug'
|
||||||
#configure_logging(config_string=config_string)
|
#configure_logging(config_string=config_string)
|
||||||
|
@ -19,6 +20,15 @@ def inject_tx(txhex):
|
||||||
assert s.state.get_code(contract_address)
|
assert s.state.get_code(contract_address)
|
||||||
return contract_address
|
return contract_address
|
||||||
|
|
||||||
|
code_template = """
|
||||||
|
~calldatacopy(0, 0, 128)
|
||||||
|
~call(3000, 1, 0, 0, 128, 0, 32)
|
||||||
|
return(~mload(0) == %s)
|
||||||
|
"""
|
||||||
|
|
||||||
|
def mk_validation_code(address):
|
||||||
|
return serpent.compile(code_template % (utils.checksum_encode(address)))
|
||||||
|
|
||||||
# Install RLP decoder library
|
# Install RLP decoder library
|
||||||
rlp_decoder_address = inject_tx( '0xf90237808506fc23ac00830330888080b902246102128061000e60003961022056600060007f010000000000000000000000000000000000000000000000000000000000000060003504600060c082121515585760f882121561004d5760bf820336141558576001905061006e565b600181013560f783036020035260005160f6830301361415585760f6820390505b5b368112156101c2577f010000000000000000000000000000000000000000000000000000000000000081350483602086026040015260018501945060808112156100d55760018461044001526001828561046001376001820191506021840193506101bc565b60b881121561014357608081038461044001526080810360018301856104600137608181141561012e5760807f010000000000000000000000000000000000000000000000000000000000000060018401350412151558575b607f81038201915060608103840193506101bb565b60c08112156101b857600182013560b782036020035260005160388112157f010000000000000000000000000000000000000000000000000000000000000060018501350402155857808561044001528060b6838501038661046001378060b6830301830192506020810185019450506101ba565bfe5b5b5b5061006f565b601f841315155857602060208502016020810391505b6000821215156101fc578082604001510182826104400301526020820391506101d8565b808401610420528381018161044003f350505050505b6000f31b2d4f')
|
rlp_decoder_address = inject_tx( '0xf90237808506fc23ac00830330888080b902246102128061000e60003961022056600060007f010000000000000000000000000000000000000000000000000000000000000060003504600060c082121515585760f882121561004d5760bf820336141558576001905061006e565b600181013560f783036020035260005160f6830301361415585760f6820390505b5b368112156101c2577f010000000000000000000000000000000000000000000000000000000000000081350483602086026040015260018501945060808112156100d55760018461044001526001828561046001376001820191506021840193506101bc565b60b881121561014357608081038461044001526080810360018301856104600137608181141561012e5760807f010000000000000000000000000000000000000000000000000000000000000060018401350412151558575b607f81038201915060608103840193506101bb565b60c08112156101b857600182013560b782036020035260005160388112157f010000000000000000000000000000000000000000000000000000000000000060018501350402155857808561044001528060b6838501038661046001378060b6830301830192506020810185019450506101ba565bfe5b5b5b5061006f565b601f841315155857602060208502016020810391505b6000821215156101fc578082604001510182826104400301526020820391506101d8565b808401610420528381018161044003f350505050505b6000f31b2d4f')
|
||||||
|
|
||||||
|
@ -37,10 +47,14 @@ ct = abi.ContractTranslator([{'name': 'check(address)', 'type': 'function', 'con
|
||||||
assert utils.big_endian_to_int(s.send(t.k0, purity_checker_address, 0, ct.encode('submit', [rlp_decoder_address]))) == 1
|
assert utils.big_endian_to_int(s.send(t.k0, purity_checker_address, 0, ct.encode('submit', [rlp_decoder_address]))) == 1
|
||||||
assert utils.big_endian_to_int(s.send(t.k0, purity_checker_address, 0, ct.encode('submit', [sighasher_address]))) == 1
|
assert utils.big_endian_to_int(s.send(t.k0, purity_checker_address, 0, ct.encode('submit', [sighasher_address]))) == 1
|
||||||
|
|
||||||
|
k1_valcode_addr = s.send(t.k0, "", 0, mk_validation_code(t.a0))
|
||||||
|
assert utils.big_endian_to_int(s.send(t.k0, purity_checker_address, 0, ct.encode('submit', [k1_valcode_addr]))) == 1
|
||||||
|
|
||||||
# Install Casper
|
# Install Casper
|
||||||
|
|
||||||
casper_code = open('simple_casper.v.py').read().replace('0x1Db3439a222C519ab44bb1144fC28167b4Fa6EE6', utils.checksum_encode(t.a0)) \
|
casper_code = open('simple_casper.v.py').read().replace('0x1Db3439a222C519ab44bb1144fC28167b4Fa6EE6', utils.checksum_encode(k1_valcode_addr)) \
|
||||||
.replace('0x476c2cA9a7f3B16FeCa86512276271FAf63B6a24', utils.checksum_encode(sighasher_address))
|
.replace('0x476c2cA9a7f3B16FeCa86512276271FAf63B6a24', utils.checksum_encode(sighasher_address)) \
|
||||||
|
.replace('0xD7a3BD6C9eA32efF147d067f907AE6b22d436F91', utils.checksum_encode(purity_checker_address))
|
||||||
|
|
||||||
print('Casper code length', len(compiler.compile(casper_code)))
|
print('Casper code length', len(compiler.compile(casper_code)))
|
||||||
|
|
||||||
|
@ -50,15 +64,6 @@ print('Gas consumed to launch Casper', s.state.receipts[-1].gas_used - s.state.r
|
||||||
|
|
||||||
# Helper functions for making a prepare, commit, login and logout message
|
# Helper functions for making a prepare, commit, login and logout message
|
||||||
|
|
||||||
code_template = """
|
|
||||||
~calldatacopy(0, 0, 128)
|
|
||||||
~call(3000, 1, 0, 0, 128, 0, 32)
|
|
||||||
return(~mload(0) == %s)
|
|
||||||
"""
|
|
||||||
|
|
||||||
def mk_validation_code(address):
|
|
||||||
return serpent.compile(code_template % (utils.checksum_encode(address)))
|
|
||||||
|
|
||||||
def mk_prepare(epoch, hash, ancestry_hash, source_epoch, source_ancestry_hash, key):
|
def mk_prepare(epoch, hash, ancestry_hash, source_epoch, source_ancestry_hash, key):
|
||||||
sighash = utils.sha3(rlp.encode([epoch, hash, ancestry_hash, source_epoch, source_ancestry_hash]))
|
sighash = utils.sha3(rlp.encode([epoch, hash, ancestry_hash, source_epoch, source_ancestry_hash]))
|
||||||
v, r, s = utils.ecdsa_raw_sign(sighash, key)
|
v, r, s = utils.ecdsa_raw_sign(sighash, key)
|
||||||
|
@ -209,7 +214,9 @@ assert casper.get_current_epoch() == 1
|
||||||
assert casper.get_consensus_messages__ancestry_hash_justified(0, b'\x00' * 32)
|
assert casper.get_consensus_messages__ancestry_hash_justified(0, b'\x00' * 32)
|
||||||
print("Epoch 1 initialized")
|
print("Epoch 1 initialized")
|
||||||
for k in (t.k1, t.k2, t.k3, t.k4, t.k5, t.k6):
|
for k in (t.k1, t.k2, t.k3, t.k4, t.k5, t.k6):
|
||||||
casper.deposit(utils.privtoaddr(k), utils.privtoaddr(k), value=3 * 10**18)
|
valcode_addr = s.send(t.k0, '', 0, mk_validation_code(utils.privtoaddr(k)))
|
||||||
|
assert utils.big_endian_to_int(s.send(t.k0, purity_checker_address, 0, ct.encode('submit', [valcode_addr]))) == 1
|
||||||
|
casper.deposit(valcode_addr, utils.privtoaddr(k), value=3 * 10**18)
|
||||||
print("Processed 6 deposits")
|
print("Processed 6 deposits")
|
||||||
casper.prepare(0, mk_prepare(1, b'\x10' * 32, b'\x00' * 32, 0, b'\x00' * 32, t.k0))
|
casper.prepare(0, mk_prepare(1, b'\x10' * 32, b'\x00' * 32, 0, b'\x00' * 32, t.k0))
|
||||||
casper.commit(0, mk_commit(1, b'\x10' * 32, 0, t.k0))
|
casper.commit(0, mk_commit(1, b'\x10' * 32, 0, t.k0))
|
||||||
|
|
Loading…
Reference in New Issue