1+ /*
2+ * Copyright 2023 ACINQ SAS
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+ package fr .acinq .eclair .reputation
18+
19+ import akka .actor .testkit .typed .scaladsl .{ScalaTestWithActorTestKit , TestProbe }
20+ import akka .actor .typed .ActorRef
21+ import com .typesafe .config .ConfigFactory
22+ import fr .acinq .bitcoin .scalacompat .Crypto .PublicKey
23+ import fr .acinq .eclair .reputation .Reputation .ReputationConfig
24+ import fr .acinq .eclair .reputation .ReputationRecorder ._
25+ import fr .acinq .eclair .{MilliSatoshiLong , randomKey }
26+ import org .scalatest .Outcome
27+ import org .scalatest .funsuite .FixtureAnyFunSuiteLike
28+
29+ import java .util .UUID
30+ import scala .concurrent .duration .DurationInt
31+
32+ class ReputationRecorderSpec extends ScalaTestWithActorTestKit (ConfigFactory .load(" application" )) with FixtureAnyFunSuiteLike {
33+ val (uuid1, uuid2, uuid3, uuid4, uuid5, uuid6, uuid7, uuid8) = (UUID .randomUUID(), UUID .randomUUID(), UUID .randomUUID(), UUID .randomUUID(), UUID .randomUUID(), UUID .randomUUID(), UUID .randomUUID(), UUID .randomUUID())
34+ val originNode : PublicKey = randomKey().publicKey
35+
36+ case class FixtureParam (config : ReputationConfig , reputationRecorder : ActorRef [Command ], replyTo : TestProbe [Confidence ])
37+
38+ override def withFixture (test : OneArgTest ): Outcome = {
39+ val config = ReputationConfig (1000000000 msat, 10 seconds)
40+ val replyTo = TestProbe [Confidence ](" confidence" )
41+ val reputationRecorder = testKit.spawn(ReputationRecorder (config, Map .empty))
42+ withFixture(test.toNoArgTest(FixtureParam (config, reputationRecorder.ref, replyTo)))
43+ }
44+
45+ test(" standard" ) { f =>
46+ import f ._
47+
48+ reputationRecorder ! GetConfidence (replyTo.ref, originNode, isEndorsed = true , uuid1, 1100 msat)
49+ assert(replyTo.expectMessageType[Confidence ].value == 0 )
50+ reputationRecorder ! RecordResult (originNode, isEndorsed = true , uuid1, isSuccess = true )
51+ reputationRecorder ! GetConfidence (replyTo.ref, originNode, isEndorsed = true , uuid2, 1100 msat)
52+ assert(replyTo.expectMessageType[Confidence ].value == 0.5 )
53+ reputationRecorder ! GetConfidence (replyTo.ref, originNode, isEndorsed = true , uuid3, 1100 msat)
54+ assert(replyTo.expectMessageType[Confidence ].value === 0.333 +- 0.001 )
55+ reputationRecorder ! CancelRelay (originNode, isEndorsed = true , uuid3)
56+ reputationRecorder ! GetConfidence (replyTo.ref, originNode, isEndorsed = true , uuid4, 1100 msat)
57+ assert(replyTo.expectMessageType[Confidence ].value === 0.333 +- 0.001 )
58+ reputationRecorder ! RecordResult (originNode, isEndorsed = true , uuid4, isSuccess = true )
59+ reputationRecorder ! RecordResult (originNode, isEndorsed = true , uuid2, isSuccess = false )
60+ // Not endorsed
61+ reputationRecorder ! GetConfidence (replyTo.ref, originNode, isEndorsed = false , uuid5, 1100 msat)
62+ assert(replyTo.expectMessageType[Confidence ].value == 0 )
63+ // Different origin node
64+ reputationRecorder ! GetConfidence (replyTo.ref, randomKey().publicKey, isEndorsed = true , uuid6, 1100 msat)
65+ assert(replyTo.expectMessageType[Confidence ].value == 0 )
66+ // Very large HTLC
67+ reputationRecorder ! GetConfidence (replyTo.ref, originNode, isEndorsed = true , uuid5, 10000000 msat)
68+ assert(replyTo.expectMessageType[Confidence ].value === 0.0 +- 0.001 )
69+ }
70+
71+ test(" trampoline" ) { f =>
72+ import f ._
73+
74+ val (a, b, c) = (randomKey().publicKey, randomKey().publicKey, randomKey().publicKey)
75+
76+ reputationRecorder ! GetTrampolineConfidence (replyTo.ref, Map ((a, true ) -> 1000 .msat, (b, true ) -> 2000 .msat, (c, false ) -> 3000 .msat), uuid1)
77+ assert(replyTo.expectMessageType[Confidence ].value == 0 )
78+ reputationRecorder ! RecordTrampolineSuccess (Map ((a, true ) -> 500 .msat, (b, true ) -> 1000 .msat, (c, false ) -> 1500 .msat), uuid1)
79+ reputationRecorder ! GetTrampolineConfidence (replyTo.ref, Map ((a, true ) -> 1000 .msat, (c, false ) -> 1000 .msat), uuid2)
80+ assert(replyTo.expectMessageType[Confidence ].value === 0.333 +- 0.001 )
81+ reputationRecorder ! GetTrampolineConfidence (replyTo.ref, Map ((a, false ) -> 1000 .msat, (b, true ) -> 2000 .msat), uuid3)
82+ assert(replyTo.expectMessageType[Confidence ].value == 0 )
83+ reputationRecorder ! RecordTrampolineFailure (Set ((a, true ), (c, false )), uuid2)
84+ reputationRecorder ! RecordTrampolineSuccess (Map ((a, false ) -> 1000 .msat, (b, true ) -> 2000 .msat), uuid3)
85+
86+ reputationRecorder ! GetConfidence (replyTo.ref, a, isEndorsed = true , uuid4, 1000 msat)
87+ assert(replyTo.expectMessageType[Confidence ].value === 0.2 +- 0.001 )
88+ reputationRecorder ! GetConfidence (replyTo.ref, a, isEndorsed = false , uuid5, 1000 msat)
89+ assert(replyTo.expectMessageType[Confidence ].value === 0.5 +- 0.001 )
90+ reputationRecorder ! GetConfidence (replyTo.ref, b, isEndorsed = true , uuid6, 1000 msat)
91+ assert(replyTo.expectMessageType[Confidence ].value === 0.75 +- 0.001 )
92+ reputationRecorder ! GetConfidence (replyTo.ref, b, isEndorsed = false , uuid7, 1000 msat)
93+ assert(replyTo.expectMessageType[Confidence ].value == 0.0 )
94+ reputationRecorder ! GetConfidence (replyTo.ref, c, isEndorsed = false , uuid8, 1000 msat)
95+ assert(replyTo.expectMessageType[Confidence ].value === (3.0 / 7 ) +- 0.001 )
96+ }
97+ }
0 commit comments