Casper validator withdrawing works!
This commit is contained in:
parent
29106975c0
commit
ae34648c9b
|
@ -1,8 +1,10 @@
|
||||||
from ethereum.casper_utils import RandaoManager, get_skips_and_block_making_time, \
|
from ethereum.casper_utils import RandaoManager, get_skips_and_block_making_time, \
|
||||||
generate_validation_code, call_casper, make_block, check_skips, get_timestamp, \
|
generate_validation_code, call_casper, sign_block, check_skips, get_timestamp, \
|
||||||
get_casper_ct, validator_sizes
|
get_casper_ct, validator_sizes, find_indices, get_dunkle_candidates
|
||||||
from ethereum.utils import sha3, hash32, privtoaddr, ecsign, zpad, encode_int32, \
|
from ethereum.utils import sha3, hash32, privtoaddr, ecsign, zpad, encode_int32, \
|
||||||
big_endian_to_int
|
big_endian_to_int
|
||||||
|
from ethereum.transaction_queue import TransactionQueue
|
||||||
|
from ethereum.block_creation import make_head_candidate
|
||||||
from ethereum.block import Block
|
from ethereum.block import Block
|
||||||
from ethereum.transactions import Transaction
|
from ethereum.transactions import Transaction
|
||||||
from ethereum.chain import Chain
|
from ethereum.chain import Chain
|
||||||
|
@ -34,6 +36,8 @@ class Validator():
|
||||||
def __init__(self, genesis, key, network, env, time_offset=5):
|
def __init__(self, genesis, key, network, env, time_offset=5):
|
||||||
# Create a chain object
|
# Create a chain object
|
||||||
self.chain = Chain(genesis, env=env)
|
self.chain = Chain(genesis, env=env)
|
||||||
|
# Create a transaction queue
|
||||||
|
self.txqueue = TransactionQueue()
|
||||||
# Use the validator's time as the chain's time
|
# Use the validator's time as the chain's time
|
||||||
self.chain.time = lambda: self.get_timestamp()
|
self.chain.time = lambda: self.get_timestamp()
|
||||||
# My private key
|
# My private key
|
||||||
|
@ -61,6 +65,8 @@ class Validator():
|
||||||
self.time_offset = random.randrange(time_offset) - (time_offset // 2)
|
self.time_offset = random.randrange(time_offset) - (time_offset // 2)
|
||||||
# Determine the epoch length
|
# Determine the epoch length
|
||||||
self.epoch_length = self.call_casper('getEpochLength')
|
self.epoch_length = self.call_casper('getEpochLength')
|
||||||
|
# My minimum gas price
|
||||||
|
self.mingasprice = 20 * 10**9
|
||||||
# Give this validator a unique ID
|
# Give this validator a unique ID
|
||||||
self.id = len(ids)
|
self.id = len(ids)
|
||||||
ids.append(self.id)
|
ids.append(self.id)
|
||||||
|
@ -71,44 +77,23 @@ class Validator():
|
||||||
return call_casper(self.chain.state, fun, args)
|
return call_casper(self.chain.state, fun, args)
|
||||||
|
|
||||||
def find_my_indices(self):
|
def find_my_indices(self):
|
||||||
epoch = self.chain.state.block_number // self.epoch_length
|
i, j, success = find_indices(self.chain.state, self.validation_code)
|
||||||
print 'Finding indices for epoch %d' % epoch, self.call_casper('getEpoch')
|
if i is j is None:
|
||||||
for i in range(len(validator_sizes)):
|
self.indices = None
|
||||||
valcount = self.call_casper('getHistoricalValidatorCount', [epoch, i])
|
self.active = False
|
||||||
print i, valcount, self.call_casper('getHistoricalValidatorCount', [0, i])
|
self.next_skip_count, self.next_skip_timestamp = 0, 0
|
||||||
for j in range(valcount):
|
print 'Not in current validator set'
|
||||||
valcode = self.call_casper('getValidationCode', [i, j])
|
elif not success:
|
||||||
print (valcode, self.validation_code)
|
self.indices = None
|
||||||
if valcode == self.validation_code:
|
self.active = False
|
||||||
self.indices = i, j
|
self.next_skip_count, self.next_skip_timestamp = 0, 0
|
||||||
start = self.call_casper('getStartEpoch', [i, j])
|
print 'Registered at (%d, %d) but not in current set' % (i, j)
|
||||||
end = self.call_casper('getEndEpoch', [i, j])
|
|
||||||
if start <= epoch < end:
|
|
||||||
self.active = True
|
|
||||||
self.next_skip_count = 0
|
|
||||||
self.next_skip_timestamp = get_timestamp(self.chain, self.next_skip_count)
|
|
||||||
print 'In current validator set at (%d, %d)' % (i, j)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.indices = None
|
|
||||||
self.active = False
|
|
||||||
self.next_skip_count, self.next_skip_timestamp = 0, 0
|
|
||||||
print 'Registered at (%d, %d) but not in current set' % (i, j)
|
|
||||||
return
|
|
||||||
self.indices = None
|
|
||||||
self.active = False
|
|
||||||
self.next_skip_count, self.next_skip_timestamp = 0, 0
|
|
||||||
print 'Not in current validator set'
|
|
||||||
|
|
||||||
def get_uncles(self):
|
|
||||||
anc = self.chain.get_block(self.chain.get_blockhash_by_number(self.chain.state.block_number - CHECK_FOR_UNCLES_BACK))
|
|
||||||
if anc:
|
|
||||||
descendants = self.chain.get_descendants(anc)
|
|
||||||
else:
|
else:
|
||||||
descendants = self.chain.get_descendants(self.chain.db.get('GENESIS_HASH'))
|
self.indices = [i, j]
|
||||||
potential_uncles = [x for x in descendants if x not in self.chain and isinstance(x, Block)]
|
self.next_skip_count = 0
|
||||||
uncles = [x.header for x in potential_uncles if not call_casper(self.chain.state, 'isDunkleIncluded', [x.header.hash])]
|
self.next_skip_timestamp = get_timestamp(self.chain, self.next_skip_count)
|
||||||
return uncles
|
self.active = True
|
||||||
|
print 'In current validator set at (%d, %d)' % (i, j)
|
||||||
|
|
||||||
def get_timestamp(self):
|
def get_timestamp(self):
|
||||||
return int(self.network.time * 0.01) + self.time_offset
|
return int(self.network.time * 0.01) + self.time_offset
|
||||||
|
@ -128,8 +113,13 @@ class Validator():
|
||||||
self.network.broadcast(self, ChildRequest(obj.header.hash))
|
self.network.broadcast(self, ChildRequest(obj.header.hash))
|
||||||
self.update_head()
|
self.update_head()
|
||||||
elif isinstance(obj, Transaction):
|
elif isinstance(obj, Transaction):
|
||||||
if self.chain.add_transaction(obj):
|
print 'Receiving transaction', obj
|
||||||
|
if obj.gasprice >= self.mingasprice:
|
||||||
|
self.txqueue.add_transaction(obj)
|
||||||
|
print 'Added transaction, txqueue size %d' % len(self.txqueue.txs)
|
||||||
self.network.broadcast(self, obj)
|
self.network.broadcast(self, obj)
|
||||||
|
else:
|
||||||
|
print 'Gasprice too low'
|
||||||
self.received_objects[obj.hash] = True
|
self.received_objects[obj.hash] = True
|
||||||
for x in self.chain.get_chain():
|
for x in self.chain.get_chain():
|
||||||
assert x.hash in self.received_objects
|
assert x.hash in self.received_objects
|
||||||
|
@ -155,25 +145,25 @@ class Validator():
|
||||||
if random.random() > 0.999:
|
if random.random() > 0.999:
|
||||||
print 'Simulating validator failure, block %d not created' % (self.chain.head.header.number + 1 if self.chain.head else 0)
|
print 'Simulating validator failure, block %d not created' % (self.chain.head.header.number + 1 if self.chain.head else 0)
|
||||||
return
|
return
|
||||||
# Make the block, make sure it's valid
|
# Make the block
|
||||||
pre_dunkle_count = call_casper(self.chain.state, 'getTotalDunklesIncluded', [])
|
s1 = self.chain.state.trie.root_hash
|
||||||
dunkle_txs = []
|
pre_dunkle_count = self.call_casper('getTotalDunklesIncluded')
|
||||||
for i, u in enumerate(self.get_uncles()[:4]):
|
dunkle_txs = get_dunkle_candidates(self.chain, self.chain.state)
|
||||||
start_nonce = self.chain.state.get_nonce(self.address)
|
blk = make_head_candidate(self.chain, self.txqueue)
|
||||||
txdata = casper_ct.encode('includeDunkle', [rlp.encode(u)])
|
randao = self.randao.get_parent(self.call_casper('getRandao', self.indices))
|
||||||
dunkle_txs.append(Transaction(start_nonce + i, 0, 650000, self.chain.config['CASPER_ADDR'], 0, txdata).sign(self.key))
|
blk = sign_block(blk, self.key, randao, self.indices, self.next_skip_count)
|
||||||
for dtx in dunkle_txs[::-1]:
|
# Make sure it's valid
|
||||||
self.chain.add_transaction(dtx, force=True)
|
|
||||||
blk = make_block(self.chain, self.key, self.randao, self.indices, self.next_skip_count)
|
|
||||||
global global_block_counter
|
global global_block_counter
|
||||||
global_block_counter += 1
|
global_block_counter += 1
|
||||||
for dtx in dunkle_txs:
|
for dtx in dunkle_txs:
|
||||||
assert dtx in blk.transactions, (dtx, blk.transactions)
|
assert dtx in blk.transactions, (dtx, blk.transactions)
|
||||||
print 'made block with timestamp %d and %d dunkles' % (blk.timestamp, len(dunkle_txs))
|
print 'made block with timestamp %d and %d dunkles' % (blk.timestamp, len(dunkle_txs))
|
||||||
|
s2 = self.chain.state.trie.root_hash
|
||||||
|
assert s1 == s2
|
||||||
assert blk.timestamp >= self.next_skip_timestamp
|
assert blk.timestamp >= self.next_skip_timestamp
|
||||||
assert self.chain.add_block(blk)
|
assert self.chain.add_block(blk)
|
||||||
self.update_head()
|
self.update_head()
|
||||||
post_dunkle_count = call_casper(self.chain.state, 'getTotalDunklesIncluded', [])
|
post_dunkle_count = self.call_casper('getTotalDunklesIncluded')
|
||||||
assert post_dunkle_count - pre_dunkle_count == len(dunkle_txs)
|
assert post_dunkle_count - pre_dunkle_count == len(dunkle_txs)
|
||||||
self.received_objects[blk.hash] = True
|
self.received_objects[blk.hash] = True
|
||||||
print 'Validator %d making block %d (%s)' % (self.id, blk.header.number, blk.header.hash[:8].encode('hex'))
|
print 'Validator %d making block %d (%s)' % (self.id, blk.header.number, blk.header.hash[:8].encode('hex'))
|
||||||
|
@ -202,6 +192,6 @@ class Validator():
|
||||||
sigdata = encode_int32(v) + encode_int32(r) + encode_int32(s)
|
sigdata = encode_int32(v) + encode_int32(r) + encode_int32(s)
|
||||||
txdata = casper_ct.encode('startWithdrawal', [self.indices[0], self.indices[1], sigdata])
|
txdata = casper_ct.encode('startWithdrawal', [self.indices[0], self.indices[1], sigdata])
|
||||||
tx = Transaction(self.chain.state.get_nonce(self.address), gasprice, 650000, self.chain.config['CASPER_ADDR'], 0, txdata).sign(self.key)
|
tx = Transaction(self.chain.state.get_nonce(self.address), gasprice, 650000, self.chain.config['CASPER_ADDR'], 0, txdata).sign(self.key)
|
||||||
self.chain.add_transaction(tx)
|
self.txqueue.add_transaction(tx, force=True)
|
||||||
self.network.broadcast(self, tx)
|
self.network.broadcast(self, tx)
|
||||||
print 'Withdrawing!'
|
print 'Withdrawing!'
|
||||||
|
|
|
@ -4,7 +4,7 @@ import casper
|
||||||
from ethereum.parse_genesis_declaration import mk_basic_state
|
from ethereum.parse_genesis_declaration import mk_basic_state
|
||||||
from ethereum.config import Env
|
from ethereum.config import Env
|
||||||
from ethereum.casper_utils import RandaoManager, generate_validation_code, call_casper, \
|
from ethereum.casper_utils import RandaoManager, generate_validation_code, call_casper, \
|
||||||
get_skips_and_block_making_time, sign_block, make_block, get_contract_code, \
|
get_skips_and_block_making_time, sign_block, get_contract_code, \
|
||||||
casper_config, get_casper_ct, get_casper_code, get_rlp_decoder_code, \
|
casper_config, get_casper_ct, get_casper_code, get_rlp_decoder_code, \
|
||||||
get_hash_without_ed_code, make_casper_genesis, validator_sizes, find_indices
|
get_hash_without_ed_code, make_casper_genesis, validator_sizes, find_indices
|
||||||
from ethereum.utils import sha3, privtoaddr
|
from ethereum.utils import sha3, privtoaddr
|
||||||
|
@ -29,7 +29,7 @@ s = make_casper_genesis(validators=[(generate_validation_code(privtoaddr(k)), ds
|
||||||
for k, ds, r in zip(keys, deposit_sizes, randaos)],
|
for k, ds, r in zip(keys, deposit_sizes, randaos)],
|
||||||
alloc={privtoaddr(k): {'balance': 10**18} for k in keys},
|
alloc={privtoaddr(k): {'balance': 10**18} for k in keys},
|
||||||
timestamp=2,
|
timestamp=2,
|
||||||
epoch_length=40)
|
epoch_length=50)
|
||||||
g = s.to_snapshot()
|
g = s.to_snapshot()
|
||||||
print 'Genesis state created'
|
print 'Genesis state created'
|
||||||
|
|
||||||
|
@ -65,5 +65,7 @@ for i in range(100000):
|
||||||
if i == 4000:
|
if i == 4000:
|
||||||
print 'Checking that validators have withdrawn'
|
print 'Checking that validators have withdrawn'
|
||||||
for v in validators[:5]:
|
for v in validators[:5]:
|
||||||
assert call_casper(v.chain.state, 'getEndEpoch', []) <= 2
|
assert v.call_casper('getEndEpoch', v.indices) <= 2
|
||||||
|
for v in validators[5:]:
|
||||||
|
assert v.call_casper('getEndEpoch', v.indices) > 2
|
||||||
print 'Check successful'
|
print 'Check successful'
|
||||||
|
|
Loading…
Reference in New Issue