Giter Club home page Giter Club logo

clightning4j / jrpclightning Goto Github PK

View Code? Open in Web Editor NEW
16.0 5.0 9.0 1.48 MB

:zap: Java framework for C-Lightning to work with the RPC interface, and also the library simplifies the work to develop custom plugins with Java, Kotlin, and all the languages that supports the Java dependencies :zap:

Home Page: https://clightning4j.github.io/JRPClightning/

License: GNU General Public License v2.0

Java 98.37% Dockerfile 0.36% Shell 1.27%
lightning lightning-network c-lightning wrapper bitcoin rpc-wrapper command-wrapper hacktoberfest

jrpclightning's People

Contributors

benthecarman avatar ev-john avatar francescofact avatar hsteinmueller avatar mhechavarria avatar theborakompanioni avatar vincenzopalazzo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

jrpclightning's Issues

Divide the project into submodule to support also Android, deadline unsettled

We could divide the module into different submodules, and here are the following for the moment

  • utils: Contains all the JSON converted and socket interface (only the interface)
  • RPC: contains all the socket implementation, and five a ClightningRPC implementation access, (we could support also android)
  • plugin: Contains all the interfaces to developing a plugin for c-lightning

feat: support multiple classes extending `CLightningPlugin`

Currently, and if I am not mistaken, the library only supports a single Plugin class on the whole classpath.
In some cases it is desirable to have multiple classes extending CLightningPlugin, even if only one is actually active (by invoking start()).

The reasons seems to be that CLightningPlugin#registerMethod collects all classes containing any of the annotations (Subscription, Hook, etc.) and subsequently tries to invoke it on the currently active plugin object, even if it might not have the method defined itself.

I assume the plugin still works and will just report false or duplicate information in the getmanifest response.
Would it be desirable to report the correct information and support multiple classes?

disable or rewrite the flacky test

Recent integration testing show that there is something wrong with this test, so we should diable it or fix it

jrcplightning_1  |   Test testCommandConnectAndCloseOne FAILED
jrcplightning_1  | 
jrcplightning_1  |   junit.framework.AssertionFailedError: Error when running the command FUNDCHANNEL.
jrcplightning_1  |   Error inside command with error code: 304
jrcplightning_1  |    Message: Still syncing with bitcoin network 
jrcplightning_1  |    listfunds -> {"outputs":

Refactoring TestCLightningRPC class

As mentioned in the issue #13 it would be nice to have a version that contains the same refactoring of the class CLightningRPC in the test class.

Maybe it is good to subdivide the test into the following section

  • Network
  • Bitcoin
  • ecc (look lightning-cli help commands division)

Exception Refactoring

The exception inside the library needs a little refactoring and more improvements.

P.S: The exception inside the plugin need to use the log to print the message to lightningd console or debug file

Make the Snapshot version available on maven

When the plugin is developed with the dev version of it is difficult to compile the library with a different version of JDK.

A solution is to make available a snapshot of the master branch available on maven

Make a lite interface of the ClightnigRPC

The core is that we can avoid mixing the code where there is a generic method that returns a Java object and not a generic method that returns a not java object, but a JSON payload or gives the possibility to fill a java obj with a JSON content.

Fixed typo error without break the API of the library

I'm a very bad person when it is the moment to write things, and my library contains a lot of typos.

If someone wants to contribute to this repository, you can start to read the code, and maybe fix some typos. However, this repository is used in a big project like JMars where the solidity of the API is more important than the typos.

The change of the API can be discussed in the discussion section.

If you want assigned this issue, please leave a comment below

Good luck :)

build: remove logback.xml from release jar

The current jar includes a logback configuration file.

If a downstream consumer also defines a logback.xml, logback will complain about it on stdout, which makes cln killing the plugin. This happens even with <root level="OFF"> and no console appender defined.

11:19:14,443 |-INFO in LoggerContext[default] - Found resource [logback.xml] at [file:/home/user/workspace/tapplication/build/resources/main/logback.xml]
11:19:14,443 |-WARN in LoggerContext[default] - Resource [logback.xml] occurs multiple times on the classpath.
11:19:14,444 |-WARN in LoggerContext[default] - Resource [logback.xml] occurs at [jar:file:/home/user/workspace/application/libs/jrpclightning-0.2.4-SNAPSHOT.jar!/logback.xml]
11:19:14,444 |-WARN in LoggerContext[default] - Resource [logback.xml] occurs at [file:/home/user/workspace/application/build/resources/main/logback.xml]

