11package org .lfdecentralizedtrust .splice .integration .tests
22
33import org .lfdecentralizedtrust .splice .codegen .java .splice .amulet .UnclaimedReward
4+ import org .lfdecentralizedtrust .splice .codegen .java .splice .dsorules .validatorlicensechange .VLC_ChangeWeight
45import org .lfdecentralizedtrust .splice .codegen .java .splice .validatorlicense .*
56import org .lfdecentralizedtrust .splice .config .ConfigTransforms .{
67 ConfigurableApp ,
@@ -9,7 +10,12 @@ import org.lfdecentralizedtrust.splice.config.ConfigTransforms.{
910import org .lfdecentralizedtrust .splice .environment .BuildInfo
1011import org .lfdecentralizedtrust .splice .integration .EnvironmentDefinition
1112import org .lfdecentralizedtrust .splice .integration .tests .SpliceTests .IntegrationTest
12- import org .lfdecentralizedtrust .splice .util .{TimeTestUtil , TriggerTestUtil , WalletTestUtil }
13+ import org .lfdecentralizedtrust .splice .util .{
14+ SvTestUtil ,
15+ TimeTestUtil ,
16+ TriggerTestUtil ,
17+ WalletTestUtil ,
18+ }
1319import org .lfdecentralizedtrust .splice .validator .automation .ReceiveFaucetCouponTrigger
1420import org .lfdecentralizedtrust .splice .wallet .automation .CollectRewardsAndMergeAmuletsTrigger
1521import com .digitalasset .canton .config .CantonRequireTypes .InstanceName
@@ -20,7 +26,8 @@ class ValidatorLicenseMetadataTimeBasedIntegrationTest
2026 extends IntegrationTest
2127 with WalletTestUtil
2228 with TimeTestUtil
23- with TriggerTestUtil {
29+ with TriggerTestUtil
30+ with SvTestUtil {
2431
2532 override def environmentDefinition : SpliceEnvironmentDefinition =
2633 EnvironmentDefinition
@@ -134,67 +141,103 @@ class ValidatorLicenseMetadataTimeBasedIntegrationTest
134141 }
135142 }
136143
137- " unclaimed ValidatorLivenessActivityRecord contracts should be expired" in { implicit env =>
138- startAllSync(
139- sv1Backend,
140- sv1ScanBackend,
141- aliceValidatorBackend,
142- )
143-
144- advanceTimeForRewardAutomationToRunForCurrentRound
145-
146- eventually() {
147- val validatorLivenessActivityRecordRounds =
148- sv1Backend.participantClient.ledger_api_extensions.acs
149- .filterJava(ValidatorLivenessActivityRecord .COMPANION )(
150- dsoParty
151- )
152- .map(_.data.round.number)
153- .toSet
144+ " expired ValidatorLivenessActivityRecord creates UnclaimedReward with correct weight" in {
145+ implicit env =>
146+ startAllSync(
147+ sv1Backend,
148+ sv1ScanBackend,
149+ aliceValidatorBackend,
150+ )
154151
155- validatorLivenessActivityRecordRounds shouldBe Set (0L , 1L )
156- }
157-
158- // pause the trigger to avoid collecting further rewards
159- setTriggersWithin(
160- triggersToResumeAtStart = Seq .empty,
161- triggersToPauseAtStart = Seq (
162- aliceValidatorBackend.validatorAutomation.trigger[ReceiveFaucetCouponTrigger ]
163- ),
164- ) {
152+ val aliceValidatorParty = aliceValidatorBackend.getValidatorPartyId()
165153
154+ // Change Alice's validator license weight to 10.0
155+ val aliceNewWeight = BigDecimal (10.0 )
166156 actAndCheck(
167- " Advance rounds so that issuing rounds 0 and 1 no longer exist" ,
168- (1 to 5 ).foreach { _ =>
169- advanceRoundsToNextRoundOpening
170- },
157+ " Modify validator licenses" ,
158+ modifyValidatorLicenses(
159+ sv1Backend,
160+ svsToCastVotes = Seq .empty,
161+ Seq (new VLC_ChangeWeight (aliceValidatorParty.toProtoPrimitive, aliceNewWeight.bigDecimal)),
162+ ),
171163 )(
172- " ValidatorLivenessActivityRecord contracts for round 0 and 1 should be expired " ,
164+ " validator license modifications have been applied " ,
173165 _ => {
174- val issuingRounds = sv1ScanBackend.getOpenAndIssuingMiningRounds()._2
175- issuingRounds.map(_.payload.round.number).toSet shouldBe Set (2L , 3L , 4L )
176-
177- val allValidatorLivenessActivityRecord =
178- sv1Backend.participantClient.ledger_api_extensions.acs
179- .filterJava(ValidatorLivenessActivityRecord .COMPANION )(
180- dsoParty
166+ val licenses =
167+ aliceValidatorBackend.participantClientWithAdminToken.ledger_api_extensions.acs
168+ .filterJava(ValidatorLicense .COMPANION )(
169+ dsoParty,
170+ c => c.data.validator == aliceValidatorParty.toProtoPrimitive,
181171 )
182- allValidatorLivenessActivityRecord shouldBe empty
183-
184- // assuming this value is the same in that of round 0 and 1
185- val issuancePerValidatorFaucetCoupon =
186- issuingRounds.headOption.value.payload.optIssuancePerValidatorFaucetCoupon.toScala.value
187-
188- val unclaimedRewards = sv1Backend.participantClient.ledger_api_extensions.acs
189- .filterJava(UnclaimedReward .COMPANION )(
190- dsoParty
191- )
192- .map(_.data.amount)
193-
194- unclaimedRewards.count(_ == issuancePerValidatorFaucetCoupon) shouldBe 2
172+ licenses should have length 1
173+ licenses.head.data.weight.toScala.map(BigDecimal (_)) shouldBe Some (aliceNewWeight)
195174 },
196175 )
197- succeed
198- }
176+
177+ advanceTimeForRewardAutomationToRunForCurrentRound
178+
179+ // Verify liveness activity records are created for with correct weight
180+ val aliceActivityRecords = eventually() {
181+ val records = sv1Backend.participantClient.ledger_api_extensions.acs
182+ .filterJava(ValidatorLivenessActivityRecord .COMPANION )(
183+ dsoParty,
184+ c => c.data.validator == aliceValidatorParty.toProtoPrimitive,
185+ )
186+ records.map(_.data.round.number).toSet shouldBe Set (0L , 1L )
187+ records
188+ }
189+
190+ aliceActivityRecords.foreach { record =>
191+ record.data.weight.toScala.map(BigDecimal (_)) shouldBe Some (aliceNewWeight)
192+ }
193+
194+ val recordRounds = aliceActivityRecords.map(_.data.round.number).toSet
195+
196+ // pause the trigger to avoid collecting further rewards
197+ setTriggersWithin(
198+ triggersToResumeAtStart = Seq .empty,
199+ triggersToPauseAtStart = Seq (
200+ aliceValidatorBackend.validatorAutomation.trigger[ReceiveFaucetCouponTrigger ]
201+ ),
202+ ) {
203+ actAndCheck(
204+ " Advance rounds so that issuing rounds 0 and 1 no longer exist" ,
205+ (1 to 5 ).foreach { _ =>
206+ advanceRoundsToNextRoundOpening
207+ },
208+ )(
209+ " ValidatorLivenessActivityRecord contracts for round 0 and 1 should be expired" ,
210+ _ => {
211+ // Verify activity records are expired
212+ val allValidatorLivenessActivityRecord =
213+ sv1Backend.participantClient.ledger_api_extensions.acs
214+ .filterJava(ValidatorLivenessActivityRecord .COMPANION )(
215+ dsoParty
216+ )
217+ allValidatorLivenessActivityRecord shouldBe empty
218+
219+ // Get issuance value from issuing rounds
220+ val issuingRounds = sv1ScanBackend.getOpenAndIssuingMiningRounds()._2
221+ issuingRounds should not be empty
222+
223+ val issuancePerValidatorFaucetCoupon =
224+ issuingRounds.headOption.value.payload.optIssuancePerValidatorFaucetCoupon.toScala.value
225+
226+ // Expected amount per record is weight * issuance
227+ val expectedAmountPerRecord =
228+ aliceNewWeight.bigDecimal.multiply(issuancePerValidatorFaucetCoupon)
229+
230+ val unclaimedRewards = sv1Backend.participantClient.ledger_api_extensions.acs
231+ .filterJava(UnclaimedReward .COMPANION )(dsoParty)
232+ .map(_.data.amount)
233+
234+ // Should have unclaimed rewards with the weighted amount for each round
235+ unclaimedRewards.count(
236+ _.compareTo(expectedAmountPerRecord) == 0
237+ ) shouldBe recordRounds.size
238+ },
239+ )
240+ succeed
241+ }
199242 }
200243}
0 commit comments