Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -385,15 +385,15 @@ abstract class ScanAppReference(
@Help.Summary("Get CIP-0104 activity totals for a specific round")
def getRewardAccountingActivityTotals(
roundNumber: Long
): Option[definitions.GetRewardAccountingActivityTotalsResponse] =
): definitions.GetRewardAccountingActivityTotalsResponse =
consoleEnvironment.run {
httpCommand(HttpScanAppClient.GetRewardAccountingActivityTotals(roundNumber))
}

@Help.Summary("Get CIP-0104 root hash for a specific round")
def getRewardAccountingRootHash(
roundNumber: Long
): Option[definitions.GetRewardAccountingRootHashResponse] =
): definitions.GetRewardAccountingRootHashResponse =
consoleEnvironment.run {
httpCommand(HttpScanAppClient.GetRewardAccountingRootHash(roundNumber))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import org.lfdecentralizedtrust.splice.config.ConfigTransforms.{
}
import org.lfdecentralizedtrust.splice.http.v0.definitions
import definitions.DamlValueEncoding.members.CompactJson
import definitions.GetRewardAccountingActivityTotalsResponse
import definitions.GetRewardAccountingRootHashResponse
import org.lfdecentralizedtrust.splice.integration.EnvironmentDefinition
import org.lfdecentralizedtrust.splice.integration.tests.SpliceTests.IntegrationTestWithIsolatedEnvironment
import org.lfdecentralizedtrust.splice.integration.tests.TokenStandardTest.CreateAllocationRequestResult
Expand Down Expand Up @@ -88,9 +90,11 @@ class TrafficBasedRewardsTimeBasedIntegrationTest

assertOldestOpenRound(0)

clue("Reward accounting endpoints return 404 before any data is available") {
clue("Reward accounting endpoints report 'Undetermined' before any data is available") {
sv1ScanBackend.getRewardAccountingEarliestAvailableRound() shouldBe None
sv1ScanBackend.getRewardAccountingActivityTotals(0L) shouldBe None
sv1ScanBackend.getRewardAccountingActivityTotals(0L) shouldBe an[
GetRewardAccountingActivityTotalsResponse.members.RewardAccountingActivityTotalsUndetermined
]
}

// Here we perform all settlements with verdict ingestion paused just to
Expand Down Expand Up @@ -237,26 +241,38 @@ class TrafficBasedRewardsTimeBasedIntegrationTest
}

clue("Verify activity totals for the computed round") {
val totals = sv1ScanBackend.getRewardAccountingActivityTotals(earliest)
totals.value.roundNumber shouldBe earliest
totals.value.activityRecordsCount should be > 0L
val totals = inside(sv1ScanBackend.getRewardAccountingActivityTotals(earliest)) {
case GetRewardAccountingActivityTotalsResponse.members
.RewardAccountingActivityTotalsOk(t) =>
t
}
totals.roundNumber shouldBe earliest
totals.activityRecordsCount should be > 0L
}

clue("Verify root hash is available") {
val rootHash = sv1ScanBackend.getRewardAccountingRootHash(earliest)
rootHash shouldBe defined
rootHash.value.roundNumber shouldBe earliest
rootHash.value.rootHash should have length 64 // hex-encoded SHA-256
val rootHash = inside(sv1ScanBackend.getRewardAccountingRootHash(earliest)) {
case GetRewardAccountingRootHashResponse.members.RewardAccountingRootHashOk(h) => h
}
rootHash.roundNumber shouldBe earliest
rootHash.rootHash should have length 64 // hex-encoded SHA-256
}

clue("Verify batch lookup for root hash returns batch contents") {
val rootHashHex = sv1ScanBackend.getRewardAccountingRootHash(earliest).value.rootHash
val rootHashHex = inside(sv1ScanBackend.getRewardAccountingRootHash(earliest)) {
case GetRewardAccountingRootHashResponse.members.RewardAccountingRootHashOk(h) =>
h.rootHash
}
sv1ScanBackend.getRewardAccountingBatch(earliest, rootHashHex) shouldBe defined
}

clue("Verify 404 for non-existent data") {
sv1ScanBackend.getRewardAccountingActivityTotals(earliest + 100) shouldBe None
sv1ScanBackend.getRewardAccountingRootHash(earliest + 100) shouldBe None
clue("Verify response for non-existent data") {
sv1ScanBackend.getRewardAccountingActivityTotals(earliest + 100) shouldBe an[
GetRewardAccountingActivityTotalsResponse.members.RewardAccountingActivityTotalsUndetermined
]
sv1ScanBackend.getRewardAccountingRootHash(earliest + 100) shouldBe an[
GetRewardAccountingRootHashResponse.members.RewardAccountingRootHashUndetermined
]
sv1ScanBackend.getRewardAccountingBatch(earliest, "0" * 64) shouldBe None
}
}
Expand Down
76 changes: 68 additions & 8 deletions apps/scan/src/main/openapi/scan.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1859,7 +1859,7 @@ paths:
"500":
$ref: "../../../../common/src/main/openapi/common-external.yaml#/components/responses/500"

/v0/reward-accounting-process/rounds/earliest-available:
/v0/internal/reward-accounting-process/rounds/earliest-available:
get:
tags: [internal, scan]
x-jvm-package: scan
Expand All @@ -1878,7 +1878,7 @@ paths:
"404":
$ref: "../../../../common/src/main/openapi/common-external.yaml#/components/responses/404"

/v0/reward-accounting-process/rounds/{round_number}/activity-totals:
/v0/internal/reward-accounting-process/rounds/{round_number}/activity-totals:
get:
tags: [internal, scan]
x-jvm-package: scan
Expand All @@ -1901,10 +1901,8 @@ paths:
application/json:
schema:
"$ref": "#/components/schemas/GetRewardAccountingActivityTotalsResponse"
"404":
$ref: "../../../../common/src/main/openapi/common-external.yaml#/components/responses/404"

/v0/reward-accounting-process/rounds/{round_number}/root-hash:
/v0/internal/reward-accounting-process/rounds/{round_number}/root-hash:
get:
tags: [internal, scan]
x-jvm-package: scan
Expand All @@ -1926,10 +1924,8 @@ paths:
application/json:
schema:
"$ref": "#/components/schemas/GetRewardAccountingRootHashResponse"
"404":
$ref: "../../../../common/src/main/openapi/common-external.yaml#/components/responses/404"

/v0/reward-accounting-process/rounds/{round_number}/batches/{batch_hash}:
/v0/internal/reward-accounting-process/rounds/{round_number}/batches/{batch_hash}:
get:
tags: [internal, scan]
x-jvm-package: scan
Expand Down Expand Up @@ -4700,13 +4696,29 @@ components:
format: int64

GetRewardAccountingActivityTotalsResponse:
type: object
oneOf:
- "$ref": "#/components/schemas/RewardAccountingActivityTotalsOk"
- "$ref": "#/components/schemas/RewardAccountingActivityTotalsUndetermined"
- "$ref": "#/components/schemas/RewardAccountingActivityTotalsCannotProvide"
discriminator:
propertyName: status
mapping:
Ok: "#/components/schemas/RewardAccountingActivityTotalsOk"
Undetermined: "#/components/schemas/RewardAccountingActivityTotalsUndetermined"
CannotProvide: "#/components/schemas/RewardAccountingActivityTotalsCannotProvide"

RewardAccountingActivityTotalsOk:
type: object
required:
- status
- round_number
- total_app_activity_weight
- active_parties_count
- activity_records_count
properties:
status:
type: string
round_number:
type: integer
format: int64
Expand All @@ -4720,19 +4732,67 @@ components:
type: integer
format: int64

RewardAccountingActivityTotalsUndetermined:
type: object
required:
- status
properties:
status:
type: string

RewardAccountingActivityTotalsCannotProvide:
type: object
required:
- status
properties:
status:
type: string

GetRewardAccountingRootHashResponse:
type: object
oneOf:
- "$ref": "#/components/schemas/RewardAccountingRootHashOk"
- "$ref": "#/components/schemas/RewardAccountingRootHashUndetermined"
- "$ref": "#/components/schemas/RewardAccountingRootHashCannotProvide"
discriminator:
propertyName: status
mapping:
Ok: "#/components/schemas/RewardAccountingRootHashOk"
Undetermined: "#/components/schemas/RewardAccountingRootHashUndetermined"
CannotProvide: "#/components/schemas/RewardAccountingRootHashCannotProvide"

RewardAccountingRootHashOk:
type: object
required:
- status
- round_number
- root_hash
properties:
status:
type: string
round_number:
type: integer
format: int64
root_hash:
type: string
description: Hex-encoded root hash

RewardAccountingRootHashUndetermined:
type: object
required:
- status
properties:
status:
type: string

RewardAccountingRootHashCannotProvide:
type: object
required:
- status
properties:
status:
type: string

GetRewardAccountingBatchResponse:
type: object
oneOf:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import org.lfdecentralizedtrust.splice.http.HttpClient
import org.lfdecentralizedtrust.splice.http.v0.definitions.{
AnsEntry,
GetDsoInfoResponse,
GetRewardAccountingBatchResponse,
GetRewardAccountingRootHashResponse,
HoldingsSummaryRequestV1,
HoldingsSummaryResponse,
HoldingsSummaryResponseV1,
Expand Down Expand Up @@ -740,6 +742,18 @@ class BftScanConnection(
ec: ExecutionContext,
tc: TraceContext,
): Future[NonNegativeInt] = bftCall(_.getActivePhysicalSynchronizerSerial())

override def getRewardAccountingRootHash(roundNumber: Long)(implicit
ec: ExecutionContext,
tc: TraceContext,
): Future[GetRewardAccountingRootHashResponse] =
bftCall(_.getRewardAccountingRootHash(roundNumber))

override def getRewardAccountingBatch(roundNumber: Long, batchHash: String)(implicit
ec: ExecutionContext,
tc: TraceContext,
): Future[Option[GetRewardAccountingBatchResponse]] =
bftCall(_.getRewardAccountingBatch(roundNumber, batchHash))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to check whether doing BFT calls for this endpoint using the standard code path works as expected, as deviations in the responses are expected. I suspect we might be logging mismatches too aggressively.

Nothing to do right now, but something to be aware of.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, at the moment this is just to compile the code. When the triggers actually use BFT client, we will have to circle back to these concerns.

}
trait HasUrl {
def url: Uri
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import org.lfdecentralizedtrust.splice.environment.*
import org.lfdecentralizedtrust.splice.http.HttpClient
import org.lfdecentralizedtrust.splice.http.v0.definitions.{
GetDsoInfoResponse,
GetRewardAccountingBatchResponse,
GetRewardAccountingRootHashResponse,
HoldingsSummaryResponse,
HoldingsSummaryResponseV1,
LookupTransferCommandStatusResponse,
Expand Down Expand Up @@ -323,6 +325,16 @@ trait ScanConnection
tc: TraceContext,
): Future[NonNegativeInt]

def getRewardAccountingRootHash(roundNumber: Long)(implicit
ec: ExecutionContext,
tc: TraceContext,
): Future[GetRewardAccountingRootHashResponse]

def getRewardAccountingBatch(roundNumber: Long, batchHash: String)(implicit
ec: ExecutionContext,
tc: TraceContext,
): Future[Option[GetRewardAccountingBatchResponse]]

}

object ScanConnection {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import org.lfdecentralizedtrust.splice.environment.{
}
import org.lfdecentralizedtrust.splice.http.HttpClient
import org.lfdecentralizedtrust.splice.http.v0.definitions.{
GetRewardAccountingBatchResponse,
GetRewardAccountingRootHashResponse,
HoldingsSummaryRequestV1,
HoldingsSummaryResponse,
HoldingsSummaryResponseV1,
Expand Down Expand Up @@ -824,6 +826,24 @@ class SingleScanConnection private[client] (
config.adminApi.url,
HttpScanAppClient.GetActivePhysicalSynchronizerSerial(),
)

override def getRewardAccountingRootHash(roundNumber: Long)(implicit
ec: ExecutionContext,
tc: TraceContext,
): Future[GetRewardAccountingRootHashResponse] =
runHttpCmd(
config.adminApi.url,
HttpScanAppClient.GetRewardAccountingRootHash(roundNumber),
)

override def getRewardAccountingBatch(roundNumber: Long, batchHash: String)(implicit
ec: ExecutionContext,
tc: TraceContext,
): Future[Option[GetRewardAccountingBatchResponse]] =
runHttpCmd(
config.adminApi.url,
HttpScanAppClient.GetRewardAccountingBatch(roundNumber, batchHash),
)
}

object SingleScanConnection {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2900,7 +2900,7 @@ object HttpScanAppClient {
case class GetRewardAccountingActivityTotals(roundNumber: Long)
extends InternalBaseCommand[
http.GetRewardAccountingActivityTotalsResponse,
Option[definitions.GetRewardAccountingActivityTotalsResponse],
definitions.GetRewardAccountingActivityTotalsResponse,
] {
override def submitRequest(
client: ScanClient,
Expand All @@ -2913,16 +2913,14 @@ object HttpScanAppClient {

override def handleOk()(implicit decoder: TemplateJsonDecoder) = {
case http.GetRewardAccountingActivityTotalsResponse.OK(response) =>
Right(Some(response))
case http.GetRewardAccountingActivityTotalsResponse.NotFound(_) =>
Right(None)
Right(response)
}
}

case class GetRewardAccountingRootHash(roundNumber: Long)
extends InternalBaseCommand[
http.GetRewardAccountingRootHashResponse,
Option[definitions.GetRewardAccountingRootHashResponse],
definitions.GetRewardAccountingRootHashResponse,
] {
override def submitRequest(
client: ScanClient,
Expand All @@ -2935,9 +2933,7 @@ object HttpScanAppClient {

override def handleOk()(implicit decoder: TemplateJsonDecoder) = {
case http.GetRewardAccountingRootHashResponse.OK(response) =>
Right(Some(response))
case http.GetRewardAccountingRootHashResponse.NotFound(_) =>
Right(None)
Right(response)
}
}

Expand Down
Loading
Loading