Skip to content

Commit

Permalink
Merge ElementsProject#969: Test duration of fedpeg validity in dynafe…
Browse files Browse the repository at this point in the history
…d test

7aaf01e Test duration of fedpeg validity in dynafed test (Steven Roose)

Pull request description:

  I noticed this scenario was not really tested in the test

Tree-SHA512: 05b112b8d2859b1ea718b473c80b6bf0e75fed4f0441cbfafa673b44c2c4d4dad7e932568983ecba6c124baeddbc350193a5c0a0079696a6a67cee1cadb1a586
  • Loading branch information
stevenroose committed Mar 24, 2021
2 parents 9d35590 + 7aaf01e commit 277cbb2
Showing 1 changed file with 118 additions and 0 deletions.
118 changes: 118 additions & 0 deletions test/functional/feature_dynafed.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
initial_extension = [initial_online+initial_online]
new_extension = [initial_offline+initial_online]

ERR_MP_INVALID_PEGOUT = "64: invalid-pegout-proof"
ERR_MP_INVALID_PEGIN = "16: pegin-no-witness"

def go_to_epoch_end(node):
epoch_info = node.getblockchaininfo()
blocks_to_mine = epoch_info["epoch_length"] - epoch_info["epoch_age"] - 1
Expand Down Expand Up @@ -438,6 +441,120 @@ def test_transition_mempool_eject(self):
assert_raises_rpc_error(-26, "invalid-pegout-proof", self.nodes[0].sendrawtransaction, raw_pegout)
assert_raises_rpc_error(-26, "pegin-no-witness, Peg-in tx is invalid.", self.nodes[0].sendrawtransaction, raw_claim)

def assert_accepted(self, tx):
ret = self.nodes[0].testmempoolaccept([tx])[0]
assert ret["allowed"], ret["reject-reason"]

def test_valid_epochs(self):
self.log.info("Testing pegins and pegouts stay valid for some epochs")
# previous test leaves us at age 9
self.nodes[0].generatetoaddress(1, self.nodes[0].getnewaddress())
self.sync_all()
assert_equal(self.nodes[1].getblockchaininfo()["epoch_age"], 0)

# signblockscript is OP_TRUE, let's transition to something we can PAK peg-out to
# and OP_TRUE fedpegscript, and set signblockscript back to OP_TRUE

WSH_OP_TRUE = self.nodes[0].decodescript("51")["segwit"]["hex"]
xpub = "tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B"
init_details = self.nodes[1].initpegoutwallet(xpub)
pak_entry = init_details["pakentry"]
# stitch the extension space together using the relevant keys
extension_space = [pak_entry[4:4+66]+pak_entry[4+66+1:]]
pak_prop = {"signblockscript":WSH_OP_TRUE, "max_block_witness":3, "fedpegscript":"51", "extension_space":extension_space}
# generate blocks with the new proposal
for _ in range(9):
self.nodes[1].submitblock(self.nodes[1].getnewblockhex(0, pak_prop))

self.sync_all()
assert_equal(self.nodes[1].getblockchaininfo()["epoch_age"], 9)
assert_equal(self.nodes[1].getblockchaininfo()["current_signblock_hex"], WSH_OP_TRUE)
assert_equal(self.nodes[1].getsidechaininfo()["current_fedpegscripts"], ["51", "52"])

# Transactions

# pegout prep is easy, just pegout
pegout_tx = self.nodes[1].gettransaction(self.nodes[1].sendtomainchain("", 1)["txid"])["hex"]
self.assert_accepted(pegout_tx)

# Peg-in prep:
# hack: since we're not validating peg-ins in parent chain, just make
# both the funding and claim tx on same chain (printing money)
fund_info = self.nodes[0].getpeginaddress()
peg_id = self.nodes[0].sendtoaddress(fund_info["mainchain_address"], 1)
peg_tx = self.nodes[0].gettransaction(peg_id)["hex"]
# we need the confirmation of the peg tx, so we can't easily assert
# that the pegin tx would be accepted at this very point
self.nodes[0].generatetoaddress(1, self.nodes[0].getnewaddress())
proof = self.nodes[0].gettxoutproof([peg_id])
pegin_tx = self.nodes[0].createrawpegin(peg_tx, proof, fund_info["claim_script"])["hex"]
pegin_tx = self.nodes[0].signrawtransactionwithwallet(pegin_tx)["hex"]
# both should be allowed after that block
assert_equal(self.nodes[0].getsidechaininfo()["current_fedpegscripts"], ["51", "52"])
self.assert_accepted(pegin_tx)
self.assert_accepted(pegout_tx)

