Open uwla opened 7 months ago
That's a pretty cool idea. No objections from me if you want to implement this.
I'll implement it. I have not done it yet, but I'll do it 👍
Hi @uwla, have you been able to work on this? I can help with that immediately if you have something else at hand.
CC @jamaljsr
Hi @uwla, have you been able to work on this? I can help with that immediately if you have something else at hand.
CC @jamaljsr
Hello. I was busy and could not do it. I think I'll be do able to implement the feature by the weekend, otherwise I'll let you know
Hi @jamaljsr and @Anyitechs.
I think I need help here, but more with the development stuff.
In the past, I was able to build Polar locally and to run the development server with hot-reload. But, I'm currently not being able to do so neither locally neither using Dev Containers. I get the following errors:
$ cross-env CI=false PUBLIC_URL=./ rescripts build
node:internal/modules/cjs/loader:575
throw e;
^
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './lib/tokenize' is not defined by "exports" in /app/node_modules/postcss-safe-parser/node_modules/postcss/package.json
at new NodeError (node:internal/errors:399:5)
at exportsNotFound (node:internal/modules/esm/resolve:261:10)
at packageExportsResolve (node:internal/modules/esm/resolve:591:9)
at resolveExports (node:internal/modules/cjs/loader:569:36)
at Module._findPath (node:internal/modules/cjs/loader:643:31)
at Module._resolveFilename (node:internal/modules/cjs/loader:1068:27)
at Module._load (node:internal/modules/cjs/loader:928:27)
at Module.require (node:internal/modules/cjs/loader:1149:19)
at require (node:internal/modules/helpers:121:18)
at Object.<anonymous> (/app/node_modules/postcss-safe-parser/lib/safe-parser.js:1:17) {
code: 'ERR_PACKAGE_PATH_NOT_EXPORTED'
}
Node.js v20.1.0
after troubleshooting, I updated Node version to the latest stable using NVM. It solved the error but I got a new one:
Creating an optimized production build...
Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:69:19)
at Object.createHash (node:crypto:138:10)
at module.exports (/app/node_modules/webpack/lib/util/createHash.js:135:53)
at NormalModule._initBuildHash (/app/node_modules/webpack/lib/NormalModule.js:417:16)
at handleParseError (/app/node_modules/webpack/lib/NormalModule.js:471:10)
at /app/node_modules/webpack/lib/NormalModule.js:503:5
at /app/node_modules/webpack/lib/NormalModule.js:358:12
at /app/node_modules/loader-runner/lib/LoaderRunner.js:373:3
at iterateNormalLoaders (/app/node_modules/loader-runner/lib/LoaderRunner.js:214:10)
at iterateNormalLoaders (/app/node_modules/loader-runner/lib/LoaderRunner.js:221:10)
at /app/node_modules/loader-runner/lib/LoaderRunner.js:236:3
at runSyncOrAsync (/app/node_modules/loader-runner/lib/LoaderRunner.js:130:11)
at iterateNormalLoaders (/app/node_modules/loader-runner/lib/LoaderRunner.js:232:2)
at Array.<anonymous> (/app/node_modules/loader-runner/lib/LoaderRunner.js:205:4)
at Storage.finished (/app/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:55:16)
at /app/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:91:9
/app/node_modules/react-scripts/scripts/build.js:19
throw err;
After more troubleshooting, I exported export NODE_OPTIONS=--openssl-legacy-provider
, which solved the error but got a new one:
$ cross-env CI=false PUBLIC_URL=./ rescripts build
Creating an optimized production build...
One of your dependencies, babel-preset-react-app, is importing the
"@babel/plugin-proposal-private-property-in-object" package without
declaring it in its dependencies. This is currently working because
"@babel/plugin-proposal-private-property-in-object" is already in your
node_modules folder for unrelated reasons, but it may break at any time.
babel-preset-react-app is part of the create-react-app project, which
is not maintianed anymore. It is thus unlikely that this bug will
ever be fixed. Add "@babel/plugin-proposal-private-property-in-object" to
your devDependencies to work around this error. This will make this message
go away.
Failed to compile.
/app/src/components/App.tsx
TypeScript error in /app/src/components/App.tsx(14,6):
'StoreProvider' cannot be used as a JSX component.
Its type 'typeof StoreProvider' is not a valid JSX element type.
Type 'typeof StoreProvider' is not assignable to type 'new (props: any, deprecatedLegacyContext?: any) => Component<any, any, any>'.
Construct signature return types 'StoreProvider<any>' and 'Component<any, any, any>' are incompatible.
The types returned by 'render()' are incompatible between these types.
Type 'React.ReactNode' is not assignable to type 'import("/app/node_modules/@types/react-dom/node_modules/@types/react/index").ReactNode'.
Type '{}' is not assignable to type 'ReactNode'. TS2786
12 | return (
13 | // store provider for easy-peasy hooks
> 14 | <StoreProvider store={store}>
| ^
15 | {/* react-redux provider for router state */}
16 | <Provider store={store as any}>
17 | {/* connected-react-router */}
This one got me stuck.
I do want to implement this feature for Polar, but I'm not being able to compile or launch a development server.
I'll try setting up a Ubuntu VM and see if I can get it to work.
If any of you can help me here, I'll appreciate it!
Make sure you're using the latest master
branch. These issues should have been resolved by #827.
I just tested with a fresh clone of the repo using node v20.9.0 and it worked for me.
Thanks @jamaljsr it worked. Now I can work on this issue. I'll try to do some work this week, and finish it in the next week, because Im kinda busy this weekend.
Hi @jamaljsr. I'm almost finishing it, but I need a tip on how to get specific information.
For context, here is the function to balance a single channel:
const balanceChannel = async (
channel: LightningNodeChannel,
localNode: LightningNode,
remoteNode: LightningNode,
satsTolerance = 100,
) => {
if (channel.status !== 'Open') {
// TODO: warn about channel not opened.
return;
}
if (remoteNode === undefined || remoteNode === null) {
// TODO: warn about remote node being null.
return;
}
const localBalance = Number(channel.localBalance);
const remoteBalance = Number(channel.remoteBalance);
const balanceDifference = localBalance - remoteBalance;
// If the balance difference in satoshis is too small, we ignore it.
if (Math.abs(balanceDifference) < satsTolerance) {
return;
}
// The source node pays an invoice to the target node, in order to balance the channel.
const src = balanceDifference > 0 ? localNode : remoteNode;
const target = balanceDifference > 0 ? remoteNode : localNode;
const invoice = await getNodeLightningService(target).createInvoice(
target,
balanceDifference,
);
await getNodeLightningService(src).payInvoice(src, invoice);
};
Notice we need the remoteNode
because it creates the invoice.
Here is how the AutoBalanceButton
currently looks like:
const AutoBalanceButton: React.FC<Props> = ({ network }) => {
const handleClick = async () => {
const lnNodes = network.nodes.lightning;
const channels = {} as { [key: string]: ChannelInfo };
for (const node of lnNodes) {
const lightningService = getNodeLightningService(node);
const nodeChannels = await lightningService.getChannels(node);
for (const channel of nodeChannels) {
const { uniqueId } = channel;
// Add the channel, using current node as local node.
if (!Object(channels).hasOwnProperty(uniqueId)) {
channels[uniqueId] = {
channel: channel,
localNode: node,
} as ChannelInfo;
} else {
// Channel already exists, so current node is treated as remote node.
channels[uniqueId].remoteNode = node;
}
}
}
await autoBalanceChannels(Object.values(channels));
};
return <Button onClick={handleClick}>Auto Balance channels</Button>;
};
It is not working because the method getChannels
of the interface LightningService
will only return the outgoing channels, not the ingoing channels. Due to this, I cannot assign the remoteNode
to the ChannelInfo
(whose interface is { channel: Channel, localNode: LightningNode, remoteNode: LightningNode }
) because the channels array is empty and I cannot loop over it.
Can you tell me which function, class or methdo I can use to get the LightningNode
remote node of a LightningChannel
channel ?
Yes, the LightningService
will only return the channels that were opened by the supplied node. This was the simpler approach to avoid creating duplicate links in the chart. There is an existing function (updateChartFromNodes) that uses the data from the lightning store to recreate the nodes & links in the chart based on the currently opened channels. I'd imagine that you could do something very similar to balance the channels. By only looking at the outbound channels for each node, you can be sure that you only balance each channel once. If you got all of the channels for each node, then you'd need to keep track of which channels you've already balanced or ensure that the channel balances were continually updated after each iteration.
I hope this helps, but let me know if you have more questions.
Is your feature request related to a problem? Please describe. Yes, the problem is: sometimes we need balanced channels to do some stuff while testing and developing locally, but balancing them manually takes precious time.
Describe the solution you'd like A button that we can click and have the channels balanced automatically (in the background by polar).
Suggestion
Here is a pseudo-code to balance the channels:
I can try do this, but some guidance is welcomed