Skip to content

Commit

Permalink
pytest: test Bitcoin plugin registration and the bcli plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
darosior committed Feb 7, 2020
1 parent 93a3326 commit 083d123
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 0 deletions.
5 changes: 5 additions & 0 deletions lightningd/chaintopology.c
Original file line number Diff line number Diff line change
Expand Up @@ -1000,12 +1000,17 @@ void setup_topology(struct chain_topology *topo,

/* This waits for bitcoind. */
if (!bitcoind_check_commands(topo->bitcoind)) {
/* For testing.. */
log_debug(topo->ld->log, "Missing Bitcoin plugin commands");
fprintf(stderr, "Could not access all commands required to talk"
" to bitcoind, is a Bitcoin plugin (by default "
"plugins/bcli) registered ?");
exit(1);
}

/* For testing.. */
log_debug(topo->ld->log, "All Bitcoin plugin commands registered");

/* Sanity checks, then topology initialization. */
bitcoind_getchaininfo(topo->bitcoind, true, check_chain, topo);

Expand Down
37 changes: 37 additions & 0 deletions tests/plugins/bitcoin/part1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env python3
"""
This registers part of the Bitcoin backend methods.
We only use it for testing startup and we don't care about the actual values.
"""
import time

from pyln.client import Plugin


plugin = Plugin()


@plugin.method("getfeerate")
def getfeerate(plugin, **kwargs):
time.sleep(1)
return {}


@plugin.method("getrawblockbyheight")
def getblock(plugin, **kwargs):
time.sleep(1)
return {}


@plugin.method("getchaininfo")
def getchaininfo(plugin, **kwargs):
time.sleep(1)
return {}


# We don't use these options, but it allows us to get to the expected failure.
plugin.add_option("bitcoin-rpcuser", "", "")
plugin.add_option("bitcoin-rpcpassword", "", "")
plugin.add_option("bitcoin-rpcport", "", "")

plugin.run()
26 changes: 26 additions & 0 deletions tests/plugins/bitcoin/part2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env python3
"""
This registers part of the Bitcoin backend methods.
We only use it for testing startup and we don't care about the actual values.
"""
import time

from pyln.client import Plugin


plugin = Plugin()


@plugin.method("sendrawtransaction")
def sendtx(plugin, **kwargs):
time.sleep(1)
return {}


@plugin.method("gettxout")
def gettxout(plugin, **kwargs):
time.sleep(1)
return {}


plugin.run()
81 changes: 81 additions & 0 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -823,3 +823,84 @@ def test_libplugin(node_factory):

# Test RPC calls FIXME: test concurrent ones ?
assert l1.rpc.call("testrpc") == l1.rpc.getinfo()


def test_bitcoin_backend(node_factory, bitcoind):
"""
This tests interaction with the Bitcoin backend, but not specifically bcli
"""
l1 = node_factory.get_node(start=False, options={"disable-plugin": "bcli"},
may_fail=True, allow_broken_log=True)

# We don't start if we haven't all the required methods registered.
plugin = os.path.join(os.getcwd(), "tests/plugins/bitcoin/part1.py")
l1.daemon.opts["plugin"] = plugin
try:
l1.daemon.start()
except ValueError:
assert l1.daemon.is_in_log("Missing Bitcoin plugin commands")
# Now we should start if all the commands are registered, even if they
# are registered by two distincts plugins.
del l1.daemon.opts["plugin"]
l1.daemon.opts["plugin-dir"] = os.path.join(os.getcwd(),
"tests/plugins/bitcoin/")
try:
l1.daemon.start()
except ValueError:
msg = "All Bitcoin plugin commands registered"
assert l1.daemon.is_in_log(msg)
else:
raise Exception("We registered all commands but couldn't start!")
else:
raise Exception("We could start without all commands registered !!")

# But restarting with just bcli is ok
del l1.daemon.opts["plugin-dir"]
del l1.daemon.opts["disable-plugin"]
l1.start()
assert l1.daemon.is_in_log("bitcoin-cli initialized and connected to"
" bitcoind")


def test_bcli(node_factory, bitcoind):
"""
This tests the bcli plugin, used to gather Bitcoin data from a local
bitcoind.
Mostly sanity checks of the interface..
"""
l1, l2 = node_factory.get_nodes(2)

# We cant stop it dynamically
with pytest.raises(RpcError):
l1.rpc.plugin_stop("bcli")

# Failure case of feerate is tested in test_misc.py
assert "feerate" in l1.rpc.call("getfeerate", {"blocks": 3,
"mode": "CONSERVATIVE"})

resp = l1.rpc.call("getchaininfo")
assert resp["chain"] == "regtest"
for field in ["headercount", "blockcount", "ibd"]:
assert field in resp

# We shouldn't get upset if we ask for an unknown-yet block
resp = l1.rpc.call("getrawblockbyheight", {"height": 500})
assert resp["blockhash"] is resp["block"] is None
resp = l1.rpc.call("getrawblockbyheight", {"height": 50})
assert resp["blockhash"] is not None and resp["blockhash"] is not None
# Some other bitcoind-failure cases for this call are covered in
# tests/test_misc.py

l1.fundwallet(10**5)
l1.connect(l2)
txid = l1.rpc.fundchannel(l2.info["id"], 10**4)["txid"]
txo = l1.rpc.call("gettxout", {"txid": txid, "vout": 0})
assert (Millisatoshi(txo["amount"]) == Millisatoshi(10**4 * 10**3)
and txo["script"].startswith("0020"))
l1.rpc.close(l2.info["id"])
# When output is spent, it should give us null !
txo = l1.rpc.call("gettxout", {"txid": txid, "vout": 0})
assert txo["amount"] is txo["script"] is None

resp = l1.rpc.call("sendrawtransaction", {"tx": "dummy"})
assert not resp["success"] and "decode failed" in resp["errmsg"]

0 comments on commit 083d123

Please sign in to comment.