# let's generate 20 blocks to pass through 2 new epochs without there being a transition
for _ in range(20):
self.nodes[0].generatetoaddress(1, self.nodes[0].getnewaddress())
self.assert_accepted(pegin_tx)
self.assert_accepted(pegout_tx)
assert_equal(self.nodes[0].getsidechaininfo()["current_fedpegscripts"], ["51", "51"])

# Now have node 1 transition to new pak and fedpegscript
pak_prop["fedpegscript"] = "52"
pak_prop["extension_space"] = initial_extension
for _ in range(9):
self.assert_accepted(pegin_tx)
self.assert_accepted(pegout_tx)
self.nodes[1].submitblock(self.nodes[1].getnewblockhex(0, pak_prop))
sync_blocks(self.nodes)

# so right before the next epoch, the new params are active and
# the pegout is already invalid while the pegin is still valid
self.assert_accepted(pegin_tx)
assert_equal(self.nodes[0].testmempoolaccept([pegout_tx])[0]["reject-reason"], ERR_MP_INVALID_PEGOUT)
# lets go back one block and make sure we can mine the pegout tx
old_tip = self.nodes[0].getbestblockhash()
self.nodes[0].invalidateblock(old_tip)
pegout_txid = self.nodes[0].sendrawtransaction(pegout_tx)
self.nodes[0].submitblock(self.nodes[0].getnewblockhex(0, pak_prop))
tip = self.nodes[0].getbestblockhash()
assert_equal(self.nodes[0].getrawtransaction(pegout_txid, True, tip)["confirmations"], 1)
# undo it again so that we can make sure it is no longer allowed after this point
self.nodes[0].invalidateblock(tip)
self.nodes[0].reconsiderblock(old_tip)

# and after the 10th block of course that is still the case
self.nodes[1].submitblock(self.nodes[1].getnewblockhex(0, pak_prop))
sync_blocks(self.nodes)
self.assert_accepted(pegin_tx)
assert_equal(self.nodes[0].testmempoolaccept([pegout_tx])[0]["reject-reason"], ERR_MP_INVALID_PEGOUT)

# We're in the next epoch, in this one the pegin tx should be accepted up until the last block
assert_equal(self.nodes[1].getsidechaininfo()["current_fedpegscripts"], ["52", "51"])
for _ in range(9):
self.assert_accepted(pegin_tx)
assert_equal(self.nodes[0].testmempoolaccept([pegout_tx])[0]["reject-reason"], ERR_MP_INVALID_PEGOUT)
self.nodes[1].generatetoaddress(1, self.nodes[1].getnewaddress())
sync_blocks(self.nodes)

# so on the last block both should not be allowed
assert_equal(self.nodes[1].getsidechaininfo()["current_fedpegscripts"], ["52", "52"])
assert_equal(self.nodes[0].testmempoolaccept([pegout_tx])[0]["reject-reason"], ERR_MP_INVALID_PEGOUT)
assert_equal(self.nodes[0].testmempoolaccept([pegin_tx])[0]["reject-reason"], ERR_MP_INVALID_PEGIN)

# then undo the last block and make sure we could have mined the pegin in the very last block
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# first use the pegin tx created earlier
pegin_txid = self.nodes[0].sendrawtransaction(pegin_tx)
self.nodes[0].generatetoaddress(1, self.nodes[0].getnewaddress())
assert_equal(self.nodes[0].gettransaction(pegin_txid)["confirmations"], 1)
# make sure that using claimpegin directly also works
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
pegin_txid = self.nodes[0].claimpegin(peg_tx, proof, fund_info["claim_script"])
self.nodes[0].generatetoaddress(1, self.nodes[0].getnewaddress())
assert_equal(self.nodes[0].gettransaction(pegin_txid)["confirmations"], 1)

def run_test(self):
self.test_legacy_params()
Expand All @@ -448,6 +565,7 @@ def run_test(self):
self.test_four_fifth_vote()
self.test_all_vote()
self.test_transition_mempool_eject()
self.test_valid_epochs()

if __name__ == '__main__':
DynaFedTest().main()

0 comments on commit 277cbb2

Please sign in to comment.