Context: https://stackoverflow.com/questions/3401051/suppress-all-logback-output-to-console
Also: https://mailman.qos.ch/pipermail/logback-user/2010-August/001717.html

Logback only outputs its status messages when there is a warning or error - in this case Logback thinks that you have two logback.xml files on the classpath.

An additional side effect is that a clightning4j dir is created in the users home directory.
Would it be possible to exclude the logback.xml file in the release builds?

Missing listfunds method with parameters

The list funds accept optional parameters, and the library missing this method here

CLightningListFounds result = CLightningRPC.getInstance().listFunds(closed);

Make a wrapper of RPC method parameters

it could be a good improvement to add a native RPC method parameters passed inside the request

Now in the code, I need to do the following stuff

val listParamter = request["params"].asJsonArray.toList()

With koltin it is a goof but with java some additional check is needed

Refactoring CLightningRPC

The class CLightningRPC is too big and it is not readble, maybe it is better to divide the method in a class with different files, such as BitcoinCommands, NetworksCommand, and use the CLightningRPC only as a mediator.

retype the filed from msat from String to int

The change implemented in the PR ElementsProject/lightning#5306 happens from the next release, so the solution is to break the type and move all msat filed from String to integer.

We need to decide only if we want to support both or just the last version, commenting on the PR if you want discuss it before stat to working on it

With command invoice the object CLightningInvoice have some null propriety!

{
  "jsonrpc": 2.0,
  "id": 11,
  "result": {
    "payment_hash": "7707b76fad49b89d6a5402680203a90734aec85b28da0f0ae3ac6019cd4b97b7",
    "expires_at": "1600034700",
    "bolt11": "lntb10n1p042hgvpp5wurmwmadfxuf66j5qf5qyqafqu62ajzm9rdq7zhr43spnn2tj7msdqjv3jhxcmjd9c8g6t0dcxqyjw5qcqp2sp5a8m5mpv0nkx7f7x4qgr6wquzexhe920xqpkf3n8av60r26shjrts9qy9qsq6g3jse4920uvve2t8jhd9nr74zr2yq5m2663vd0pxz5k0lfczy5p9xfwjjd2alvps9jr5tdqdvng2vx3wzpm9vq0v3mqy03lpl6dqgcp9ynjp2",
    "warning_capacity": "No channels"
  }
}
00:05:00.266 [Test worker] DEBUG jrpc.clightning.TestCLightningRPC - invoice: lntb10n1p042hgvpp5wurmwmadfxuf66j5qf5qyqafqu62ajzm9rdq7zhr43spnn2tj7msdqjv3jhxcmjd9c8g6t0dcxqyjw5qcqp2sp5a8m5mpv0nkx7f7x4qgr6wquzexhe920xqpkf3n8av60r26shjrts9qy9qsq6g3jse4920uvve2t8jhd9nr74zr2yq5m2663vd0pxz5k0lfczy5p9xfwjjd2alvps9jr5tdqdvng2vx3wzpm9vq0v3mqy03lpl6dqgcp9ynjp2

junit.framework.AssertionFailedError
	at junit.framework.Assert.fail(Assert.java:55)
	at junit.framework.Assert.assertTrue(Assert.java:22)
	at junit.framework.Assert.assertNotNull(Assert.java:256)
	at junit.framework.Assert.assertNotNull(Assert.java:248)
	at junit.framework.TestCase.assertNotNull(TestCase.java:417)
	at jrpc.clightning.TestCLightningRPC.testCommandGetInvoiceFour(TestCLightningRPC.java:106)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
	at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:119)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
	at java.base/java.lang.Thread.run(Thread.java:830)

Given a method to pass the rpc wrapper to the startup

Before with the singleton, the library is able to gen the correct path of the lightning socket at any time, if we remove it in some of the next releases we need to think about how the plugin can have an rpc call inside itself.

Refactoring class CLightningRPC

I noted that my mind has a bug, in fact when I have started to design the java RPC wrapper I choose to use the mediator pattern and create a query string with a library rules, such as the example below.

