-
Notifications
You must be signed in to change notification settings - Fork 267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proper types for UNIX timestamps #1990
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1990 +/- ##
==========================================
+ Coverage 87.59% 87.74% +0.15%
==========================================
Files 159 160 +1
Lines 12444 12477 +33
Branches 525 549 +24
==========================================
+ Hits 10900 10948 +48
+ Misses 1544 1529 -15
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few highlights to facilitate review.
} | ||
|
||
object TimestampSecond { | ||
def now: TimestampSecond = TimestampSecond(System.currentTimeMillis() / 1000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is mostly the only file now where we call System.currentTimeMillis()
, apart from very few cases where it made sense to be as close to the JVM as possible (e.g. for the RNG) .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be:
def now: TimestampSecond = TimestampSecond(System.currentTimeMillis() / 1000) | |
def now(): TimestampSecond = TimestampSecond(System.currentTimeMillis() / 1000) |
eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala
Outdated
Show resolved
Hide resolved
preimage_opt match { | ||
// If we have a pre-image, the payment succeeded. | ||
case Some(preimage) => OutgoingPaymentStatus.Succeeded( | ||
preimage, fees_opt.getOrElse(MilliSatoshi(0)), paymentRoute_opt.map(b => paymentRouteCodec.decode(b) match { | ||
case Attempt.Successful(route) => route.value | ||
case Attempt.Failure(_) => Nil | ||
}).getOrElse(Nil), | ||
completedAt_opt.getOrElse(0) | ||
completedAt_opt.getOrElse(0 unixms) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example of unixms
usage:
completedAt_opt.getOrElse(0 unixms) | |
completedAt_opt.getOrElse(0 unixms) |
// BOLT 7: "nodes MAY prune channels should the timestamp of the latest channel_update be older than 2 weeks" | ||
// but we don't want to prune brand new channels for which we didn't yet receive a channel update | ||
val staleThresholdSeconds = (System.currentTimeMillis.milliseconds - 14.days).toSeconds | ||
val staleThresholdSeconds = TimestampSecond.now - 14.days |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😎
val staleThreshold = TimestampSecond.now - 14.days | ||
timestamp < staleThreshold |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😎
val timestamp1 = c.update_1_opt.map(_.timestamp).getOrElse(0L unix) | ||
val timestamp2 = c.update_2_opt.map(_.timestamp).getOrElse(0L unix) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example of unix
usage.
@@ -352,7 +353,7 @@ private[channel] object ChannelCodecs0 { | |||
val DATA_WAIT_FOR_FUNDING_CONFIRMED_COMPAT_01_Codec: Codec[DATA_WAIT_FOR_FUNDING_CONFIRMED] = ( | |||
("commitments" | commitmentsCodec) :: | |||
("fundingTx" | provide[Option[Transaction]](None)) :: | |||
("waitingSince" | provide(System.currentTimeMillis.milliseconds.toSeconds)) :: | |||
("waitingSince" | provide(TimestampSecond.now.toLong)) :: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please review carrefully.
@@ -69,6 +69,8 @@ object CommonCodecs { | |||
// this codec will fail if the amount does not fit on 32 bits | |||
val millisatoshi32: Codec[MilliSatoshi] = uint32.xmapc(l => MilliSatoshi(l))(_.toLong) | |||
|
|||
val timestampSecond: Codec[TimestampSecond] = uint32.xmapc(TimestampSecond(_))(_.toLong) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Codecs are now typed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(continued)
val fromFormParam: NameDefaultUnmarshallerReceptacle[TimestampSecond] = "from".as[TimestampSecond](timestampSecondUnmarshaller).?(0 unix) | ||
val toFormParam: NameDefaultUnmarshallerReceptacle[TimestampSecond] = "to".as[TimestampSecond](timestampSecondUnmarshaller).?(Long.MaxValue unix) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note how we provide a default value here now.
@@ -101,8 +101,8 @@ trait Channel { | |||
} | |||
|
|||
val channelStats: Route = postRequest("channelstats") { implicit t => | |||
formFields(fromFormParam.?, toFormParam.?) { (from_opt, to_opt) => | |||
complete(eclairApi.channelStats(from_opt, to_opt)) | |||
formFields(fromFormParam, toFormParam) { (from, to) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note how the param extractors return a non-optional value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That must have been quite painful, thanks!
Worth integrating quickly to avoid lengthy merge/rebase IMO.
} | ||
|
||
object TimestampSecond { | ||
def now: TimestampSecond = TimestampSecond(System.currentTimeMillis() / 1000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be:
def now: TimestampSecond = TimestampSecond(System.currentTimeMillis() / 1000) | |
def now(): TimestampSecond = TimestampSecond(System.currentTimeMillis() / 1000) |
This one of the last places where we still don't enforce strong typing. Only the minimum has been done here, as a proof of concept.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀
We define
TimestampSecond
andTimestampMilli
for second and millisecond precision UNIX-style timestamps.Let me know what you think of the syntaxic sugar, I went for
123456 unix
and123456789 unixms
.Json serialization is as follows for resp. second and millisecond precision. Note that in both case we display the unix format in second precision, but the iso format is more precise: