Skip to content

Commit

Permalink
[Tests] Functional testing for ProUpRev txes
Browse files Browse the repository at this point in the history
  • Loading branch information
random-zebra committed Jul 6, 2021
1 parent 2c16960 commit b02d147
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 28 deletions.
5 changes: 5 additions & 0 deletions test/functional/test_framework/messages.py
Expand Up @@ -1389,6 +1389,11 @@ def __init__(self, idx, owner_addr, operator_addr, voting_addr, ipport, payout_a
self.proTx = None
self.collateral = None

def revoked(self):
self.ipport = "[::]:0"
self.operator = ""
self.operator_key = None

def __repr__(self):
return "Masternode(idx=%d, owner=%s, operator=%s, voting=%s, ip=%s, payee=%s, opkey=%s, protx=%s, collateral=%s)" % (
self.idx, str(self.owner), str(self.operator), str(self.voting), str(self.ipport),
Expand Down
9 changes: 8 additions & 1 deletion test/functional/test_framework/test_framework.py
Expand Up @@ -1323,7 +1323,14 @@ def check_mn_list_on_node(self, idx, mns):
self.nodes[idx].syncwithvalidationinterfacequeue()
mnlist = self.nodes[idx].listmasternodes()
if len(mnlist) != len(mns):
raise Exception("Invalid mn list on node %d:\n%s\nExpected:%s" % (idx, str(mnlist), str(mns)))
mnlist_l = [[x['proTxHash'], x['dmnstate']['service']] for x in mnlist]
mns_l = [[x.proTx, x.ipport] for x in mns]
strErr = ""
for x in [x for x in mnlist_l if x not in mns_l]:
strErr += "Mn %s is not expected\n" % str(x)
for x in [x for x in mns_l if x not in mnlist_l]:
strErr += "Expect Mn %s not found\n" % str(x)
raise Exception("Invalid mn list on node %d:\n%s" % (idx, strErr))
protxs = {x["proTxHash"]: x for x in mnlist}
for mn in mns:
if mn.proTx not in protxs:
Expand Down
2 changes: 1 addition & 1 deletion test/functional/test_runner.py
Expand Up @@ -150,7 +150,7 @@
'tiertwo_governance_reorg.py', # ~ 361 sec
'tiertwo_masternode_activation.py', # ~ 352 sec
'tiertwo_masternode_ping.py', # ~ 293 sec
'tiertwo_reorg_mempool.py', # ~ 107 sec
'tiertwo_reorg_mempool.py', # ~ 97 sec
]

SAPLING_SCRIPTS = [
Expand Down
54 changes: 50 additions & 4 deletions test/functional/tiertwo_deterministicmns.py
Expand Up @@ -154,8 +154,8 @@ def run_test(self):
for i in range(3):
idx = 2 + len(mns) + i
add_and_key = []
add_and_key.append(miner.getnewaddress("oper-%d-key" % idx))
add_and_key.append(miner.dumpprivkey(add_and_key[0]))
add_and_key.append(controller.getnewaddress("oper-%d-key" % idx))
add_and_key.append(controller.dumpprivkey(add_and_key[0]))
self.nodes[idx].initmasternode(add_and_key[1], "", True)
op_keys.append(add_and_key)
time.sleep(1)
Expand Down Expand Up @@ -344,11 +344,13 @@ def run_test(self):
self.check_mn_list(mns)
self.log.info("Update payout address...")
old_payee = mns[2].payee
old_mn2_bal = self.get_addr_balance(controller, old_payee)
mns[2].payee = controller.getnewaddress()
controller.protx_update_registrar(mns[2].proTx, "", "", mns[2].payee)
self.sync_mempools([miner, controller])
miner.generate(len(mns))
miner.generate(1)
self.sync_blocks()
old_mn2_bal = self.get_addr_balance(controller, old_payee)
miner.generate(len(mns)-1)
self.sync_blocks()
self.check_mn_list(mns)
# Check payment to new address
Expand All @@ -358,6 +360,50 @@ def run_test(self):
# The PoSe banned node didn't receive any more payment
assert_equal(self.get_addr_balance(controller, mns[0].payee), old_mn0_balance)

# Test ProUpRev txes
self.log.info("Trying to revoke a non-existent masternode...")
assert_raises_rpc_error(-8, "not found", miner.protx_revoke,
"%064x" % getrandbits(256))
self.log.info("Trying to revoke with invalid reason...")
assert_raises_rpc_error(-8, "invalid reason", controller.protx_revoke, mns[3].proTx, "", 100)
self.log.info("Revoke masternode...")
# Controller should already have the key (as it was generated there), no need to pass it
controller.protx_revoke(mns[3].proTx, "", 1)
mns[3].revoked()
self.sync_mempools([miner, controller])
miner.generate(1)
self.sync_blocks()
self.check_mn_list(mns)
old_mn3_bal = self.get_addr_balance(controller, mns[3].payee)
self.log.info("Revoke masternode (with external key)...")
miner.protx_revoke(mns[4].proTx, mns[4].operator_key, 2)
mns[4].revoked()
miner.generate(1)
self.sync_blocks()
self.check_mn_list(mns)
old_mn4_bal = self.get_addr_balance(controller, mns[4].payee)
miner.generate(len(mns) + 1)
self.sync_blocks()
self.check_mn_list(mns)
# Check (no) payments
self.log.info("Checking payments...")
assert_equal(self.get_addr_balance(controller, mns[3].payee), old_mn3_bal)
assert_equal(self.get_addr_balance(controller, mns[4].payee), old_mn4_bal)

# Test reviving a masternode
self.log.info("Reviving a masternode...")
mns[3].operator = controller.getnewaddress()
mns[3].operator_key = controller.dumpprivkey(mns[3].operator)
miner.protx_update_registrar(mns[3].proTx, mns[3].operator, "", "", controller.dumpprivkey(mns[3].owner))
miner.generate(1)
mns[3].ipport = "127.0.0.1:3000"
miner.protx_update_service(mns[3].proTx, mns[3].ipport, "", mns[3].operator_key)
miner.generate(len(mns))
self.sync_blocks()
self.check_mn_list(mns)
self.log.info("Checking payments...")
assert_equal(self.get_addr_balance(controller, mns[3].payee), old_mn3_bal + Decimal('3'))

self.log.info("All good.")


Expand Down
63 changes: 41 additions & 22 deletions test/functional/tiertwo_reorg_mempool.py
Expand Up @@ -82,17 +82,19 @@ def run_test(self):
self.sync_blocks()
self.assert_equal_for_all(201, "getblockcount")

# Register one masternode before the split
# Register two masternodes before the split
collateral_addr = nodeA.getnewaddress() # for both collateral and payouts
pre_split_mn = create_new_dmn(100, nodeA, nodeA.getnewaddress(), None)
self.register_masternode(nodeA, pre_split_mn, collateral_addr)
pre_split_mn1 = create_new_dmn(100, nodeA, nodeA.getnewaddress(), None)
pre_split_mn2 = create_new_dmn(200, nodeA, nodeA.getnewaddress(), None)
self.register_masternode(nodeA, pre_split_mn1, collateral_addr)
self.register_masternode(nodeA, pre_split_mn2, collateral_addr)
nodeA.generate(1)
self.sync_blocks()
mnsA = [pre_split_mn]
mnsB = [pre_split_mn]
mnsA = [pre_split_mn1, pre_split_mn2]
mnsB = [pre_split_mn1, pre_split_mn2]
self.check_mn_list_on_node(0, mnsA)
self.check_mn_list_on_node(1, mnsB)
self.log.info("Pre-split masternode registered.")
self.log.info("Pre-split masternodes registered.")

# Disconnect the nodes
self.disconnect_all() # network splits at block 203
Expand Down Expand Up @@ -171,31 +173,36 @@ def run_test(self):
self.protx_register_ext(nodeA, nodeA, mempool_dmn4, mempool_dmn4.collateral, True)

# Now send a valid proUpServ tx to the mempool, without mining it
proupserv1_txid = nodeA.protx_update_service(pre_split_mn.proTx, "127.0.0.1:1000")
proupserv1_txid = nodeA.protx_update_service(pre_split_mn1.proTx, "127.0.0.1:1000")

# Try sending another update, reusing the same ip of the previous mempool tx
self.log.info("Testing proUpServ in-mempool duplicate-IP rejection...")
assert_raises_rpc_error(-26, "protx-dup", nodeA.protx_update_service, mnsA[0].proTx, "127.0.0.1:1000")

# Now send other two valid proUpServ txes to the mempool, without mining them
proupserv2_txid = nodeA.protx_update_service(mnsA[2].proTx, "127.0.0.1:2000")
proupserv3_txid = nodeA.protx_update_service(pre_split_mn.proTx, "127.0.0.1:1001")
proupserv2_txid = nodeA.protx_update_service(mnsA[3].proTx, "127.0.0.1:2000")
proupserv3_txid = nodeA.protx_update_service(pre_split_mn1.proTx, "127.0.0.1:1001")

# Send valid proUpReg tx to the mempool
operator_to_reuse = nodeA.getnewaddress()
proupreg1_txid = nodeA.protx_update_registrar(mnsA[3].proTx, operator_to_reuse, "", "")
proupreg1_txid = nodeA.protx_update_registrar(mnsA[4].proTx, operator_to_reuse, "", "")

# Try sending another one, reusing the operator key used by another mempool proTx
self.log.info("Testing proUpReg in-mempool duplicate-operator-key rejection...")
assert_raises_rpc_error(-26, "protx-dup", nodeA.protx_update_registrar,
mnsA[4].proTx, mempool_dmn1.operator, "", "")
mnsA[5].proTx, mempool_dmn1.operator, "", "")

# Now send other two valid proUpServ txes to the mempool, without mining them
new_voting_address = nodeA.getnewaddress()
proupreg2_txid = nodeA.protx_update_registrar(mnsA[4].proTx, "", new_voting_address, "")
proupreg3_txid = nodeA.protx_update_registrar(pre_split_mn.proTx, "", new_voting_address, "")
proupreg2_txid = nodeA.protx_update_registrar(mnsA[5].proTx, "", new_voting_address, "")
proupreg3_txid = nodeA.protx_update_registrar(pre_split_mn1.proTx, "", new_voting_address, "")

# Now nodeA has 4 proReg txes in its mempool, 3 proUpServ txes, and 3 proUpReg txes
# Send two valid proUpRev txes to the mempool, without mining them
self.log.info("Revoking two masternodes...")
prouprev1_txid = nodeA.protx_revoke(mnsA[6].proTx)
prouprev2_txid = nodeA.protx_revoke(pre_split_mn2.proTx)

# Now nodeA has 4 proReg txes in its mempool, 3 proUpServ txes, 3 proUpReg txes, and 2 proUpRev
mempoolA = nodeA.getrawmempool()
assert mempool_dmn1.proTx in mempoolA
assert mempool_dmn2.proTx in mempoolA
Expand All @@ -207,6 +214,8 @@ def run_test(self):
assert proupreg1_txid in mempoolA
assert proupreg2_txid in mempoolA
assert proupreg3_txid in mempoolA
assert prouprev1_txid in mempoolA
assert prouprev2_txid in mempoolA

assert_equal(nodeA.getblockcount(), 208)

Expand All @@ -226,7 +235,8 @@ def run_test(self):

# Pick the proReg for the first MN registered on chain A, and replay it on chain B
self.log.info("Replaying a masternode on a different chain...")
mnsA.remove(pre_split_mn)
mnsA.remove(pre_split_mn1)
mnsA.remove(pre_split_mn2)
replay_mn = mnsA.pop(0)
mnsB.append(replay_mn) # same proTx hash
nodeB.sendrawtransaction(nodeA.getrawtransaction(replay_mn.proTx, False))
Expand Down Expand Up @@ -310,27 +320,36 @@ def run_test(self):
assert proupreg1_txid not in mempoolA
assert proupreg2_txid not in mempoolA
assert proupreg3_txid in mempoolA
# The frist mempool proUpRev tx has been removed as it was meant to revoke
# a masternode that is not in the deterministic list anymore.
assert prouprev1_txid not in mempoolA
assert prouprev2_txid in mempoolA
# The mempool contains also all the ProReg from the disconnected blocks,
# except the ones re-registered and replayed on chain B.
for mn in mnsA:
assert mn.proTx in mempoolA
assert rereg_mn.proTx not in mempoolA
assert replay_mn.proTx not in mempoolA
assert pre_split_mn.proTx not in mempoolA
assert pre_split_mn1.proTx not in mempoolA
assert pre_split_mn1.proTx not in mempoolA

# Mine a block from nodeA so the mempool proReg txes get included
# Mine a block from nodeA so the mempool txes get included
self.log.info("Mining mempool txes...")
nodeA.generate(1)
self.sync_all()
# mempool_dmn2 and mempool_dmn3 have been included
mnsB.append(mempool_dmn2)
mnsB.append(mempool_dmn3)
# proupserv3 has changed the IP of the pre_split masternode
# proupserv3 has changed the IP of the pre_split masternode 1
# and proupreg3 has changed its voting address
mnsB.remove(pre_split_mn)
pre_split_mn.ipport = "127.0.0.1:1001"
pre_split_mn.voting = new_voting_address
mnsB.append(pre_split_mn)
mnsB.remove(pre_split_mn1)
pre_split_mn1.ipport = "127.0.0.1:1001"
pre_split_mn1.voting = new_voting_address
mnsB.append(pre_split_mn1)
# prouprev2 has revoked pre_split masternode 2
pre_split_mn2.ipport = "[::]:0"
pre_split_mn2.operator = ""
pre_split_mn2.operator_key = None
# the ProReg txes, that were added back to the mempool from the
# disconnected blocks, have been mined again
mns_all = mnsA + mnsB
Expand Down

0 comments on commit b02d147

Please sign in to comment.