public CLightningPay pay(String bolt11, String satoshi, String label, float riskFactor, String maxFeePercent, int retryFor, String maxDelay) {
        if (bolt11 == null || bolt11.trim().isEmpty()) {
            throw new CLightningException("The method pay have the parameter bolt11 is null or empty");
        }
        if (satoshi == null) {
            throw new CLightningException("The method pay have the parameter satoshi is null");
        }
        if (label == null) {
            throw new CLightningException("The method pay have the parameter label is null");
        }
        if (maxFeePercent == null) {
            throw new CLightningException("The method pay have the parameter maxFeePercent is null");
        }
        if (maxDelay == null) {
            throw new CLightningException("The method pay have the parameter maxDelay is null");
        }

        StringBuilder payload = new StringBuilder();
        payload.append("bolt11=").append(bolt11);
        if (!satoshi.trim().isEmpty()) {
            payload.append(JOIN_TOKEN_PROP).append("satoshi=").append(satoshi);
        }

        if (!label.trim().isEmpty()) {
            payload.append(JOIN_TOKEN_PROP).append("label=").append(label);
        }

        payload.append(JOIN_TOKEN_PROP).append("riskfactor=").append(riskFactor);

        if (!maxFeePercent.trim().isEmpty()) {
            payload.append(JOIN_TOKEN_PROP).append("maxfeepercent=").append(maxFeePercent);
        }

        payload.append(JOIN_TOKEN_PROP).append("retry_for=").append(retryFor);

        if (!maxDelay.trim().isEmpty()) {
            payload.append(JOIN_TOKEN_PROP).append("maxDelay=").append(maxDelay);
        }

        String payloadString = payload.toString();
        CLightningLogger.getInstance().debug(TAG, "Payload for pay connect is: " + payloadString);
        CLightningPay pay = (CLightningPay) mediatorCommand.runCommand(Command.PAY, payloadString);
        return pay;
    }

But, I noted that there is a method more but more simple, it is to create the HashMap<String, Object> payload and pass this object to the mediator. With this refactoring the code is cleaner.

Example with refactoring

ublic CLightningGetRoutes getRoute(String id, String mSatoshi, float riskFactor, int cltv,
                           String fromid, String fuzzpercent, int maxHope, ExcludeChannel... exclude){
        doCheckString("getRoute", "id", id, false);
        doCheckString("getRoute", "mSatoshi", mSatoshi, false);
        doCheckString("getRoute", "fromid", fromid, true);
        doCheckString("getRoute", "fuzzpercent", fuzzpercent, true);
        doCheckPositiveNumber("getRoute", "riskFactor", riskFactor);
        doCheckPositiveNumber("getRoute", "cltv", cltv);
        doCheckPositiveNumber("getRoute", "maxHope", maxHope);

        HashMap<String, Object> payload = new HashMap<>();

        payload.put("id", id);
        payload.put("msatoshi", maxHope);
        payload.put("riskfactor", riskFactor);
        payload.put("cltv", cltv);
        payload.put("maxhope", maxHope);

        if(!fromid.isEmpty()){
            payload.put("fromid", fromid);
        }

        if(!fuzzpercent.isEmpty()){
            payload.put("fuzzpercent", fuzzpercent);
        }

        if(exclude.length > 0){
            payload.put("exclude", exclude);
        }
        return (CLightningGetRoutes) mediatorCommand.runCommand(Command.GETROUTE, payload);
    }

Update APi in the readme

I wrote the readme a lot of time ago, and I'm a very bad people to make this task.

I discovered that the API about the log level is old, we need to change it from

   @RPCMethod(
            name = "annotation_hello",
            description = "Annotation plugin"
    )
    public void hello(CLightningPlugin plugin, CLightningJsonObject request, CLightningJsonObject response) {
        log(CLightningLevelLog.WARNING, request.toString());
        response.add("type", "random");
    }

To

   @RPCMethod(
            name = "annotation_hello",
            description = "Annotation plugin"
    )
    public void hello(CLightningPlugin plugin, CLightningJsonObject request, CLightningJsonObject response) {
        log(PluginLog.WARNING, request.toString());
        response.add("type", "random");
    }

Brainstorming things that a must have in this lib

When I start this project I taken some decisions that today I will never take again, some of them are:

  • Use a singleton instance, this break the possibility to use DI library with the class
  • Create the java version of each command, (I should be used the reflection to make the job)
  • Divided the library into two modules, one is the RPC module with all the RPC calls and JSON calls, and the other one is the plugin module and will create an internal instance of the RPC class.
  • Avoid mixing the structured class with a generic method like rawCall, I would like to have a different class, like LiteCLightningRpc(rpc_path), and ClightninRPC(rpc_path).

I would like to implement some of these changes, like

  • LiteClightningRpc(rpc_path) as first, that implements an interface like the lite-bitcoin-rpc. Deadline version 0.2.3 #62
  • Remove the singleton instance from the library, deadline version 0.3.0 #60
  • Divide the project into submodule to support also Android, deadline unsettled #61

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.