diff --git a/tests/plugins/badestimate.py b/tests/plugins/badestimate.py new file mode 100755 index 000000000..84e9112df --- /dev/null +++ b/tests/plugins/badestimate.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +import json +import subprocess + +from pyln.client import Plugin + + +plugin = Plugin() + + +def bcli(plugin, cmd): + ret = subprocess.run(['bitcoin-cli', + '-datadir={}'.format(plugin.get_option("bitcoin-datadir")), + '-rpcuser={}'.format(plugin.get_option("bitcoin-rpcuser")), + '-rpcpassword={}'.format(plugin.get_option("bitcoin-rpcpassword")), + '-rpcport={}'.format(plugin.get_option("bitcoin-rpcport"))] + + cmd, stdout=subprocess.PIPE) + if ret.returncode != 0: + return None + return ret.stdout.decode('utf-8') + + +@plugin.method("estimatefees") +def estimatefees(plugin, **kwargs): + if plugin.get_option("badestimate-badorder"): + return {"feerate_floor": 1000, + "feerates": [{"blocks": 6, + "feerate": 1240000000}, + {"blocks": 12, + "feerate": 1350000000}, + {"blocks": 100, + "feerate": 3610000000}, + {"blocks": 2, + "feerate": 1270000000}]} + else: + return {"feerate_floor": 1000, + "feerates": [{"blocks": 2, + "feerate": 1270000000}, + {"blocks": 6, + "feerate": 1240000000}, + {"blocks": 12, + "feerate": 1350000000}, + {"blocks": 100, + "feerate": 3610000000}]} + + +@plugin.method("getrawblockbyheight") +def getrawblockbyheight(plugin, height, **kwargs): + bhash = bcli(plugin, ["getblockhash", str(height)]) + if bhash is None: + return {"blockhash": None, + "block": None} + bhash = bhash.strip() + block = bcli(plugin, ["getblock", bhash, "0"]).strip() + return {"blockhash": bhash, + "block": block} + + +@plugin.method("getchaininfo") +def getchaininfo(plugin, **kwargs): + info = json.loads(bcli(plugin, ["getblockchaininfo"])) + return {"chain": info['chain'], + "headercount": info['headers'], + "blockcount": info['blocks'], + "ibd": info['initialblockdownload']} + + +@plugin.method("sendrawtransaction") +def sendrawtransaction(plugin, tx, allowhighfees=False, **kwargs): + bcli(plugin, ["sendrawtransaction", tx]) + return {'success': True} + + +@plugin.method("getutxout") +def getutxout(plugin, txid, vout, *kwargs): + txoutstr = bcli(plugin, ["gettxout", txid, vout]).strip() + if txoutstr == "": + return {"amount": None, "script": None} + txout = json.loads(txoutstr) + return {"amount": txout['value'], + "script": txout['scriptPubKey']['hex']} + + +plugin.add_option("bitcoin-rpcuser", '', '') +plugin.add_option("bitcoin-rpcpassword", '', '') +plugin.add_option("bitcoin-datadir", '', '') +plugin.add_option("bitcoin-rpcport", '', '') +plugin.add_option("badestimate-badorder", False, 'Send out-of-order estimates', opt_type='bool') + +plugin.run() diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 8ec9f8fa8..f18e30793 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -1748,6 +1748,34 @@ def test_bitcoin_backend(node_factory, bitcoind): " bitcoind") +def test_bitcoin_bad_estimatefee(node_factory, bitcoind): + """ + This tests that we don't crash if bitcoind backend gives bad estimatefees. + """ + plugin = os.path.join(os.getcwd(), "tests/plugins/badestimate.py") + l1 = node_factory.get_node(options={"disable-plugin": "bcli", + "plugin": plugin, + "badestimate-badorder": True, + "wumbo": None}, + start=False, + may_fail=True, allow_broken_log=True) + l1.daemon.start(wait_for_initialized=False, stderr_redir=True) + assert l1.daemon.wait() == 1 + l1.daemon.is_in_stderr(r"badestimate.py error: bad response to estimatefees.feerates \(Blocks must be ascending order: 2 <= 100!\)") + + del l1.daemon.opts["badestimate-badorder"] + l1.start() + + l2 = node_factory.get_node(options={"disable-plugin": "bcli", + "plugin": plugin, + "wumbo": None}) + # Give me some funds. + bitcoind.generate_block(5) + l1.fundwallet(100 * 10**8) + l1.connect(l2) + l1.rpc.fundchannel(l2.info["id"], 50 * 10**8) + + def test_bcli(node_factory, bitcoind, chainparams): """ This tests the bcli plugin, used to gather Bitcoin data from a local