mirror of
https://github.com/ACINQ/eclair.git
synced 2025-03-03 17:36:56 +01:00
Define 9999-12-31 as max value for timestamps (#2118)
This effectively reverts #2112 and implements it differently. Having a single very conservative max value is simpler and the risk of regression is very low. Also fixed a wrong comment, previous max wasn't `11/04/2262` but a huge value.
This commit is contained in:
parent
2827be875d
commit
1fd6344a5d
4 changed files with 11 additions and 12 deletions
|
@ -21,7 +21,7 @@ import java.time.Instant
|
||||||
import scala.concurrent.duration.{DurationLong, FiniteDuration}
|
import scala.concurrent.duration.{DurationLong, FiniteDuration}
|
||||||
|
|
||||||
case class TimestampSecond(private val underlying: Long) extends Ordered[TimestampSecond] {
|
case class TimestampSecond(private val underlying: Long) extends Ordered[TimestampSecond] {
|
||||||
require(underlying >= 0 && underlying <= Long.MaxValue / 1000, "invalid timestamp value")
|
require(underlying >= 0 && underlying <= 253402300799L, "invalid timestamp value")
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
def toLong: Long = underlying
|
def toLong: Long = underlying
|
||||||
def toTimestampMilli: TimestampMilli = TimestampMilli(underlying * 1000)
|
def toTimestampMilli: TimestampMilli = TimestampMilli(underlying * 1000)
|
||||||
|
@ -38,12 +38,12 @@ case class TimestampSecond(private val underlying: Long) extends Ordered[Timesta
|
||||||
|
|
||||||
object TimestampSecond {
|
object TimestampSecond {
|
||||||
val min: TimestampSecond = TimestampSecond(0) // 1/1/1970
|
val min: TimestampSecond = TimestampSecond(0) // 1/1/1970
|
||||||
val max: TimestampSecond = TimestampSecond(Long.MaxValue / 1000) // 11/04/2262 (upper limit prevents overflow when converting to milli precision)
|
val max: TimestampSecond = TimestampSecond(253402300799L) // 31/12/9999 (prevents overflow when converting to milli precision or sql timestamps)
|
||||||
def now(): TimestampSecond = TimestampSecond(System.currentTimeMillis() / 1000)
|
def now(): TimestampSecond = TimestampSecond(System.currentTimeMillis() / 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class TimestampMilli(private val underlying: Long) extends Ordered[TimestampMilli] {
|
case class TimestampMilli(private val underlying: Long) extends Ordered[TimestampMilli] {
|
||||||
require(underlying >= 0 && underlying <= Long.MaxValue, "invalid timestamp value")
|
require(underlying >= 0 && underlying <= 253402300799L * 1000, "invalid timestamp value")
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
def toLong: Long = underlying
|
def toLong: Long = underlying
|
||||||
def toSqlTimestamp: sql.Timestamp = sql.Timestamp.from(Instant.ofEpochMilli(underlying))
|
def toSqlTimestamp: sql.Timestamp = sql.Timestamp.from(Instant.ofEpochMilli(underlying))
|
||||||
|
@ -58,7 +58,7 @@ case class TimestampMilli(private val underlying: Long) extends Ordered[Timestam
|
||||||
object TimestampMilli {
|
object TimestampMilli {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
val min: TimestampMilli = TimestampMilli(0) // 1/1/1970
|
val min: TimestampMilli = TimestampMilli(0) // 1/1/1970
|
||||||
val max: TimestampMilli = TimestampMilli(Long.MaxValue) // 11/04/2262
|
val max: TimestampMilli = TimestampMilli(253402300799L * 1000) // 31/12/9999 (prevents overflow when converting to sql timestamps)
|
||||||
def now(): TimestampMilli = TimestampMilli(System.currentTimeMillis())
|
def now(): TimestampMilli = TimestampMilli(System.currentTimeMillis())
|
||||||
def fromSqlTimestamp(sqlTs: sql.Timestamp): TimestampMilli = TimestampMilli(sqlTs.getTime)
|
def fromSqlTimestamp(sqlTs: sql.Timestamp): TimestampMilli = TimestampMilli(sqlTs.getTime)
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
|
@ -22,13 +22,13 @@ import org.scalatest.funsuite.AnyFunSuite
|
||||||
class TimestampSpec extends AnyFunSuite {
|
class TimestampSpec extends AnyFunSuite {
|
||||||
|
|
||||||
test("timestamp boundaries") {
|
test("timestamp boundaries") {
|
||||||
assert(TimestampSecond.max.toLong == Long.MaxValue / 1000)
|
assert(TimestampSecond.max.toLong == 253402300799L)
|
||||||
assert(TimestampSecond.min.toLong == 0)
|
assert(TimestampSecond.min.toLong == 0)
|
||||||
assert(TimestampMilli.max.toLong == Long.MaxValue)
|
assert(TimestampMilli.max.toLong == 253402300799L * 1000)
|
||||||
assert(TimestampMilli.min.toLong == 0)
|
assert(TimestampMilli.min.toLong == 0)
|
||||||
|
|
||||||
intercept[IllegalArgumentException] {
|
intercept[IllegalArgumentException] {
|
||||||
TimestampSecond(Long.MaxValue / 1000 + 1)
|
TimestampSecond(253402300799L + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
intercept[IllegalArgumentException] {
|
intercept[IllegalArgumentException] {
|
||||||
|
|
|
@ -43,7 +43,7 @@ trait ExtraDirectives extends Directives {
|
||||||
val nodeIdsFormParam: NameUnmarshallerReceptacle[List[PublicKey]] = "nodeIds".as[List[PublicKey]](pubkeyListUnmarshaller)
|
val nodeIdsFormParam: NameUnmarshallerReceptacle[List[PublicKey]] = "nodeIds".as[List[PublicKey]](pubkeyListUnmarshaller)
|
||||||
val paymentHashFormParam: NameUnmarshallerReceptacle[ByteVector32] = "paymentHash".as[ByteVector32](sha256HashUnmarshaller)
|
val paymentHashFormParam: NameUnmarshallerReceptacle[ByteVector32] = "paymentHash".as[ByteVector32](sha256HashUnmarshaller)
|
||||||
val fromFormParam: NameDefaultUnmarshallerReceptacle[TimestampSecond] = "from".as[TimestampSecond](timestampSecondUnmarshaller).?(TimestampSecond.min)
|
val fromFormParam: NameDefaultUnmarshallerReceptacle[TimestampSecond] = "from".as[TimestampSecond](timestampSecondUnmarshaller).?(TimestampSecond.min)
|
||||||
val toFormParam: NameDefaultUnmarshallerReceptacle[TimestampSecond] = "to".as[TimestampSecond](timestampSecondUnmarshaller).?(TimestampSecond(253402300799L)) // 31/12/9999
|
val toFormParam: NameDefaultUnmarshallerReceptacle[TimestampSecond] = "to".as[TimestampSecond](timestampSecondUnmarshaller).?(TimestampSecond.max)
|
||||||
val amountMsatFormParam: NameReceptacle[MilliSatoshi] = "amountMsat".as[MilliSatoshi]
|
val amountMsatFormParam: NameReceptacle[MilliSatoshi] = "amountMsat".as[MilliSatoshi]
|
||||||
val invoiceFormParam: NameReceptacle[PaymentRequest] = "invoice".as[PaymentRequest]
|
val invoiceFormParam: NameReceptacle[PaymentRequest] = "invoice".as[PaymentRequest]
|
||||||
val routeFormatFormParam: NameUnmarshallerReceptacle[RouteFormat] = "format".as[RouteFormat](routeFormatUnmarshaller)
|
val routeFormatFormParam: NameUnmarshallerReceptacle[RouteFormat] = "format".as[RouteFormat](routeFormatUnmarshaller)
|
||||||
|
|
|
@ -1056,7 +1056,6 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM
|
||||||
test("'audit'") {
|
test("'audit'") {
|
||||||
val eclair = mock[Eclair]
|
val eclair = mock[Eclair]
|
||||||
val mockService = new MockService(eclair)
|
val mockService = new MockService(eclair)
|
||||||
val year9999 = TimestampSecond(253402300799L)
|
|
||||||
val auditResponse = AuditResponse(Seq.empty, Seq.empty, Seq.empty)
|
val auditResponse = AuditResponse(Seq.empty, Seq.empty, Seq.empty)
|
||||||
eclair.audit(any, any)(any[Timeout]) returns Future.successful(auditResponse)
|
eclair.audit(any, any)(any[Timeout]) returns Future.successful(auditResponse)
|
||||||
|
|
||||||
|
@ -1066,16 +1065,16 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM
|
||||||
check {
|
check {
|
||||||
assert(handled)
|
assert(handled)
|
||||||
assert(status == OK)
|
assert(status == OK)
|
||||||
eclair.audit(TimestampSecond.min, year9999)(any[Timeout]).wasCalled(once)
|
eclair.audit(TimestampSecond.min, TimestampSecond.max)(any[Timeout]).wasCalled(once)
|
||||||
}
|
}
|
||||||
|
|
||||||
Post("/audit", FormData("from" -> TimestampSecond.min.toLong.toString, "to" -> year9999.toLong.toString)) ~>
|
Post("/audit", FormData("from" -> TimestampSecond.min.toLong.toString, "to" -> TimestampSecond.max.toLong.toString)) ~>
|
||||||
addCredentials(BasicHttpCredentials("", mockApi().password)) ~>
|
addCredentials(BasicHttpCredentials("", mockApi().password)) ~>
|
||||||
Route.seal(mockService.audit) ~>
|
Route.seal(mockService.audit) ~>
|
||||||
check {
|
check {
|
||||||
assert(handled)
|
assert(handled)
|
||||||
assert(status == OK)
|
assert(status == OK)
|
||||||
eclair.audit(TimestampSecond.min, year9999)(any[Timeout]).wasCalled(twice)
|
eclair.audit(TimestampSecond.min, TimestampSecond.max)(any[Timeout]).wasCalled(twice)
|
||||||
}
|
}
|
||||||
|
|
||||||
Post("/audit", FormData("from" -> 123456.toString, "to" -> 654321.toString)) ~>
|
Post("/audit", FormData("from" -> 123456.toString, "to" -> 654321.toString)) ~>
|
||||||
|
|
Loading…
Add table
Reference in a new issue