diff --git a/.gitignore b/.gitignore index f9d0e7a..74fcde5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ __pycache__/ dist/ trustedcoin -venv/ \ No newline at end of file +venv/ diff --git a/estimatefees.go b/estimatefees.go index 0c3c7de..33a4587 100644 --- a/estimatefees.go +++ b/estimatefees.go @@ -18,7 +18,19 @@ type FeeRate struct { FeeRate int `json:"feerate"` } -func getFeeRates() (*EstimatedFees, error) { +func getFeeRates(network string) (*EstimatedFees, error) { + if network == "regtest" { + return &EstimatedFees{ + FeeRateFloor: 1000, + FeeRates: []FeeRate{ + {Blocks: 2, FeeRate: 1000}, + {Blocks: 6, FeeRate: 1000}, + {Blocks: 12, FeeRate: 1000}, + {Blocks: 100, FeeRate: 1000}, + }, + }, nil + } + // try bitcoind first if bitcoind != nil { in2, err2 := bitcoind.EstimateSmartFee(2, &btcjson.EstimateModeConservative) diff --git a/go.sum b/go.sum index 73ac81d..5e6369c 100644 --- a/go.sum +++ b/go.sum @@ -32,8 +32,6 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/1ma/lightningd-gjson-rpc v0.0.0-20241109130140-ddc6991a26cf h1:4QFQcuL5Fks+WRI+BSrgTxGoJxNUM/Ht8YCgQRoKcDY= -github.com/1ma/lightningd-gjson-rpc v0.0.0-20241109130140-ddc6991a26cf/go.mod h1:DqVHlrgk0q0J08nbPBCwDVuB7vzPohRnrzuGZ0ct0fg= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= diff --git a/integration_test.py b/integration_test.py index 0b7b150..c783469 100644 --- a/integration_test.py +++ b/integration_test.py @@ -1,51 +1,31 @@ from pyln.client import RpcError from pyln.testing.fixtures import * -from pyln.testing.utils import wait_for def test_bcli(node_factory, bitcoind, chainparams): """ - This tests the bcli plugin, used to gather Bitcoin data from a local - bitcoind. - Mostly sanity checks of the interface... + Based on the test_bcli from Core Lightning """ - - l1 = node_factory.get_node() - l2 = node_factory.get_node() + node = node_factory.get_node(opts={ + "disable-plugin": "bcli", + "plugin": os.path.join(os.getcwd(), 'trustedcoin'), + }) # We cant stop it dynamically with pytest.raises(RpcError): - l1.rpc.plugin_stop("bcli") + node.rpc.plugin_stop("bcli") # Failure case of feerate is tested in test_misc.py - estimates = l1.rpc.call("estimatefees") + estimates = node.rpc.call("estimatefees") assert 'feerate_floor' in estimates assert [f['blocks'] for f in estimates['feerates']] == [2, 6, 12, 100] - resp = l1.rpc.call("getchaininfo", {"last_height": 0}) + resp = node.rpc.call("getchaininfo", {"last_height": 0}) assert resp["chain"] == chainparams['name'] 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}) + resp = node.rpc.call("getrawblockbyheight", {"height": 500}) assert resp["blockhash"] is resp["block"] is None - resp = l1.rpc.call("getrawblockbyheight", {"height": 50}) + resp = node.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) - fc = l1.rpc.fundchannel(l2.info["id"], 10**4 * 3) - txo = l1.rpc.call("getutxout", {"txid": fc['txid'], "vout": fc['outnum']}) - assert (Millisatoshi(txo["amount"]) == Millisatoshi(10**4 * 3 * 10**3) - and txo["script"].startswith("0020")) - l1.rpc.close(l2.info["id"]) - # When output is spent, it should give us null ! - wait_for(lambda: l1.rpc.call("getutxout", { - "txid": fc['txid'], - "vout": fc['outnum'] - })['amount'] is None) - - resp = l1.rpc.call("sendrawtransaction", {"tx": "dummy", "allowhighfees": False}) - assert not resp["success"] and "decode failed" in resp["errmsg"] diff --git a/main.go b/main.go index 2e35c4a..a5c8ff2 100644 --- a/main.go +++ b/main.go @@ -59,6 +59,7 @@ func main() { {Name: "bitcoin-rpcport", Type: "string", Description: "Port to bitcoind RPC (optional).", Default: ""}, {Name: "bitcoin-rpcuser", Type: "string", Description: "Username to bitcoind RPC (optional).", Default: ""}, {Name: "bitcoin-rpcpassword", Type: "string", Description: "Password to bitcoind RPC (optional).", Default: ""}, + {Name: "bitcoin-datadir", Type: "string", Description: "-datadir arg for bitcoin-cli. For compatibility with bcli, not actually used.", Default: ""}, }, RPCMethods: []plugin.RPCMethod{ { @@ -131,7 +132,7 @@ func main() { Description: "Get the Bitcoin feerate in sat/kilo-vbyte.", LongDescription: "", Handler: func(p *plugin.Plugin, params plugin.Params) (resp any, errCode int, err error) { - estfees, err := getFeeRates() + estfees, err := getFeeRates(p.Network) if err != nil { p.Logf("estimatefees error: %s", err.Error()) estfees = &EstimatedFees{} diff --git a/main_test.go b/main_test.go index a5cc200..5140161 100644 --- a/main_test.go +++ b/main_test.go @@ -11,7 +11,7 @@ import ( const executable = "./trustedcoin" const getManifestRequest = `{"jsonrpc":"2.0","id":"getmanifest","method":"getmanifest","params":{}}` -const getManifestExpectedResponse = `{"jsonrpc":"2.0","id":"getmanifest","result":{"options":[{"name":"bitcoin-rpcconnect","type":"string","default":"","description":"Hostname (IP) to bitcoind RPC (optional)."},{"name":"bitcoin-rpcport","type":"string","default":"","description":"Port to bitcoind RPC (optional)."},{"name":"bitcoin-rpcuser","type":"string","default":"","description":"Username to bitcoind RPC (optional)."},{"name":"bitcoin-rpcpassword","type":"string","default":"","description":"Password to bitcoind RPC (optional)."}],"rpcmethods":[{"name":"getrawblockbyheight","usage":"height","description":"Get the bitcoin block at a given height","long_description":""},{"name":"getchaininfo","usage":"","description":"Get the chain id, the header count, the block count and whether this is IBD.","long_description":""},{"name":"estimatefees","usage":"","description":"Get the Bitcoin feerate in sat/kilo-vbyte.","long_description":""},{"name":"sendrawtransaction","usage":"tx","description":"Send a raw transaction to the Bitcoin network.","long_description":""},{"name":"getutxout","usage":"txid vout","description":"Get informations about an output, identified by a {txid} an a {vout}","long_description":""}],"subscriptions":[],"hooks":[],"featurebits":{"features":"","channel":"","init":"","invoice":""},"dynamic":false,"notifications":[]}}` +const getManifestExpectedResponse = `{"jsonrpc":"2.0","id":"getmanifest","result":{"options":[{"name":"bitcoin-rpcconnect","type":"string","default":"","description":"Hostname (IP) to bitcoind RPC (optional)."},{"name":"bitcoin-rpcport","type":"string","default":"","description":"Port to bitcoind RPC (optional)."},{"name":"bitcoin-rpcuser","type":"string","default":"","description":"Username to bitcoind RPC (optional)."},{"name":"bitcoin-rpcpassword","type":"string","default":"","description":"Password to bitcoind RPC (optional)."},{"name":"bitcoin-datadir","type":"string","default":"","description":"-datadir arg for bitcoin-cli. For compatibility with bcli, not actually used."}],"rpcmethods":[{"name":"getrawblockbyheight","usage":"height","description":"Get the bitcoin block at a given height","long_description":""},{"name":"getchaininfo","usage":"","description":"Get the chain id, the header count, the block count and whether this is IBD.","long_description":""},{"name":"estimatefees","usage":"","description":"Get the Bitcoin feerate in sat/kilo-vbyte.","long_description":""},{"name":"sendrawtransaction","usage":"tx","description":"Send a raw transaction to the Bitcoin network.","long_description":""},{"name":"getutxout","usage":"txid vout","description":"Get informations about an output, identified by a {txid} an a {vout}","long_description":""}],"subscriptions":[],"hooks":[],"featurebits":{"features":"","channel":"","init":"","invoice":""},"dynamic":false,"notifications":[]}}` const initRequest = `{"jsonrpc":"2.0","id":"init","method":"init","params":{"options":{},"configuration":{"network":"bitcoin","lightning-dir":"/tmp","rpc-file":"foo"}}}` const initExpectedResponse = `{"jsonrpc":"2.0","id":"init"}` @@ -36,12 +36,12 @@ func start(t *testing.T) (*exec.Cmd, io.WriteCloser, io.ReadCloser, io.ReadClose _, _ = io.WriteString(stdin, getManifestRequest) if response := readline(stdout); response != getManifestExpectedResponse { - t.Fatalf("unexpected RPC response: %s", response) + t.Fatalf("unexpected manifest response: %s", response) } _, _ = io.WriteString(stdin, initRequest) if response := readline(stdout); response != initExpectedResponse { - t.Fatalf("unexpected RPC response: %s", response) + t.Fatalf("unexpected init response: %s", response) } if response := readline(stderr); !strings.Contains(response, "initialized plugin") {