1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-03-13 19:37:35 +01:00
Commit graph

756 commits

Author SHA1 Message Date
Pierre-Marie Padiou
d38f227b42
Added copyright notice to all files (#497)
* added copyright notice to all files

* updated date in LICENSE
2018-03-21 16:29:42 +01:00
dpad85
36b0b223b0 Back to snapshot 2018-03-20 16:06:01 +01:00
dpad85
eed7038635 set version to 0.2-android-alpha14 2018-03-20 10:48:51 +01:00
pm47
3a6cd31aa8
Merge branch 'wip-routing-sync' into wip-android 2018-03-19 13:02:24 +01:00
pm47
1754bf0933
back to SNAPSHOT 2018-03-16 17:05:58 +01:00
pm47
99df38db8d
merged from master, set version to 0.2-android-alpha13 2018-03-15 20:56:19 +01:00
pm47
dbb4f5b467
set version to 0.2-alpha11 2018-03-15 19:41:53 +01:00
Dominique
3d48ec871e
Improved handling of timeouts in API and GUI (#484)
Both the GUI and the API should handle AskTimeoutException failures as
specific cases: GUI should ignore them, API should print a pretty
response. Increased ask timeout to 60s.

Akka http server responses with the same format as other errors.
Fixes #414 where eclair-cli would fail to parse the server
timeout response.
2018-03-15 19:33:12 +01:00
pm47
f1b079504d added basic support for textui 2018-02-21 18:47:59 +01:00
pm47
2f43e3bff9 Merge branch 'master' into wip-android 2018-02-16 19:24:22 +01:00
pm47
1b247ae613 back to SNAPSHOT 2018-02-16 18:10:35 +01:00
pm47
0beca13b23 set version to 0.2-alpha10 2018-02-16 17:28:01 +01:00
Pierre-Marie Padiou
b91e90783f
Replaced LoggingFSM -> FSM (#439)
And changed akka default log level from `DEBUG` to `INFO`.
2018-02-16 16:51:10 +01:00
Pierre-Marie Padiou
f3b746643d
Use TCP pull mode (#422)
We now use [akka tcp pull mode](https://doc.akka.io/docs/akka/2.5.3/scala/io-tcp.html#read-back-pressure-with-pull-mode) for both incoming and outgoing connections.

In combination with setting a relatively low value for `akka.io.tcp.max-received-message-size`, this results in less RAM consumption, in particular when validating a whole routing table.

Also improved the router:
- Removed the grouping of `channel_announcement` because batching is done lower in the stack, in the bitcoin json-rpc client. Channels are now validated as they arrive.
- Keep track of all origin peers for every announcement (instead of the first one), in order not to send back the same announcements to peers.
- Better choice of data structures, which increases constant time operation (but don't completely eliminate less efficient access)
- Reworked management of private/not-yet-announced channels
2018-02-16 15:49:34 +01:00
Dominique
0416784f08 TCPException message error should be defined (#401)
* TCPException sets a message when extending RuntimeException

If no message was set for the exception, a 'null' message was displayed to
the user when TCPException is thrown. Instead, we now display the exception class name.

This fixes #399.
2018-02-12 15:33:29 +01:00
pm47
56ef710f06 back to SNAPSHOT 2018-01-23 19:11:06 +01:00
pm47
951bcc4750 set version to 0.2-alpha9 2018-01-23 15:29:21 +01:00
Dominique
af7d7b164a Various GUI Improvements (#396)
* (gui) Added funding tx id to channel panel

fixes #335

* (gui) close channel button hidden when CLOSING or CLOSED

fixes #332

* (gui) User can define a preferred display unit

On startup FxApp reads the configuration from `eclair.conf` and sets
a unit to which all the amounts in the UI must be converted.

This unit is a CoinUnit object. Only `sat`, `mbtc` and `btc` are accepted.
`msat` is not accepted because it's an internal accounting unit which
should be invisible to the user. Default unit is `btc`

The gui does not expose any ui feature to update this unit at runtime.

* (gui) Notification message wraps and can now be copied

Notification message should be readable especially when an error occurs.
The message can be copied for easier issue reporting.

* Payment attempts is limited to 1

* (gui) consistent order in status bar contextual actions

* (gui) fixed unit parsing

* (gui) added menu shortcuts

fixes #347

* Revert "Payment attempts is limited to 1"

This reverts commit 1f4168aacb.

* (gui) BtcAmount are convertible to raw big decimal without loss

Fix issue where the decimal part of a BtcAmount could be lost.
Millisatoshi is now accepted as a user preferred unit.

* Set a minimum htlc amount of 1 mSat by default

By default, the node configuration should be permissive and accept low
value payments. It is up to the node admin to set up a restrictive
configuration if he needs it.

* (gui) port in node uri is optional

* (gui) added reactive errors in open channel window

* (gui) format max pr amount to user preferred unit

* (gui) Payment Request QR should be uppercased

see #375

* (gui) added a conf for the gui module

* Added eclair.gui.unit option in README
2018-01-23 15:25:53 +01:00
Benoît Verret
eb03b8ddfe (minor) Fix a comment (#386) 2018-01-21 11:47:48 +01:00
dpad85
42715abda0 Back to SNAPSHOT 2018-01-05 11:54:31 +01:00
pm47
74faad53e8 back to SNAPSHOT 2017-12-23 19:26:54 +01:00
pm47
8edb2a478c set version to 0.2-alpha8 2017-12-23 18:37:00 +01:00
pm47
6874dd6a50 set version to 0.2-android-alpha12 2017-12-23 00:21:07 +01:00
pm47
78559d4298 Merge branch 'master' into wip-android 2017-12-22 23:34:10 +01:00
Pierre-Marie Padiou
a3bdf52a2f
Improve logs (#320)
* always print `shortChannelId` in hex

* fixed logs in `ThrottleForwarder`

* logs the `paymentHash` when relaying an htlc

* don't print all channel data when restoring a channel

* added logs to relayer

* reduced log level in Peer

* cleaned up switchboard logs

* fixed `id`/`channelId` mixup in relayer logs

* slight changes in log levels

* do not log as warning when tx generation is simply skipped

* streamlined relayer logs

* improved router logs

* don't display errors when witness can't be parsed

* don't log connection errors as warnings

* reduce amount of logs in case of local known error

* removed reconnection message to deadletter

* try a cleaner way of displaying channel errors

* put some reconnection-related logs from info to debug

* peer: ignore `Rebroadcast` messages in `INITIALIZING`

* less verbose exception logging in channel

* display friendlier close type

* reduced default log level to INFO
2017-12-22 23:32:34 +01:00
pm47
aa5e7abf4a fixed textui 2017-12-22 23:28:21 +01:00
pm47
44dc219b61 back to SNAPSHOT 2017-12-15 19:33:07 +01:00
pm47
5730f19f06 set version to 0.2-android-alpha11 2017-12-15 19:32:23 +01:00
pm47
8c0eb4c159 back to SNAPSHOT 2017-12-15 19:31:22 +01:00
pm47
83649c3e9f set version to 0.2-android-alpha10 2017-12-15 19:17:45 +01:00
pm47
62af12b91e back to SNAPSHOT 2017-12-15 18:28:14 +01:00
pm47
f1afe3f4b7 back to SNAPSHOT 2017-12-14 18:22:39 +01:00
pm47
1155788b5e set version to 0.2-alpha7 2017-12-14 12:28:25 +01:00
pm47
44f7bd7145 bcak to SNAPSHOT 2017-12-06 19:19:30 +01:00
dpad85
b52948e889 Release version 0.2-android-alpha9 2017-12-06 19:12:45 +01:00
pm47
3d240f5761 set version 0.2-alpha6 2017-12-06 18:34:40 +01:00
pm47
4afc498226 Merge branch 'master' into wip-android 2017-12-06 13:57:25 +01:00
Nicolas Dorier
0794fb8d5a Docker support with repeatable build (#255)
Dependency to `git` has been removed, we now use `notag` when building without
a git directory.

In order to reliably fetch all dependencies, we do a first blank build
(with no source files), then we copy the sources and do a real commit.

This is a simpler and more robust approach.

Also, fixed the .dockerignore to filter out IDE files.
2017-12-05 17:29:47 +01:00
Dominique
71f39a033b Moved akka conf to eclair-node application.conf (#252)
Overriding configuration of dependencies must be done at the application level.
2017-12-04 13:31:05 +01:00
pm47
866311d24d Merge branch 'master' into wip-android 2017-12-01 18:43:53 +01:00
pm47
6e37586f9e disabled debug mode in default logback.xml 2017-12-01 18:42:50 +01:00
pm47
68b494d283 Merge branch 'master' into wip-android 2017-11-23 11:31:46 +01:00
Pierre-Marie Padiou
bfa3e1c2ca Reformat + optimized imports (#222)
* Reformat + optimized imports

* Fixed unwanted modifications
2017-11-21 20:08:15 +01:00
dpad85
e400fb5eb4 set version to 0.2-android-alpha8 2017-11-21 19:26:41 +01:00
Pierre-Marie Padiou
ca46c0e9cf
[Android] Support for electrumx API (#214)
* back to 0.2-SNAPHOT (#166)

use scala plugin 3.3.1 (mvn scala:console now works)
add Dominique to the list of developpers

* Process `update_fail_malformed_htlc` properly (#168)

* add a test that fails and shows that we don't process `update_fail_malformed` properly
* remove HTLCs failed with update_fail_malformed
* fixes #167

* Re-send htlc/sigs after `funding_locked` (#169)

We previously skipped the `handleSync` function when we had to re-send
`funding_locked` messages on reconnection. This didn't take into account
the fact that we might have been disconnected right after sending the
very first `commit_sig` in the channel. In that case we need to first
re-send `funding_locked`, then re-send whatever updates were included in
the lost signature, and finally re-send the same `commit_sig`.

Note that the specification doesn't require to re-send the exact same
updates and signatures on reconnection. But doing this allows for a single
commitment history and allows us not to keep track of all signatures
sent to the other party.

Closes #165

* Handle `update_fail_malformed_htlc` in payment FSM (#170)

* handling `update_fail_malformed` messages in payment fsm

* added check on failure code for malformed htlc errors

Spec says that the `update_fail_malformed_htlc`.`failure_code`
must have the BADONION bit set.

* removed hard-coded actor names in fuzzy tests

* Added an integration test on revoked tx handling (#172)

The scenario was already tested at a lower level, but this is
more realistic, with a real bitcoin core.

Note that we currently only steal the counterparty's *main output*,
we ignore pending htlcs. From an incentive point-of-view, it is an
acceptable tradeoff because the amount of in-flight htlcs should
typically be far less than the main outputs (and can be configured
with `max-htlc-value-in-flight-msat`).

* Added ACK-based TCP write back-pressure (#174)

Current implementation was simplistic, which resulted in writes
being rejected when OS buffer was full. This happened especially
right after connection, when dumping a large routing table.

It is not clear whether we need read throttling too.

* Added check amount>dust on `ClaimDelayedOutputTx` (#177)

The current trimming logic [1] as defined in the spec only takes
care of 2nd level txes, making sure that their outputs are greater
than the configured dust limit. However, it is very possible that
depending on the current `feeRatePerKw`, 3rd level transactions
(such as those claiming delayed outputs) are below the dust limit.

Current implementation wasn't taking care of that, and was happily
generating transactions with negative amounts, as reported in #164.

This fixes #164 by rejecting transactions with an amount below the
dust limit, similarly to what happens when the parent output is
trimmed for 2nd level txes.

[1] https://github.com/lightningnetwork/lightning-rfc/blob/master/03-transactions.md#trimmed-outputs

* Reworked handling of `shutdown` messages (#176)

Current version attempted to do everything at once, and would always
leave the NORMAL state after processing the `shutdown` message. In
addition to being overly complicated, it had bugs because it is just
not always possible to do so: for example when we have unsigned outgoing
`update_add_htlc` and are already in the process of signing older changes,
the only thing we can do is wait for the counterparty's `revoke_and_ack`
and sign again right away when we receive it. Only after that can we
send our `shutdown` message, and we can't accept new `update_add_htlc`
in the meantime.

Another issue with the current implementation was that we considered
unsigned outgoing *changes*, when only unsigned outgoing `update_add_htlc`
are relevant in the context of `shutdown` logic.

We now also fail to route htlcs in SHUTDOWN state, as recommended by BOLT 2.

This fixes #173.

* Base checks in `sendAdd` on the *last* sent sig (#180)

fixes #175

* Store state when a sig is received in SHUTDOWN (#181)

This fixes #173 (for good this time)

* Support multiple hops in RoutingInfoTag (#185)

* Support multiple hops in RoutingInfoTag

* Change `HiddenHop` to `ExtraHop`, `channelId: BinaryData` to `shortChannelId: Long`

* payment request: encode expiry as a varlen unsigned long (#188)

* payment request expiry encoding: add Anton's test
it shows that we don't encode/decode values which would take up more than 2 5-bits value

* payment request: encode expiry as a varlen unsigned value
fixes #186

* Have channels subscribe to blockchain events at creation (#195)

Instead of only subscribing to those events when we reach certain states,
we now always subscribe to them at startup. It doesn't cost a lot because
we receive an event only when a new block appears, and is much simpler.

Note that we previously didn't even bother unsubscribing when we weren't
interested anymore in the events, and were ignoring the messages in the
`whenUnhandled` block. So it is more consistent to have the same behavior
during the whole lifetime of the channel.

This fixes #187.

* Add primary key to channel_updates table (#199)

This table was missing a primary key, which caused it to grow
indefinitely.

Also added duplication tests to other tables.

* Always store channel state when a rev is received (#201)

The way the store data currently doesn't allow for easy testing of this.
It will be improved in a later iteration.

This fixes #200.

* Add an optional 'minimum htlc expiry' tag (#202)

* Support building payments with extra hops (#198)

* Support building of outgoing payments with optional extra hops from payment requests

* Add test for route calculation with extra hops

* Simplify pattern matching in `buildExtra`

* `buildPayment` now uses a reverse Seq[Hop] to create a Seq[ExtraHop]

Since `Router` currently stores `ChannelUpdate`'s for non-public channels, it is possible to use it not only to get a route from payer to payee but also to get a "reverse" assisted route from payee when creating a `PaymentRequest`.

In principle this could be used to even generate a full reverse path to a payer which does not have an access to routing table for some reason.

* Can create `PaymentRequest`s with `RoutingInfoTag`s

* Bugfix and update test with data from live payment testing

* Move ExtraHop to PaymentRequest.scala

* Use `min_final_cltv_expiry` included in payment request (if any) (#210)

* Lock utxos when creating a funding transaction with Bitcoin Core (#211)

This mitigates issues when opening channels in parallel and having unpublished transactions reuse utxos that are already used by other txs.

Note that utxo will stay locked if counterparty disconnects after the `funding_created` message is sent, and before a `funding_signed` is received. In that case we should release locked utxos by calling `lockunspent` RPC function.

* Readme: added help for options syntax (#212)

* (README) updated link to release readme
* (README) added a link to HOCON readme for options syntax

This closes #209

* Rework preimage handling (#183)

* properly handle new htlc requests when closing

When in NORMAL state and a `shutdown` message has already been
sent or received, then any subsequent `CMD_ADD_HTLC` fails and
the relayer is notified of the failure.

Same in SHUTDOWN state.

This fixes a possible race condition when a channel just switched
to SHUTDOWN, and the relayer keeps sending it new htlcs before
being notified of the state change.

* renamed Htlc->DirectedHtlc + cleanup

* storing origin of htlcs in the channel state

Currently this information is handled in the relayer, which is not
persisted. As a consequence, if eclair is shut down and there are
pending (signed) incoming htlcs, those will always expire (time out
and fail) even if the corresponding outgoing htlc is fulfilled, because
we lose the lookup table (the relayer's `bindings` map).

Storing the origin in the channel (as opposed to persisting the state
of the relayer) makes sense because we want to store the origin if and
only if an outgoing htlc was successfully sent and signed in a channel.

It is also probably more performant because we only need to do one disk
operation (which we have to do at signing anyway) instead of two
distinct operations.

* removed bindings from relayer

Instead, we rely on the origin stored in the actor state.

* preimages are now persisted and acknowledged

Upon reception of an `UpdateFulfillHtlc`, the relayer forwards it
immediately to the origin channel, *and* it stores the preimage in
a `PreimagesDb`.

When the origin channel has irrevocably committed the fulfill in a
`CommitSig`, it sends an `AckFulfillCmd` back to the relayer, which
will then remove the preimage from its database.

In addition to that, the relayer will re-send all pending fulfills
when it is notified that a channel reaches NORMAL, SHUTDOWN, or
CLOSING state. That way we make sure that the origin channel will
always get the fulfill eventually, even if it currently OFFLINE for
example. This fixes #146.

Also, the relayer now relies on the register to forward messages to
channels based on `channelId` or `shortChannelId`. This simplifies
the relayer but adds one hop when forwarding messages.

* modified `PaymentRelayed` event

Replaced `amountIn` and `feesEarned` by more explicit `amountIn`
and `amountOut`. `feesEarned` are simply the difference.

TODO:
- when local/remote closing a channel, we currently do not wait
for htlc-related transactions, we consider the channel CLOSED when
the commitment transactions has been buried deeply enough; this is
wrong because it wouldn't let us time to extract payment preimages
in certain cases

* Reworked channel closing logic (#204)

When doing an unilateral close (local or remote), we previously weren't
watching htlc outputs to decide whether the commit was finished or not.
This was incorrect because we didn't make sure the htlc-related
transactions had indeed been confirmed on the blockchain, making us
potentially lose money.

This is not trivial, because htlc transactions may be double-spent by the
counterparty, dependending on scenarios (ex: `htlc-timeout` vs
`claim-success`). On top of that, there may be several different kind of
commits in competition at the same time.

With this change, we now:
- put `WatchConfirm` watches on the commitment tx, and on all outputs only
  us control (eg: our main output) ;
- put `WatchSpent` watches on the outputs that may be double spent by the
  counterparty; when such an output is spent, we put a `WatchConfirm` on
  the corresponding transaction and keep track of all outpoints spent ;
- every time a new transaction is confirmed, we find out if there are some
  remaining transactions waiting for confirmation, taking into account the
  fact that some 2nd/3rd-stage txs may never confirm because their input
  has been doublespent.

We also don't rely anymore on dedicated `BITCOIN_CLOSE_DONE`,
`BITCOIN_LOCALCOMMIT_DONE`, ... events.

* Better handle big routing table (#194)

* increased tcp send buffer x100

* throttle announcement messages when dumping the table

* set router throttling to chunkSize=10 delay=50ms

* Handle remote `error` in `SYNCING` state (#205)

This closes #203.

* added support for electrumx wallet/watcher

This is a rework of #184 with numerous improvements and bugfixes.

* re-enabled `WatchSpentBasic`

* fixed several issues in watcher

* fixed pattern matching for INPUT_RECONNECTED event in CLOSING

* reduced logback_colors log level

* disabled WatchSpentBasic on android

* moved bitcoin init to the bootstrap future

This way the name resolution when loading electrum server addresses does
not occur on android's main thread.

* improved fees management

* main feerate source is now earn.com (21.co) instead of bitpay insight
* if main feerate source is unavailable, we now fallback to default values
* we retrieve feerates for a set of block delays instead of just one
* we now use different block delays depending on transactions:
  - `block_delay`=`1` for txes that compete with others (eg: commitment
    tx, htlc tx, penalty tx)
  - `block_delay`=`6` for other txes (eg: funding tx, closing tx, delayed
    output tx)

TODO:
- set sensible default values for feerates

* WalletTransactionReceive contains the tx fee as an option

* connect txes even if they arrive out of order

* use manual transitions because of limitation in akka 2.3 FSM

* Delay `announcement_signatures` when received early (#217)

* delay `announcement_signatures` in state `WAIT_FOR_FUNDING_LOCKED`
* delay `announcement_signatures` in state `WAIT_FOR_FUNDING_CONFIRMED`
* always re-send our `announcement_signatures` in response to theirs

* Use a separate `htlc_key` to sign 2nd stage htlc txs (#213)

We previously used the `payment_key` both for our main output, and to sign
the local `htlc_success`/`htlc_timeout` transactions.

With this change we can keep the `payment_privkey` offline, which is far
better from a security point of view because an attacker getting control
of a node wouldn't be able to just publish the current commitment
transaction and get the funds. The attacker would only be able to get our
`htlc_privkey`, which we only use in a 2-of-2 multisig with our
counterparty, so it is useless except if the attacker and the counterparty
are the same person, and even in that case only the pending htlcs would be
at risk.

Note that this implementation is a first step and actually keeps the
payment key to spend our outputs in non-mutual close scenarios.

* wallet: send confidence event as soon as a tx is confirmed

* fixed 5985148f2f and improve events

* added `NewWalletReceiveAddress` event

* cleaned up electrum testnet seeds

* added a test on dumping routing state

* routing table dump is now disabled in the router instead of peer

* removed WAIT_FOR_FUNDING_PUBLISHED state and clarified funding tx publish assumptions

* wallet: use BIP49 derivation and 24 words mnemonic codes
we use segwit with p2sh-of-p2wkh so we should use BIP49 derivation
instead of BIP44 (same path with m/49'/... instead of m/44'/...)

* added a rollback function to `EclairWallet`

This rollback is called whenever we know we won't publish the funding tx,
so that we tell the wallet to release locks on utxos.

* fundee now checks feerates at `open_channel` reception

* proper handling of electrum connection/disconnection

* moved bitcoinj test to its own package

* Improved fees management (#216)

* main feerate source is now earn.com (21.co) instead of bitpay insight
* if main feerate source is unavailable, we now fallback to default values
* we retrieve feerates for a set of block delays instead of just one
* we now use different block delays depending on transactions:
  - `block_delay`=`1` for txes that compete with others (eg: commitment
    tx, htlc tx, penalty tx)
  - `block_delay`=`6` for other txes (eg: funding tx, closing tx, delayed
    output tx)

* make electrum wallet advertise address at startup

* Prune stale network announcements (#219)

See https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md#recommendation-on-pruning-stale-entries.

* send a new `channel_update` every 24h as keepalive

* use case object instead of symbol for ticks

* minor improvements in router init

* prune stale channels

Note that we don't want to prune brand new channels for which we didn't
yet receive a channel update, so we consider stale a channel that:
(1) is older than 2 weeks (2*7*144 = 2016 blocks)
AND
(2) didn't have an update during the last 2 weeks.

Pruning is triggered every day.

Also renamed event `BITCOIN_FUNDING_OTHER_CHANNEL_SPENT` to
`BITCOIN_FUNDING_EXTERNAL_CHANNEL_SPENT`.

* filter out duplicate announcements before checking sig

* changed routing table dump parameters

* set version to 0.2-android-SNAPSHOT
2017-11-21 18:25:27 +01:00
Pierre-Marie Padiou
875dc04d39
Support for electrumx API (#208)
This is a rework of #184 with numerous improvements and bugfixes.

* re-enabled `WatchSpentBasic`

* fixed several issues in watcher

* fixed pattern matching for INPUT_RECONNECTED event in CLOSING

* reduced logback_colors log level

* connect txes even if they arrive out of order

* wallet: send confidence event as soon as a tx is confirmed

* fixed 5985148f2f and improve events

* added `NewWalletReceiveAddress` event

* cleaned up electrum testnet seeds

* added a test on dumping routing state

* removed WAIT_FOR_FUNDING_PUBLISHED state and clarified funding tx publish assumptions

* wallet: use BIP49 derivation and 24 words mnemonic codes
we use segwit with p2sh-of-p2wkh so we should use BIP49 derivation
instead of BIP44 (same path with m/49'/... instead of m/44'/...)

* added a rollback function to `EclairWallet`

This rollback is called whenever we know we won't publish the funding tx,
so that we tell the wallet to release locks on utxos.

* fundee now checks feerates at `open_channel` reception

* proper handling of electrum connection/disconnection

* moved bitcoinj test to its own package

* make electrum wallet advertise address at startup

* set version to 0.2-SNAPSHOT
2017-11-21 18:12:45 +01:00
pm47
435c1e424c db hotfix, set version to 0.2-android-alpha7
Table `channel_updates` is missing a primary key and keeps growing
everytime eclair wallet is restarted. As a temporary quick fix, we just
delete duplicates on startup.
2017-10-24 18:52:51 +02:00
pm47
4786066bb7 set version to 0.2-android-alpha6 2017-10-24 14:36:39 +02:00
sstone
c3a1858e13 set version to 0.2-android-SNAPSHOT
and upgrade to mave scala plugin 3.3.1
2017-09-25 14:03:51 +02:00
Fabrice Drouin
1f336772b2 back to 0.2-SNAPHOT (#166)
use scala plugin 3.3.1 (mvn scala:console now works)
add Dominique to the list of developpers
2017-09-20 15:16:49 +02:00