def calc_vote_relay_delay(record_to): # UNIT-E TODO: node can't vote when it processed the checkpoint # so we create one extra block to pass that. See https://github.com/dtr-org/unit-e/issues/643 generate_block(middle) # ensure all nodes are synced before recording the delay sync_blocks([middle, record_to], timeout=10) sync_mempools([middle, record_to], timeout=10) assert_equal(len(new_votes_in_mempool(middle)), 0) # ensure that record_from node receives the block earlier than the vote disconnect_nodes(middle, finalizer.index) generate_block(middle) connect_nodes(middle, finalizer.index) wait_until(lambda: len(new_votes_in_mempool(middle)) > 0, timeout=10) now = time.perf_counter() sync_mempools([middle, record_to], wait=0.05, timeout=10) delay = time.perf_counter() - now new_votes = new_votes_in_mempool(middle) assert_equal(len(new_votes), 1) new_vote = new_votes[0] vote_tx_ids.add(new_vote) # sanity check: tx we measured is a vote tx tx = FromHex(CTransaction(), middle.getrawtransaction(new_vote)) assert_equal(tx.get_type(), TxType.VOTE) self.log.debug("Vote(%s) propagated from %d to %d in %0.3f seconds" % (new_vote, middle.index, record_to.index, delay)) return delay
def test_successful_deposit(self, finalizer, proposer): payto = finalizer.getnewaddress("", "legacy") txid = finalizer.deposit(payto, 1500) deposit_tx = finalizer.gettransaction(txid) assert_equal(deposit_tx['amount'], 0) # 0 because we send the money to ourselves assert_less_than(deposit_tx['fee'], 0) # fee returned by gettransaction is negative raw_deposit_tx = finalizer.decoderawtransaction(deposit_tx['hex']) assert_equal(raw_deposit_tx['vout'][0]['value'], 1500) assert_equal(raw_deposit_tx['vout'][1]['value'], 10000 - 1500 + deposit_tx['fee']) # wait for transaction to propagate self.wait_for_transaction(txid, 10) wait_until(lambda: finalizer.getvalidatorinfo()['validator_status'] == 'WAITING_DEPOSIT_CONFIRMATION', timeout=5) # mine a block to allow the deposit to get included self.generate_sync(proposer) disconnect_nodes(finalizer, proposer.index) wait_until(lambda: finalizer.getvalidatorinfo()['validator_status'] == 'WAITING_DEPOSIT_FINALIZATION', timeout=5) # move to checkpoint proposer.generate(8) assert_equal(proposer.getblockcount(), 10) assert_finalizationstate(proposer, {'currentEpoch': 1, 'currentDynasty': 0, 'lastJustifiedEpoch': 0, 'lastFinalizedEpoch': 0, 'validators': 0}) # the finalizer will be ready to operate at currentDynasty=3 for _ in range(4): proposer.generate(10) assert_finalizationstate(proposer, {'validators': 0}) # start new dynasty proposer.generate(1) assert_equal(proposer.getblockcount(), 51) assert_finalizationstate(proposer, {'currentEpoch': 6, 'currentDynasty': 3, 'lastJustifiedEpoch': 4, 'lastFinalizedEpoch': 3, 'validators': 1}) connect_nodes(finalizer, proposer.index) sync_blocks([finalizer, proposer], timeout=10) wait_until(lambda: finalizer.getvalidatorinfo()['enabled'] == 1, timeout=5) assert_equal(finalizer.getvalidatorinfo()['validator_status'], 'IS_VALIDATING') # creates actual vote wait_until(lambda: len(proposer.getrawmempool()) == 1, timeout=5) txraw = proposer.getrawtransaction(proposer.getrawmempool()[0]) vote = FromHex(CTransaction(), txraw) assert_equal(vote.get_type(), TxType.VOTE)
def run_test(self): p, f1, f2 = self.nodes self.setup_stake_coins(p, f1, f2) self.generate_sync(p) self.log.info("Setup deposit") self.setup_deposit(p, [f1, f2]) disconnect_nodes(p, f1.index) disconnect_nodes(p, f2.index) self.log.info("Generate few epochs") votes = self.generate_epoch(proposer=p, finalizer=f1, count=2) assert len(votes) != 0 self.log.info("Check slashig condition after node restart") self.restart_node(p) vtx = self.make_double_vote_tx(votes[0], votes[-1], p, f1) assert_raises_rpc_error(-26, 'bad-vote-invalid', p.sendrawtransaction, ToHex(vtx)) wait_until(lambda: len(p.getrawmempool()) > 0, timeout=20) slash = FromHex(CTransaction(), p.getrawtransaction(p.getrawmempool()[0])) assert_equal(slash.get_type(), TxType.SLASH) self.log.info("Slashed") self.log.info("Generate few epochs") votes = self.generate_epoch(proposer=p, finalizer=f2, count=2) assert len(votes) != 0 self.log.info( "Check slashig condition after node restart with reindex") self.restart_node(p, reindex=True) vtx = self.make_double_vote_tx(votes[0], votes[-1], p, f2) assert_raises_rpc_error(-26, 'bad-vote-invalid', p.sendrawtransaction, ToHex(vtx)) wait_until(lambda: len(p.getrawmempool()) > 0, timeout=20) slash = FromHex(CTransaction(), p.getrawtransaction(p.getrawmempool()[0])) assert_equal(slash.get_type(), TxType.SLASH) self.log.info("Slashed")
def run_test(self): p, v, s = self.nodes self.setup_stake_coins(p, v) self.generate_sync(p, nodes=[p, v]) self.log.info("Setup deposit") setup_deposit(self, p, [v]) disconnect_nodes(p, v.index) self.log.info("Generate few epochs") votes = self.generate_epoch(proposer=p, finalizer=v, count=2) assert (len(votes) != 0) assert_equal(p.getblockcount(), 32) assert_finalizationstate( p, { 'currentEpoch': 7, 'lastJustifiedEpoch': 6, 'lastFinalizedEpoch': 5, 'validators': 1 }) self.log.info("Connect fast-sync node") connect_nodes(s, p.index) sync_blocks([p, s]) assert_finalizationstate( s, { 'currentEpoch': 7, 'lastJustifiedEpoch': 6, 'lastFinalizedEpoch': 5, 'validators': 1 }) self.log.info("Generate next epoch") votes += self.generate_epoch(proposer=p, finalizer=v, count=1) assert_equal(p.getblockcount(), 37) assert_finalizationstate( p, { 'currentEpoch': 8, 'lastJustifiedEpoch': 7, 'lastFinalizedEpoch': 6, 'validators': 1 }) sync_blocks([p, s]) assert_finalizationstate( s, { 'currentEpoch': 8, 'lastJustifiedEpoch': 7, 'lastFinalizedEpoch': 6, 'validators': 1 }) self.log.info("Check slashing condition") # Create new vote with input=votes[-1] which attempts to make a double vote # To detect double vote, it's enough having two votes which are: # 1. from same validator # 2. with same source epoch # 3. with same target epoch # 4. with different target hash # So, make target hash different. vote = s.extractvotefromsignature( bytes_to_hex_str(votes[0].vin[0].scriptSig)) target_hash = list(vote['target_hash']) target_hash[0] = '0' if target_hash[0] == '1' else '1' vote['target_hash'] = "".join(target_hash) prev_tx = s.decoderawtransaction(ToHex(votes[-1])) vtx = v.createvotetransaction(vote, prev_tx['txid']) vtx = v.signrawtransactionwithwallet(vtx) vtx = FromHex(CTransaction(), vtx['hex']) assert_raises_rpc_error(-26, 'bad-vote-invalid', s.sendrawtransaction, ToHex(vtx)) wait_until(lambda: len(s.getrawmempool()) > 0, timeout=20) slash = FromHex(CTransaction(), s.getrawtransaction(s.getrawmempool()[0])) assert_equal(slash.get_type(), TxType.SLASH) self.log.info("Slashed") self.log.info("Restart fast-sync node") self.restart_node(s.index) connect_nodes(s, p.index) sync_blocks([s, p])