We now support splicing on public channels: once the splice transaction
is confirmed and locked on both sides, nodes will exchange announcement
signatures that allows them to create a `channel_announcement` that they
then broadcast to the network.
This requires reworking the data model to include the announcement and
the real `short_channel_id` in each commitment, which lets us cleanly
distinguish real `short_channel_id`s from aliases (which are set at the
channel level regardless of the current commitments).
The flow now becomes:
- when the funding transaction of a commitment confirms, we set the
corresponding real `short_channel_id` in that commitment
- if the channel is public and we've received `channel_ready` or
`splice_locked`, we send our `announcement_signatures`
- if we receive `announcement_signatures` for a commitment for which
the funding transaction is unconfirmed, we stash it and replay it
when the transaction confirms
- if we receive `announcement_signatures` for a confirmed commitment,
and we don't have a more recently announced commitment, we generate
a `channel_announcement`, store it with the commitment and update
our router data
When creating a `channel_update` for a public channel, we always use
the `short_channel_id` that matches the latest announcement we created.
This is very important to guarantee that nodes receiving our updates
will not discard them because they cannot match it to a channel.
For private channels, we stop allowing usage of the `short_channel_id`
for routing: `scid_alias` MUST be used, which ensures that the channel
utxo isn't revealed.
Note that when migrating to taproot channels, `splice_locked` will be
used to transmit nonces for the announcement signatures, which will be
compatible with the existing flow (and similarly, `channel_ready` will
be used for the initial funding transaction). They are retransmitted
on reconnection to ensure that the announcements can be generated.
Now that we wait for at least 6 confirmations before considering a
channel confirmed, we can simplify our channel announcement logic.
Whenever a channel reaches the confirmed state, it can be announced
to the network (if nodes wish to announce it). We thus don't need
the "deeply buried" state and the "temporary" scid anymore.
The logic is much simpler to follow: when the channel confirms, we
internally update the real scid to match the confirmed funding tx
and send our `announcement_signatures`. When we receive our peer's
`announcement_signatures`, we stash them if the funding tx doesn't
have enough confirmations yet, otherwise we announce the channel and
create a new `channel_update` that uses the real scid.
Whenever we create a `channel_update`, we simply look at whether the
channel is announced or not to choose which scid to use.
This will make it much simpler to announce splice transactions, which
don't need a "deeply buried" state either and will instead simply rely
on whether the splice transaction is confirmed or not to generate
`announcement_signatures`.
* Update kamon and kanela-agent
Previous version was not compatible with JDK21, see https://github.com/kamon-io/kanela/issues/150.
* Add and configure maven wrapper to use maven 3.9.9
This will make it easier to control which version of maven is used to build eclair, which in turns makes deterministic builds easier, as well as using recent compiler options (to target newer JDKs for example).
For example, even recent versions of Github runner images use an old version of maven and there is no easy way to upgrade.
* Update Dockerfile
We now use multiarch (amd64/arm64) base images.
* Run CI tests with JDK21
* Update doc to recommend Adoptium OpenJDK21
* Target Java 21
Eclair now targets Java 21 and will require a compatible Java Runtime Environment.
It will no longer work on JRE 11 and JRE 17.
We previously supported sending arbitrary trampoline payments in eclair,
which added a bunch of complexity to many of our payment components.
This was necessary because the first version of Phoenix was based on the
eclair codebase. But Phoenix isn't based on eclair anymore and is now
using https://github.com/acinq/lightning-kmp, which is the library that
mobile wallets should use.
Eclair is only meant to be used for server nodes that relay payments and
have access to the full network graph, so it doesn't make sense ever to
send trampoline payments (full source-routing will always be better). We
thus refactor our trampoline client code to only be used for tests (to
ensure that trampoline relay and trampoline receive are implemented
correctly). We isolate the test payment lifecycle in a dedicated actor
(`TrampolinePaymentLifecycle`) which simplifies other payment components
(such as `PaymentInitiator`).
This refactoring will make it easier to support the official version of
trampoline while maintaining backwards-compatibility for older Phoenix
wallets that use the non-official trampoline version.
If the latest splice transaction doesn't confirm, we allow exchanging
`tx_init_rbf` and `tx_ack_rbf` to create another splice transaction to
replace it. We use the same funding contribution as the previous splice.
When 0-conf isn't used, we reject `splice_init` while the previous
splice transaction hasn't confirmed. Our peer should either use RBF
instead of creating a new splice, or they should wait for our node
to receive the block that confirmed the previous transaction. This
protects against chains of unconfirmed transactions.
When using 0-conf, we reject `tx_init_rbf` and allow creating chains of
unconfirmed splice transactions: using RBF with 0-conf can lead to one
side stealing funds, which is why we prevent it.
If our peer was buying liquidity but tries to cancel the purchase with
an RBF attempt, we reject it: this prevents edge cases where the seller
may end up adding liquidity to the channel without being paid in return.
When providing on-the-fly funding with the `from_future_htlc` payment
type, the liquidity provider is paying mining fees for the funding
transaction while trusting that the remote node will accept the HTLCs
afterwards and thus pay a liquidity fees. If the remote node fails the
HTLCs, the liquidity provider doesn't get paid. At that point it can
disable the channel and try to actively double-spend it. When we detect
such behavior, we immediately disable `from_future_htlc` to limit the
exposure to liquidity griefing: it can then be re-enabled by using the
`enableFromFutureHtlc` RPC, or will be automatically re-enabled if the
remote node fulfills the HTLCs after a retry.
* Add `on_the_fly_funding` feature bit and messages
Add the (disabled by default) `on_the_fly_funding` feature bit and
codecs for the corresponding messages:
- `will_add_htlc`
- `will_fail_htlc`
- `will_fail_malformed_htlc`
- `cancel_on_the_fly_funding`
We also add a TLV to `update_add_htlc` to notify the recipient that we
relayed less data than what the onion encodes, in exchange for the fees
of the specified funding transaction.
* Add `non_initiator_pays_commit_fees` channel flag
We add a non-standard channel flag to `open_channel2` to allow wallets
to ask their peer to pay the commit tx fees, even when they're not the
channel opener. This is necessary for on-the-fly funding, until we can
move to 0-fee commit txs which will make it obsolete.
* Allow underpaying feerate when using future HTLCs
When an interactive-tx session is created for a liquidity purchase that
uses future HTLCs to pay fees, the initiator may not have enough funds
to honor the target feerate. We allow the transaction anyway, because
we want to get paid for the liquidity we're providing. If the feerate
is too low and the transaction doesn't confirm, we can double-spend it
if we need that liquidity elsewhere.
* Add `funding_fee` field to `CMD_ADD_HTLC`
This commit adds the funding fee field to HTLCs, but never sets it.
We update a lot of test files, but there is no functional change.
* Implement on-the-fly funding
Implement the on-the-fly funding protocol: when a payment cannot be
relayed because of a liquidity issue, we notify the `Peer` actor that
we'd like to trigger on-the-fly funding if available. If available, we
we send a funding proposal to our peer and keep track of its status.
Once a matching funding transaction is signed, we persist this funding
attempt and wait for the additional liquidity to be available (once the
channel is ready or the splice locked). We will then frequently try to
relay the payment to get paid our liquidity fees. If the payment keeps
getting rejected, or we cannot connect to our peer, we abandon the
payment when it reaches its CLTV expiry, which ensures that the upstream
channels are not at risk.
When using on-the-fly funding, we use a single channel with our peer.
If they try to open another channel while one is available, we reject
their request and expect a splice instead.
* Add support for extensible liquidity ads
The initiator of `open_channel2`, `tx_init_rbf` and `splice_init` can
request funding from the remote node. The non-initiator node will:
- let the open-channel-interceptor plugin decide whether to provide
liquidity for new channels or not, and how much
- always honor liquidity requests on existing channels (RBF and splice)
when funding rates have been configured
Liquidity ads are included in the `node_announcement` message, which
lets buyers compare sellers and connect to sellers that provide rates
they are comfortable with. They are also included in the `init` message
which allows providing different rates to specific peers.
This implements https://github.com/lightning/bolts/pull/1153. We
currently use the temporary tlv tag 1339 while we're waiting for
feedback on the spec proposal.
* Add `channelCreationFee` to liquidity ads
Creating a new channel has an additional cost compared to adding
liquidity to an existing channel: the channel will be closed in the
future, which will require paying on-chain fees. Node operators can
include a `channel-creation-fee-satoshis` in their liquidity ads to
cover some of that future cost.
* Add liquidity purchases to the `AuditDb`
Whenever liquidity is purchased, we store it in the `AuditDb`. This lets
node operators gather useful statistics on their peers, and which ones
are actively using the liquidity that is purchased.
We store minimal information about the liquidity ads itself to be more
easily compatible with potential changes in the spec.
When nodes only have private channels, they must include routing hints
in their Bolt 11 invoices to be able to receive payments. We add a
parameter to the `createinvoice` RPC for this. Note that this may leak
the channel outpoint if `scid_alias` isn't used.
Fixes#2802
The channel initiator traditionally pays the commit tx fees, but we may
want to override that when providing services to wallet users. We thus
split the current `isInitiator` flag into two flags:
- `isChannelOpener`
- `paysCommitTxFees`
We always set `paysCommitTxFees` to the same value as `isChannelOpener`.
Custom feature bits may override that behavior if necessary.
Note that backwards compatibility is preserved since our previous `bool8`
codec encodes `true` as `0xff` and `false` as `0x00`.
To save space in the offer, we can skip the node id for offers that use blinded paths.
The node id used to sign the invoice will be the last blinded node id of the path used to request the invoice.
We also make the description optional for offers without amount.
Allow sending messages to self
Fixes corner cases caused by compact encoding of node ids. Every message to be relayed now follows the same path and `MessageRelay` can relay to self.
When opening an important channel we may be willing to pay a high feerate that we wouldn't want to use when consolidating UTXOs. However because we delegate the transaction creation to bitcoin core, we can sometimes be surprised by funding transactions that are much bigger than expected. This PR protects us from such cases by refusing to open the channel if the transaction fee is too high.
Based on original work from @thomash-acinq.
This version of logback fixes the following CVE:
"a potential denial of service attack on a centralized logback receiver
when a third party controlling a remote appender connects to said
receiver and could shut down or slow down logging of events."
Eclair isn't affected since we don't use logback receivers, but if there
are applications or plugins that depend on eclair and use logback
receivers, it's better to use the logback version containing the fix.
* Make Eclair manage bitcoin core's wallet private keys
We create an empty watch-only wallet and import public descriptors generated by Eclair.
Bitcoin Core can fund transaction and manage utxos, but can no longer sign transactions.
* Check that spent amounts and utxos are consistent before we sign a PSBT
PSBT utxo fields include the amount that are being spent by the PSBT inputs, but there is a "fee attack"
where using amounts that are lower than what is actually spent may make us sign a tx that spends much more
in fees than we think.
* Check that non-segwit uxto has been provided and inputs are signed with SIGHASH_ALL
* Verify that Bitcoin Core's fee match what we specified
When we call Bitcoin Core's `fundrawtransaction` RPC method, we check that the fee that we pay match the fee rate that we requested.
The fee is computed using the utxo information that Bitcoin Core adds to our PSBT before we sign it.
We can safely used this information because if Bitcoin Core lies about the value of the inputs that we're spending then the signature we produce will also not be valid (it commits to the value being spent).
When we're adding wallet inputs to "bump" the fees of a parent transaction we need to take the whole package into account when we verify the actual fee rate, which is why some internal methods were modified to return the package weight that was used as reference when `fundrawtransaction` was called.
* Check that fundrawtransaction does not add more than 1 change output
* Validate addresses and keys generated by bitcoin core
When eclair manages private keys, make sure that we can re-compute addresses and keys
generated by bitcoin core.
* Add a separate configuration file for Eclair's onchain signer
Eclair's onchain signer now has its own `eclair-signer.conf` configuration file in HOCON format.
It includes BIP39 mnemonic codes and passphrase, a wallet name and a timestamp.
When an `eclair-signer.conf` file is found, Eclair's API will return descriptors that can be imported into an
empty watch-only Bitcoin Wallet.
When wallet name in `eclair-signer.conf` matches the name of the Bitcoin Core wallet defined in `eclair.conf`
(`eclair.bitcoind.wallet`), Eclair will bypass Bitcoin Core and sign onchain transactions directly.
* Skip validation of local non-change outputs:
Local non-change outputs send to an external address, for splicing out funds for example.
We assume that these inputs are trusted i.e have been created by a trusted API call and our local
onchain key manager will not validate them during the signing process.
* Document why we use a separate, specific file for the onchain key manager
Using a new signer section is eclair.conf would be simpler but "leaks" because it becomes available everywhere
in the code through the actor system's settings instead of being contained to where it is actually needed
and could potentially be exposed through a bug that "exports" the configuration (through logs, ....)
though this is highly unlikely.
* Additional changes to delegate bitcoin core keys to eclair (#2726)
Refactor the `BitcoinCoreClient` and `LocalOnChainKeyManager` to:
- rely less on exceptions
- use more idiomatic scala (reduce dependency on kotlin types)
- provide more detailed logs
We also simplify the `useEclairSigner` field in `BitcoinCoreClient`.
The complexity of handling the case where there was an on-chain key
manager but for a different wallet than the one configured isn't
something that should be used, so it wasn't worth supporting.
Some checks were inconsistent and are now unified:
- checking the exact `scriptPubKey` in our outputs in TODO and TODO
- we allow using `fundTransaction` with a tx that already includes a
change output (which may happen when RBF-ing a transaction)
- `getP2wpkhPubkeyHashForChange` didn't verify the returned key
We completely separate the two cases in `signPsbt`, because otherwise
in the non eclair-backed case, we were calling bitcoind's `processpsbt`
twice for no good reason, which is bad for performance.
We also decouple the `OnChainKeyManager` from the `BitcoinCoreClient`.
This lets users keep running their eclair node with a bitcoin client that
owns the private key while configuring the on-chain key manager for a
future bitcoin client that will leverage this on-chain key manager.
Users can use the eclair APIs to get the master xpub and descriptors to
properly configure their next bitcoin core node, and switch to it once it
has synchronized the descriptors.
* Simplify replaceable tx funding
We were previously signing twice (with makes a call to `bitcoind`),
just to get the final weights and adjust the change outputs. This was
unnecessary, as we can adjust the weights before adding inputs.
We were also duplicating the checks where we verify that `bitcoind` is
malicious. We only need to check that once, during the final signing step.
---------
Co-authored-by: Bastien Teinturier <31281497+t-bast@users.noreply.github.com>
Node operators may disable automatic fee-bumping on their local commit if
they don't have anything at stake (no pending HTLCs), which saves fees in
most cases. A drawback in that case is that if the commitment doesn't
confirm quickly enough, the remote's funds are also locked.
This can be an issue for LSPs, where the remote peer doesn't have a good
ability to fee-bump commit txs. We give more control to the node operator
by letting them fee-bump local commit txs explicitly through the RPC to
unblock wallet users funds.
* Update code dependencies
I also wanted to update logback, but I'm hitting issues because of our
custom logger in `FixtureSpec` (`LoggingEventAware` not found).
* Update build dependencies
We're now using mvn 3.9.2 to build eclair, which reports warnings in some
of the build plugins we use. Updating plugins fixes most of the warnings,
and the remaining warnings have to be fixed by the plugins themselves
to support mvn 4.x.
For fighting jamming attempts, or even just to detect one, we need to know how fast relayed HTLCs are fulfilled. We now measure this and store it in the audit database. Previously the "IN" and "OUT" directions for the same HTLC were storing the same timestamp (corresponding to when the HTLC is fulfilled), we now use the timestamp at which we received the UpdateAddHtlc for the "IN" direction.
When sending a message, the postman can now ask the router to find a route using channels only.
The same route is also used as a reply path when applicable.
The graph data structure has been updated to include both active and disabled edges.
The graph now contains features for vertices.
This RPC allows to access the historic channel data without
relying on third party services like LN explorers.
Note that when the `remoteNodeId` filter is not provided, this
query may be expensive on nodes with a lot of closed channels.
We add a `cpfpbumpfees` API that lets node operators bump the fees
of a package of unconfirmed transactions.
Node operators can for example ensure their funding txs confirm before
they hit the `2016` funding timeout. It's also very useful when you have
a long chain of unconfirmed funding transactions and/or mutual close
transactions and want to bump them all at once.
NB: the node operator needs to figure out which outpoints belong to him
(which should be fairly easy using existing APIs).
Included doc folder in the assembly zip. ** wildcard indicates all the files in the current folder and all the files in the subfolders of the current folder.
Fixes#1645
We now reject onion message payloads that contain unexpected fields and classify final payloads as being either an invoice request, an invoice response, an error or an invalid payload.
Each of these cases are mutually exclusive, it is not allowed to send both an invoice request and an invoice at the same time for instance.
Invalid payloads are not dropped immediately so that if they are the response we were waiting for, we can stop waiting and return an error without retrying.
Add support for both splice-in and splice-out in Eclair. Mixing concurrent local/remote splice-in/splice-out is wired, although not supported in the API.
The implementation differs from the current wip BOLT proposal on at least the following points:
- we use a poor man's _quiescence_ protocol which just rejects the splice if the channel is not idle
- splice txs always _spend_ the previous funding/splice tx, even if it isn't confirmed yet and could theoretically be RBFed. This is done to be compatible with zero-conf splices
- the persistence/reconnection follows the logic described in https://gist.github.com/t-bast/1ac31f4e27734a10c5b9847d06db8d86.
We add a new `fundingTxIndex` to `Commitment`, which has two nice advantages:
- making debug much easier compared to dealing with txid:
`splice=1 is now active, removed=0 remaining=2,1`
- allowing to discriminate between initial funding, splices, rbf, and
combinations thereof.
We closely mimick RBFing the initial funding tx (e.g. `RbfStatus` vs `SpliceStatus`).
---------
Co-authored-by: Bastien Teinturier <31281497+t-bast@users.noreply.github.com>
Main behavior changes (see commit messages for details):
- channel opening errors are returned with a 200/OK status from the api
- we return a success in the case of dual-funding or rbf, if the interactive tx has completed, even if the publish fails
- for rbf, we send the success response later in the flow: only when the rbf flow is successful, as opposed to when we initiate it
This is a prerequisite to splices, but also a first step towards reworking the channel request/response mechanism.
Co-authored-by: Bastien Teinturier <31281497+t-bast@users.noreply.github.com>
Each RBF attempt adds more data that we need to store and process,
so we want to limit our peers to a reasonable use of RBF.
We send a warning to let them know that they are close to reaching the
limits.
The order of the elements in a TLV stream is an implementation detail that will disappear with serialization. Equality between TlvStream shouldn't depend on this order.
For that we use `Set`s instead of `Iterable`s.
To avoid bash interpreting '&' as background job metacharacter,
properly quote the string containing it.
Otherwise you get output like the following:
eclair-node[3517981]: No java installations was detected.
eclair-node[3518011]: Please go to https://adoptopenjdk.net/?variant=openjdk11
eclair-node[3518012]: /usr/bin/eclair-node: line 285: and: command not found
* Add ChannelOpened event
Emit an event when a channel is opened and ready to process payments.
This event is distinct from the `ChannelCreated` event which is sent
earlier, once we think a funding transaction has been successfully created
(but cannot guarantee when we're not the initiator).
* Add event to websocket
This is a breaking change, but it should be ok since the previous event
wasn't reliable: it was emitted at a time where we couldn't guarantee
that the channel would really confirm.
We add an actor that waits for a given peer to be connected and ready to
process payments. This is useful in the context of async payments for
the receiver's LSP.