Skip to content

Commit

Permalink
Merge 277cbb2 into merged_master (Elements PR #969)
Browse files Browse the repository at this point in the history
  • Loading branch information
apoelstra committed Mar 26, 2021
2 parents 48dc78d + 277cbb2 commit 0699c4d
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 = "invalid-pegout-proof"
ERR_MP_INVALID_PEGIN = "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))
self.sync_blocks()

# 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))
self.sync_blocks()
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())
self.sync_blocks()

# 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 0699c4d

Please sign in to comment.