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 @@ -49,28 +49,40 @@ class MergeMemberTrafficContractsTrigger(
// Skip contracts with invalid member ids
Future.successful(TaskSuccess(s"Skipping MemberTraffic with invalid memberId: ${err}"))
},
memberId => {
for {
dsoRules <- store.getDsoRules()
threshold = dsoRules.payload.config.numMemberTrafficContractsThreshold
synchronizerId = SynchronizerId.tryFromString(memberTraffic.payload.synchronizerId)
memberTraffics <- store.listMemberTrafficContracts(
memberId,
synchronizerId,
PageLimit.tryCreate(2 * threshold.toInt),
)
outcome <-
if (memberTraffics.length > threshold)
mergeMemberTrafficContracts(memberId, memberTraffics, controller)
else
memberId =>
SynchronizerId
.fromString(memberTraffic.payload.synchronizerId)
.fold(
err => {
// Unlike a foreign synchronizer id, an unparseable one means corrupt data and
// should never be routine, so it is worth an alarm as well as a skip.
logger.warn(s"Skipping MemberTraffic with unparseable synchronizerId: ${err}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Can we just avoid parsing the synchronizer id in the first place? I don't really see why we shouldn't merge for an unmergeable sync id.

Future.successful(
TaskSuccess(
s"More than ${threshold} member traffic contracts are required for $memberId on domain $synchronizerId " +
s"in order to merge them. Currently, there are only ${memberTraffics.length}."
)
TaskSuccess(s"Skipping MemberTraffic with invalid synchronizerId: ${err}")
Comment thread
sadiq1971 marked this conversation as resolved.
)
} yield outcome
},
},
synchronizerId =>
for {
dsoRules <- store.getDsoRules()
threshold = dsoRules.payload.config.numMemberTrafficContractsThreshold
memberTraffics <- store.listMemberTrafficContracts(
memberId,
synchronizerId,
PageLimit.tryCreate(2 * threshold.toInt),
)
outcome <-
if (memberTraffics.length > threshold)
mergeMemberTrafficContracts(memberId, memberTraffics, controller)
else
Future.successful(
TaskSuccess(
s"More than ${threshold} member traffic contracts are required for " +
s"$memberId on domain $synchronizerId in order to merge them. " +
s"Currently, there are only ${memberTraffics.length}."
)
)
} yield outcome,
),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,60 +64,81 @@ class ReconcileSequencerLimitWithMemberTrafficTrigger(
// Skip contracts with invalid member ids
Future.successful(TaskSuccess(s"Skipping MemberTraffic with invalid memberId: ${err}"))
},
memberId => {
val synchronizerId = SynchronizerId.tryFromString(memberTraffic.payload.synchronizerId)
synchronizerNodeService.sequencerAdminConnection().flatMap { sequencerAdminConnection =>
sequencerAdminConnection.getStatus
.map(_.successOption.map(_.synchronizerId))
.flatMap {
case None =>
Future.failed(
Status.FAILED_PRECONDITION
.withDescription("Sequencer is not yet initialized")
.asRuntimeException()
)
case Some(sequencerSynchronizerId)
if sequencerSynchronizerId.logical != synchronizerId =>
Future.failed(
Status.INTERNAL
.withDescription(
s"The MemberTraffic contract synchronizerId must match the connected domain ${sequencerSynchronizerId}"
)
.asRuntimeException()
)
case _ =>
store
.getDsoRulesWithSvNodeStates()
.flatMap(rulesAndStates => {
if (
rulesAndStates
.activeSvParticipantAndMediatorIds(synchronizerId)
.contains(memberId)
) {
// SVs are granted unlimited traffic and do not need to purchase it via MemberTraffic contracts.
// While the top-up trigger for SV validators is disabled by default, we also explicitly ignore
// SV related MemberTraffic contracts here as a safeguard for the case of 3rd party top-ups
// of SV nodes or an SV validator misconfiguration that changes the defaults.
Future
.successful(
TaskSuccess(s"Skipping MemberTraffic contract for SV node $memberId")
memberId =>
SynchronizerId
.fromString(memberTraffic.payload.synchronizerId)
.fold(
err => {
// Unlike a foreign synchronizer id, an unparseable one means corrupt data and
// should never be routine, so it is worth an alarm as well as a skip.
logger.warn(s"Skipping MemberTraffic with unparseable synchronizerId: ${err}")
Future.successful(
TaskSuccess(s"Skipping MemberTraffic with invalid synchronizerId: ${err}")
Comment thread
sadiq1971 marked this conversation as resolved.
)
},
synchronizerId =>
synchronizerNodeService.sequencerAdminConnection().flatMap {
sequencerAdminConnection =>
sequencerAdminConnection.getStatus
.map(_.successOption.map(_.synchronizerId))
.flatMap {
case None =>
Future.failed(
Status.FAILED_PRECONDITION
.withDescription("Sequencer is not yet initialized")
.asRuntimeException()
)
} else {
val trafficLimitOffset =
rulesAndStates.dsoRules.payload.initialTrafficState.asScala
.get(memberId.toProtoPrimitive)
.fold(0L)(_.consumedTraffic)
reconcileExtraTrafficLimitForMember(
memberId,
synchronizerId,
trafficLimitOffset,
sequencerAdminConnection,
)
case Some(sequencerSynchronizerId)
if sequencerSynchronizerId.logical != synchronizerId =>
// Traffic can be purchased for any registered synchronizer, so we
Comment thread
sadiq1971 marked this conversation as resolved.
// observe MemberTraffic contracts that this sequencer does not serve.
// They are granted by the operator of the synchronizer they name, on
// that synchronizer's own sequencer, so skip them here rather than
// failing the trigger.
Future.successful(
TaskSuccess(
s"Skipping MemberTraffic contract for synchronizer " +
Comment thread
sadiq1971 marked this conversation as resolved.
s"$synchronizerId, this sequencer serves " +
s"${sequencerSynchronizerId.logical}"
)
)
case _ =>
store
.getDsoRulesWithSvNodeStates()
.flatMap(rulesAndStates => {
if (
rulesAndStates
.activeSvParticipantAndMediatorIds(synchronizerId)
.contains(memberId)
) {
// SVs are granted unlimited traffic and do not need to purchase
// it via MemberTraffic contracts. While the top-up trigger for SV
// validators is disabled by default, we also explicitly ignore SV
// related MemberTraffic contracts here as a safeguard for the case
// of 3rd party top-ups of SV nodes or an SV validator
// misconfiguration that changes the defaults.
Future
.successful(
TaskSuccess(
s"Skipping MemberTraffic contract for SV node $memberId"
)
)
} else {
val trafficLimitOffset =
rulesAndStates.dsoRules.payload.initialTrafficState.asScala
.get(memberId.toProtoPrimitive)
.fold(0L)(_.consumedTraffic)
reconcileExtraTrafficLimitForMember(
memberId,
synchronizerId,
trafficLimitOffset,
sequencerAdminConnection,
)
}
})
}
})
}
}
},
},
),
)
}

Expand Down
Loading