mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-19 16:57:40 +03:00
Remove most of ErrorFactories [DPP-606] (#13146)
changelog_begin changelog_end
This commit is contained in:
parent
0a52e56ca1
commit
c7c211e4df
@ -16,8 +16,8 @@ import com.daml.lf.transaction.GlobalKey
|
||||
import com.daml.lf.value.Value
|
||||
import com.daml.lf.{VersionRange, language}
|
||||
import org.slf4j.event.Level
|
||||
|
||||
import java.time.{Duration, Instant}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
@Explanation(
|
||||
@ -528,10 +528,11 @@ object LedgerApiErrors extends LedgerApiErrorGroup {
|
||||
id = "LEDGER_ID_MISMATCH",
|
||||
ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing,
|
||||
) {
|
||||
case class Reject(override val cause: String)(implicit
|
||||
case class Reject(_expectedLedgerId: String, _receivedLegerId: String)(implicit
|
||||
loggingContext: ContextualizedErrorLogger
|
||||
) extends LoggingTransactionErrorImpl(
|
||||
cause = cause,
|
||||
cause =
|
||||
s"Ledger ID '${_receivedLegerId}' not found. Actual Ledger ID is '${_expectedLedgerId}'.",
|
||||
definiteAnswer = true,
|
||||
)
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ trait TransactionError extends BaseError {
|
||||
)(implicit loggingContext: ContextualizedErrorLogger): RpcStatus =
|
||||
_rpcStatus(None, correlationId)
|
||||
|
||||
// TODO error codes: this impl vs. GrpcStatus.toProto
|
||||
def _rpcStatus(
|
||||
overrideCode: Option[Status.Code],
|
||||
correlationId: Option[String],
|
||||
|
@ -213,7 +213,11 @@ final class Authorizer(
|
||||
private def authorizationErrorAsGrpc[T](
|
||||
errOrV: Either[AuthorizationError, T]
|
||||
): Either[StatusRuntimeException, T] =
|
||||
errOrV.fold(err => Left(ErrorFactories.permissionDenied(err.reason)), Right(_))
|
||||
errOrV.fold(
|
||||
err =>
|
||||
Left(LedgerApiErrors.AuthorizationChecks.PermissionDenied.Reject(err.reason).asGrpcError),
|
||||
Right(_),
|
||||
)
|
||||
|
||||
private def assertServerCall[A](observer: StreamObserver[A]): ServerCallStreamObserver[A] =
|
||||
observer match {
|
||||
@ -247,15 +251,21 @@ final class Authorizer(
|
||||
.extractClaimSetFromContext()
|
||||
.flatMap({
|
||||
case ClaimSet.Unauthenticated =>
|
||||
Failure(ErrorFactories.unauthenticatedMissingJwtToken())
|
||||
Failure(
|
||||
LedgerApiErrors.AuthorizationChecks.Unauthenticated
|
||||
.MissingJwtToken()
|
||||
.asGrpcError
|
||||
)
|
||||
case authenticatedUser: ClaimSet.AuthenticatedUser =>
|
||||
Failure(
|
||||
ErrorFactories.internalAuthenticationError(
|
||||
s"Unexpected unresolved authenticated user claim",
|
||||
new RuntimeException(
|
||||
s"Unexpected unresolved authenticated user claim for user '${authenticatedUser.userId}"
|
||||
),
|
||||
)
|
||||
LedgerApiErrors.AuthorizationChecks.InternalAuthorizationError
|
||||
.Reject(
|
||||
s"Unexpected unresolved authenticated user claim",
|
||||
new RuntimeException(
|
||||
s"Unexpected unresolved authenticated user claim for user '${authenticatedUser.userId}"
|
||||
),
|
||||
)
|
||||
.asGrpcError
|
||||
)
|
||||
case claims: ClaimSet.Claims => Success(claims)
|
||||
})
|
||||
|
@ -11,7 +11,6 @@ import com.daml.error.DamlContextualizedErrorLogger
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.participant.state.index.v2.UserManagementStore
|
||||
import com.daml.logging.{ContextualizedLogger, LoggingContext}
|
||||
import com.daml.platform.server.api.validation.ErrorFactories
|
||||
import io.grpc.StatusRuntimeException
|
||||
import io.grpc.stub.ServerCallStreamObserver
|
||||
|
||||
@ -113,7 +112,9 @@ private[auth] final class OngoingAuthorizationObserver[A](
|
||||
.notExpired(now)
|
||||
.left
|
||||
.map(authorizationError =>
|
||||
ErrorFactories.permissionDenied(authorizationError.reason)(errorLogger)
|
||||
LedgerApiErrors.AuthorizationChecks.PermissionDenied
|
||||
.Reject(authorizationError.reason)(errorLogger)
|
||||
.asGrpcError
|
||||
)
|
||||
|
||||
private def staleStreamAuthError: StatusRuntimeException =
|
||||
|
@ -58,10 +58,12 @@ final class AuthorizationInterceptor(
|
||||
case Failure(error: StatusRuntimeException) =>
|
||||
closeWithError(error)
|
||||
case Failure(exception: Throwable) =>
|
||||
val error = ErrorFactories.internalAuthenticationError(
|
||||
securitySafeMessage = "Failed to get claims from request metadata",
|
||||
exception = exception,
|
||||
)(errorLogger)
|
||||
val error = LedgerApiErrors.AuthorizationChecks.InternalAuthorizationError
|
||||
.Reject(
|
||||
message = "Failed to get claims from request metadata",
|
||||
throwable = exception,
|
||||
)(errorLogger)
|
||||
.asGrpcError
|
||||
closeWithError(error)
|
||||
case Success(claimSet) =>
|
||||
val nextCtx = prevCtx.withValue(AuthorizationInterceptor.contextKeyClaimSet, claimSet)
|
||||
@ -85,9 +87,11 @@ final class AuthorizationInterceptor(
|
||||
claimsSet <- userRightsResult match {
|
||||
case Left(msg) =>
|
||||
Future.failed(
|
||||
ErrorFactories.permissionDenied(
|
||||
s"Could not resolve rights for user '$userId' due to '$msg'"
|
||||
)(errorLogger)
|
||||
LedgerApiErrors.AuthorizationChecks.PermissionDenied
|
||||
.Reject(
|
||||
s"Could not resolve rights for user '$userId' due to '$msg'"
|
||||
)(errorLogger)
|
||||
.asGrpcError
|
||||
)
|
||||
case Right(userRights: Set[UserRight]) =>
|
||||
Future.successful(
|
||||
|
@ -4,11 +4,11 @@
|
||||
package com.daml.ledger.client.services.commands.tracker
|
||||
|
||||
import com.daml.error.ContextualizedErrorLogger
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.grpc.GrpcStatus
|
||||
import com.daml.ledger.api.v1.command_completion_service.Checkpoint
|
||||
import com.daml.ledger.api.v1.completion.Completion
|
||||
import com.daml.ledger.grpc.GrpcStatuses
|
||||
import com.daml.platform.server.api.validation.ErrorFactories
|
||||
import com.google.rpc.status.{Status => StatusProto}
|
||||
import com.google.rpc.{Status => StatusJavaProto}
|
||||
import io.grpc.Status.Code
|
||||
@ -117,9 +117,20 @@ object CompletionResponse {
|
||||
val statusBuilder = GrpcStatus.toJavaBuilder(notOkResponse.grpcStatus)
|
||||
GrpcStatus.buildStatus(metadata, statusBuilder)
|
||||
case CompletionResponse.TimeoutResponse(_) =>
|
||||
ErrorFactories.SubmissionQueueErrors.timedOutOnAwaitingForCommandCompletion()
|
||||
LedgerApiErrors.RequestTimeOut
|
||||
.Reject(
|
||||
"Timed out while awaiting for a completion corresponding to a command submission.",
|
||||
_definiteAnswer = false,
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
case CompletionResponse.NoStatusInResponse(_, _) =>
|
||||
ErrorFactories.SubmissionQueueErrors.noStatusInCompletionResponse()
|
||||
LedgerApiErrors.InternalError
|
||||
.Generic(
|
||||
"Missing status in completion response.",
|
||||
throwableO = None,
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -38,12 +38,10 @@ da_scala_library(
|
||||
"//ledger/ledger-api-akka",
|
||||
"//ledger/ledger-api-domain",
|
||||
"//ledger/ledger-api-health",
|
||||
"//ledger/ledger-grpc",
|
||||
"//ledger/ledger-offset",
|
||||
"//ledger/ledger-resources",
|
||||
"//ledger/metrics",
|
||||
"//libs-scala/contextualized-logging",
|
||||
"//libs-scala/grpc-utils",
|
||||
"//libs-scala/logging-entries",
|
||||
"//libs-scala/resources",
|
||||
"//libs-scala/resources-akka",
|
||||
|
@ -7,6 +7,7 @@ import java.time.{Duration, Instant}
|
||||
|
||||
import com.daml.api.util.{DurationConversion, TimestampConversion}
|
||||
import com.daml.error.ContextualizedErrorLogger
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.api.domain.{LedgerId, optionalLedgerId}
|
||||
import com.daml.ledger.api.v1.commands
|
||||
import com.daml.ledger.api.v1.commands.Command.Command.{
|
||||
@ -230,7 +231,11 @@ final class CommandsValidator(ledgerId: LedgerId) {
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): Either[StatusRuntimeException, DeduplicationPeriod] =
|
||||
optMaxDeduplicationDuration.fold[Either[StatusRuntimeException, DeduplicationPeriod]](
|
||||
Left(missingLedgerConfig())
|
||||
Left(
|
||||
LedgerApiErrors.RequestValidation.NotFound.LedgerConfiguration
|
||||
.Reject()
|
||||
.asGrpcError
|
||||
)
|
||||
) { maxDeduplicationDuration =>
|
||||
deduplicationPeriod match {
|
||||
case commands.Commands.DeduplicationPeriod.Empty =>
|
||||
@ -251,12 +256,14 @@ final class CommandsValidator(ledgerId: LedgerId) {
|
||||
.fold(
|
||||
_ =>
|
||||
Left(
|
||||
nonHexOffset(
|
||||
fieldName = "deduplication_period",
|
||||
offsetValue = offset,
|
||||
message =
|
||||
s"the deduplication offset has to be a hexadecimal string and not $offset",
|
||||
)
|
||||
LedgerApiErrors.RequestValidation.NonHexOffset
|
||||
.Error(
|
||||
_fieldName = "deduplication_period",
|
||||
_offsetValue = offset,
|
||||
_message =
|
||||
s"the deduplication offset has to be a hexadecimal string and not $offset",
|
||||
)
|
||||
.asGrpcError
|
||||
),
|
||||
hexOffset =>
|
||||
Right(DeduplicationPeriod.DeduplicationOffset(Offset.fromHexString(hexOffset))),
|
||||
|
@ -4,6 +4,7 @@
|
||||
package com.daml.ledger.api.validation
|
||||
|
||||
import com.daml.error.ContextualizedErrorLogger
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.api.domain
|
||||
import com.daml.ledger.api.v1.ledger_offset.LedgerOffset
|
||||
import com.daml.ledger.api.v1.ledger_offset.LedgerOffset.LedgerBoundary
|
||||
@ -16,7 +17,7 @@ object LedgerOffsetValidator {
|
||||
|
||||
private val boundary = "boundary"
|
||||
|
||||
import ErrorFactories.{invalidArgument, missingField, offsetAfterLedgerEnd}
|
||||
import ErrorFactories.{invalidArgument, missingField}
|
||||
import FieldValidations.requireLedgerString
|
||||
|
||||
def validateOptional(
|
||||
@ -56,7 +57,11 @@ object LedgerOffsetValidator {
|
||||
): Either[StatusRuntimeException, Unit] =
|
||||
ledgerOffset match {
|
||||
case abs: domain.LedgerOffset.Absolute if abs > ledgerEnd =>
|
||||
Left(offsetAfterLedgerEnd(offsetType, abs.value, ledgerEnd.value))
|
||||
Left(
|
||||
LedgerApiErrors.RequestValidation.OffsetAfterLedgerEnd
|
||||
.Reject(offsetType, abs.value, ledgerEnd.value)
|
||||
.asGrpcError
|
||||
)
|
||||
case _ => Right(())
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ class GrpcHealthService(
|
||||
private val errorLogger: ContextualizedErrorLogger =
|
||||
new DamlContextualizedErrorLogger(logger, loggingContext, None)
|
||||
|
||||
import ErrorFactories.invalidArgumentWasNotFound
|
||||
import ErrorFactories.invalidArgument
|
||||
|
||||
override def bindService(): ServerServiceDefinition =
|
||||
HealthGrpc.bindService(this, executionContext)
|
||||
@ -60,7 +60,7 @@ class GrpcHealthService(
|
||||
.collect {
|
||||
case component if !healthChecks.hasComponent(component) =>
|
||||
Failure(
|
||||
invalidArgumentWasNotFound(s"Component $component does not exist.")(errorLogger)
|
||||
invalidArgument(s"Component $component does not exist.")(errorLogger)
|
||||
)
|
||||
}
|
||||
.getOrElse {
|
||||
|
@ -6,6 +6,7 @@ package com.daml.platform.server.api.validation
|
||||
import java.time.Duration
|
||||
|
||||
import com.daml.error.ContextualizedErrorLogger
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.api.DeduplicationPeriod
|
||||
import io.grpc.StatusRuntimeException
|
||||
|
||||
@ -31,10 +32,12 @@ object DeduplicationPeriodValidator {
|
||||
validateNonNegativeDuration(duration).flatMap { duration =>
|
||||
if (duration.compareTo(maxDeduplicationDuration) > 0)
|
||||
Left(
|
||||
ErrorFactories.invalidDeduplicationPeriod(
|
||||
s"The given deduplication duration of $duration exceeds the maximum deduplication duration of $maxDeduplicationDuration",
|
||||
Some(maxDeduplicationDuration),
|
||||
)
|
||||
LedgerApiErrors.RequestValidation.InvalidDeduplicationPeriodField
|
||||
.Reject(
|
||||
s"The given deduplication duration of $duration exceeds the maximum deduplication duration of $maxDeduplicationDuration",
|
||||
Some(maxDeduplicationDuration),
|
||||
)
|
||||
.asGrpcError
|
||||
)
|
||||
else Right(duration)
|
||||
}
|
||||
|
@ -3,125 +3,15 @@
|
||||
|
||||
package com.daml.platform.server.api.validation
|
||||
|
||||
import java.sql.{SQLNonTransientException, SQLTransientException}
|
||||
import java.time.{Duration, Instant}
|
||||
|
||||
import com.daml.error.definitions.{IndexErrors, LedgerApiErrors}
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.error.ContextualizedErrorLogger
|
||||
import com.daml.grpc.GrpcStatus
|
||||
import com.daml.ledger.api.domain.LedgerId
|
||||
import com.daml.ledger.grpc.GrpcStatuses
|
||||
import com.daml.ledger.offset.Offset
|
||||
import com.daml.lf.data.Ref.TransactionId
|
||||
import com.daml.lf.transaction.GlobalKey
|
||||
import com.daml.lf.value.Value
|
||||
import com.daml.platform.server.api.{ApiException => NoStackTraceApiException}
|
||||
import com.google.protobuf.{Any => AnyProto}
|
||||
import com.google.rpc.{ErrorInfo, Status}
|
||||
import io.grpc.Status.Code
|
||||
import com.google.rpc.Status
|
||||
import io.grpc.protobuf.StatusProto
|
||||
import io.grpc.StatusRuntimeException
|
||||
import scalaz.syntax.tag._
|
||||
|
||||
object ErrorFactories {
|
||||
|
||||
object SubmissionQueueErrors {
|
||||
def failedToEnqueueCommandSubmission(message: String)(t: Throwable)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): Status =
|
||||
LedgerApiErrors.InternalError
|
||||
.Generic(
|
||||
message = s"$message: ${t.getClass.getSimpleName}: ${t.getMessage}",
|
||||
throwableO = Some(t),
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
|
||||
def queueClosed(queueName: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): Status =
|
||||
LedgerApiErrors.ServiceNotRunning
|
||||
.Reject(queueName)
|
||||
.asGrpcStatusFromContext
|
||||
|
||||
def timedOutOnAwaitingForCommandCompletion()(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): Status =
|
||||
LedgerApiErrors.RequestTimeOut
|
||||
.Reject(
|
||||
"Timed out while awaiting for a completion corresponding to a command submission.",
|
||||
_definiteAnswer = false,
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
|
||||
def noStatusInCompletionResponse()(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): Status =
|
||||
LedgerApiErrors.InternalError
|
||||
.Generic(
|
||||
"Missing status in completion response.",
|
||||
throwableO = None,
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
}
|
||||
|
||||
def bufferFull(message: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): Status =
|
||||
LedgerApiErrors.ParticipantBackpressure
|
||||
.Rejection(message)
|
||||
.asGrpcStatusFromContext
|
||||
|
||||
def sqlTransientException(exception: SQLTransientException)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
IndexErrors.DatabaseErrors.SqlTransientError.Reject(exception).asGrpcError
|
||||
|
||||
def sqlNonTransientException(exception: SQLNonTransientException)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
IndexErrors.DatabaseErrors.SqlNonTransientError.Reject(exception).asGrpcError
|
||||
|
||||
def transactionNotFound(transactionId: TransactionId)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.RequestValidation.NotFound.Transaction
|
||||
.Reject(transactionId)
|
||||
.asGrpcError
|
||||
|
||||
def packageNotFound(packageId: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.RequestValidation.NotFound.Package
|
||||
.Reject(_packageId = packageId)
|
||||
.asGrpcError
|
||||
|
||||
def versionServiceInternalError(message: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.InternalError.VersionService(message).asGrpcError
|
||||
|
||||
def duplicateCommandException(existingSubmissionId: Option[String])(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.ConsistencyErrors.DuplicateCommand
|
||||
.Reject(_existingCommandSubmissionId = existingSubmissionId)
|
||||
.asGrpcError
|
||||
|
||||
/** @param expected Expected ledger id.
|
||||
* @param received Received ledger id.
|
||||
* @return An exception with the [[Code.NOT_FOUND]] status code.
|
||||
*/
|
||||
def ledgerIdMismatch(
|
||||
expected: LedgerId,
|
||||
received: LedgerId,
|
||||
)(implicit contextualizedErrorLogger: ContextualizedErrorLogger): StatusRuntimeException = {
|
||||
LedgerApiErrors.RequestValidation.LedgerIdMismatch
|
||||
.Reject(
|
||||
s"Ledger ID '${received.unwrap}' not found. Actual Ledger ID is '${expected.unwrap}'."
|
||||
)
|
||||
.asGrpcError
|
||||
}
|
||||
|
||||
/** @param fieldName A missing field's name.
|
||||
* @return An exception with the [[Code.INVALID_ARGUMENT]] status code.
|
||||
*/
|
||||
@ -142,47 +32,6 @@ object ErrorFactories {
|
||||
.Reject(message)
|
||||
.asGrpcError
|
||||
|
||||
// This error builder covers cases where existing logic handling invalid arguments returned NOT_FOUND.
|
||||
def invalidArgumentWasNotFound(message: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.RequestValidation.InvalidArgument
|
||||
.Reject(message)
|
||||
.asGrpcError
|
||||
|
||||
def offsetOutOfRange(message: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.RequestValidation.OffsetOutOfRange
|
||||
.Reject(message)
|
||||
.asGrpcError
|
||||
|
||||
def offsetAfterLedgerEnd(offsetType: String, requestedOffset: String, ledgerEnd: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.RequestValidation.OffsetAfterLedgerEnd
|
||||
.Reject(offsetType, requestedOffset, ledgerEnd)
|
||||
.asGrpcError
|
||||
|
||||
def nonHexOffset(fieldName: String, offsetValue: String, message: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.RequestValidation.NonHexOffset
|
||||
.Error(
|
||||
_fieldName = fieldName,
|
||||
_offsetValue = offsetValue,
|
||||
_message = message,
|
||||
)
|
||||
.asGrpcError
|
||||
|
||||
def invalidDeduplicationPeriod(
|
||||
message: String,
|
||||
maxDeduplicationDuration: Option[Duration],
|
||||
)(implicit contextualizedErrorLogger: ContextualizedErrorLogger): StatusRuntimeException =
|
||||
LedgerApiErrors.RequestValidation.InvalidDeduplicationPeriodField
|
||||
.Reject(message, maxDeduplicationDuration)
|
||||
.asGrpcError
|
||||
|
||||
/** @param fieldName An invalid field's name.
|
||||
* @param message A status' message.
|
||||
* @return An exception with the [[Code.INVALID_ARGUMENT]] status code.
|
||||
@ -191,101 +40,10 @@ object ErrorFactories {
|
||||
fieldName: String,
|
||||
message: String,
|
||||
)(implicit contextualizedErrorLogger: ContextualizedErrorLogger): StatusRuntimeException =
|
||||
ledgerRequestValidationInvalidField(fieldName, message).asGrpcError
|
||||
|
||||
private def ledgerRequestValidationInvalidField(fieldName: String, message: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): LedgerApiErrors.RequestValidation.InvalidField.Reject = {
|
||||
LedgerApiErrors.RequestValidation.InvalidField
|
||||
.Reject(s"Invalid field $fieldName: $message")
|
||||
}
|
||||
|
||||
/** @param message A status' message.
|
||||
* @param definiteAnswer A flag that says whether it is a definite answer. Provided only in the context of command deduplication.
|
||||
* @return An exception with the [[Code.ABORTED]] status code.
|
||||
*/
|
||||
@deprecated
|
||||
def aborted(message: String, definiteAnswer: Option[Boolean]): StatusRuntimeException = {
|
||||
val statusBuilder = Status
|
||||
.newBuilder()
|
||||
.setCode(Code.ABORTED.value())
|
||||
.setMessage(message)
|
||||
addDefiniteAnswerDetails(definiteAnswer, statusBuilder)
|
||||
grpcError(statusBuilder.build())
|
||||
}
|
||||
|
||||
def isTimeoutUnknown_wasAborted(message: String, definiteAnswer: Option[Boolean])(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.RequestTimeOut
|
||||
.Reject(message, definiteAnswer.getOrElse(false))
|
||||
.asGrpcError
|
||||
|
||||
def packageUploadRejected(message: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.AdminServices.PackageUploadRejected.Reject(message).asGrpcError
|
||||
|
||||
def configurationEntryRejected(message: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.AdminServices.ConfigurationEntryRejected.Reject(message).asGrpcError
|
||||
|
||||
// permission denied is intentionally without description to ensure we don't leak security relevant information by accident
|
||||
def permissionDenied(cause: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.AuthorizationChecks.PermissionDenied.Reject(cause).asGrpcError
|
||||
|
||||
def unauthenticatedMissingJwtToken()(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.AuthorizationChecks.Unauthenticated
|
||||
.MissingJwtToken()
|
||||
.asGrpcError
|
||||
|
||||
def internalAuthenticationError(securitySafeMessage: String, exception: Throwable)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.AuthorizationChecks.InternalAuthorizationError
|
||||
.Reject(securitySafeMessage, exception)
|
||||
.asGrpcError
|
||||
|
||||
def missingLedgerConfig()(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.RequestValidation.NotFound.LedgerConfiguration
|
||||
.Reject()
|
||||
.asGrpcError
|
||||
|
||||
def missingLedgerConfig(message: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): com.google.rpc.status.Status =
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.RequestValidation.NotFound.LedgerConfiguration
|
||||
.RejectWithMessage(message)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
|
||||
def participantPrunedDataAccessed(message: String, earliestOffset: Offset)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.RequestValidation.ParticipantPrunedDataAccessed
|
||||
.Reject(message, earliestOffset.toHexString)
|
||||
.asGrpcError
|
||||
|
||||
/** @return An exception with the [[Code.UNAVAILABLE]] status code.
|
||||
*/
|
||||
def serviceNotRunning(serviceName: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.ServiceNotRunning.Reject(serviceName).asGrpcError
|
||||
|
||||
def trackerFailure(msg: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): StatusRuntimeException =
|
||||
LedgerApiErrors.InternalError.Generic(msg).asGrpcError
|
||||
|
||||
/** Transforms Protobuf [[Status]] objects, possibly including metadata packed as [[ErrorInfo]] objects,
|
||||
* into exceptions with metadata in the trailers.
|
||||
*
|
||||
@ -313,136 +71,4 @@ object ErrorFactories {
|
||||
if (message.length > maxMessageLength) message.take(maxMessageLength) + "..." else message
|
||||
}
|
||||
|
||||
object CommandRejections {
|
||||
@deprecated
|
||||
def partyNotKnownOnLedger(reason: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): com.google.rpc.status.Status =
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.WriteServiceRejections.PartyNotKnownOnLedger
|
||||
.RejectDeprecated(reason)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
|
||||
def contractsNotFound(missingContractIds: Set[String])(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): com.google.rpc.status.Status =
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.ConsistencyErrors.ContractNotFound
|
||||
.MultipleContractsNotFound(missingContractIds)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
|
||||
def inconsistentContractKeys(
|
||||
lookupResult: Option[Value.ContractId],
|
||||
currentResult: Option[Value.ContractId],
|
||||
)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): com.google.rpc.status.Status =
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.ConsistencyErrors.InconsistentContractKey
|
||||
.Reject(
|
||||
s"Contract key lookup with different results: expected [$lookupResult], actual [$currentResult]"
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
|
||||
def duplicateContractKey(reason: String, key: GlobalKey)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): com.google.rpc.status.Status =
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.ConsistencyErrors.DuplicateContractKey
|
||||
.RejectWithContractKeyArg(reason, key)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
|
||||
def partiesNotKnownToLedger(parties: Set[String])(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): com.google.rpc.status.Status =
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.WriteServiceRejections.PartyNotKnownOnLedger
|
||||
.Reject(parties)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
|
||||
def submitterCannotActViaParticipant(reason: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): com.google.rpc.status.Status =
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.WriteServiceRejections.SubmitterCannotActViaParticipant
|
||||
.Reject(reason)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
|
||||
def invalidLedgerTime(reason: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): com.google.rpc.status.Status =
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.ConsistencyErrors.InvalidLedgerTime
|
||||
.RejectSimple(reason)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
|
||||
def invalidLedgerTime(
|
||||
ledgerTime: Instant,
|
||||
ledgerTimeLowerBound: Instant,
|
||||
ledgerTimeUpperBound: Instant,
|
||||
)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): com.google.rpc.status.Status =
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.ConsistencyErrors.InvalidLedgerTime
|
||||
.RejectEnriched(
|
||||
s"Ledger time $ledgerTime outside of range [$ledgerTimeLowerBound, $ledgerTimeUpperBound]",
|
||||
ledgerTime,
|
||||
ledgerTimeLowerBound,
|
||||
ledgerTimeUpperBound,
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
|
||||
def inconsistent(reason: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): com.google.rpc.status.Status =
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.ConsistencyErrors.Inconsistent.Reject(reason).asGrpcStatusFromContext
|
||||
)
|
||||
|
||||
object Deprecated {
|
||||
@deprecated
|
||||
def disputed(reason: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): com.google.rpc.status.Status =
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.WriteServiceRejections.Disputed.Reject(reason).asGrpcStatusFromContext
|
||||
)
|
||||
|
||||
@deprecated
|
||||
def outOfQuota(reason: String)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
): com.google.rpc.status.Status =
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.WriteServiceRejections.OutOfQuota.Reject(reason).asGrpcStatusFromContext
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private[daml] lazy val definiteAnswers = Map(
|
||||
true -> AnyProto.pack[ErrorInfo](
|
||||
ErrorInfo.newBuilder().putMetadata(GrpcStatuses.DefiniteAnswerKey, "true").build()
|
||||
),
|
||||
false -> AnyProto.pack[ErrorInfo](
|
||||
ErrorInfo.newBuilder().putMetadata(GrpcStatuses.DefiniteAnswerKey, "false").build()
|
||||
),
|
||||
)
|
||||
|
||||
private def addDefiniteAnswerDetails(
|
||||
definiteAnswer: Option[Boolean],
|
||||
statusBuilder: Status.Builder,
|
||||
): Unit = {
|
||||
definiteAnswer.foreach { definiteAnswer =>
|
||||
statusBuilder.addDetails(definiteAnswers(definiteAnswer))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
package com.daml.platform.server.api.validation
|
||||
|
||||
import com.daml.error.ContextualizedErrorLogger
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.api.domain
|
||||
import com.daml.ledger.api.domain.LedgerId
|
||||
import com.daml.ledger.api.v1.value.Identifier
|
||||
@ -24,7 +25,12 @@ object FieldValidations {
|
||||
case None => Right(None)
|
||||
case Some(`ledgerId`) => Right(Some(ledgerId))
|
||||
case Some(mismatching) =>
|
||||
Left(ledgerIdMismatch(ledgerId, mismatching))
|
||||
import scalaz.syntax.tag._
|
||||
Left(
|
||||
LedgerApiErrors.RequestValidation.LedgerIdMismatch
|
||||
.Reject(ledgerId.unwrap, mismatching.unwrap)
|
||||
.asGrpcError
|
||||
)
|
||||
}
|
||||
|
||||
def requireNonEmptyString(s: String, fieldName: String)(implicit
|
||||
|
@ -8,7 +8,7 @@ import java.time.Duration
|
||||
import java.util.regex.Pattern
|
||||
|
||||
import ch.qos.logback.classic.Level
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.error.definitions.{IndexErrors, LedgerApiErrors, LoggingTransactionErrorImpl}
|
||||
import com.daml.error.definitions.LedgerApiErrors.RequestValidation.InvalidDeduplicationPeriodField.ValidMaxDeduplicationFieldKey
|
||||
import com.daml.error.utils.ErrorDetails
|
||||
import com.daml.error.{
|
||||
@ -16,27 +16,20 @@ import com.daml.error.{
|
||||
DamlContextualizedErrorLogger,
|
||||
ErrorAssertionsWithLogCollectorAssertions,
|
||||
}
|
||||
import com.daml.ledger.api.domain.LedgerId
|
||||
import com.daml.ledger.offset.Offset
|
||||
import com.daml.lf.data.Ref
|
||||
import com.daml.platform.server.api.validation.ErrorFactories._
|
||||
import com.daml.platform.testing.LogCollector.ExpectedLogEntry
|
||||
import com.daml.platform.testing.{LogCollector, LogCollectorAssertions}
|
||||
import com.google.rpc._
|
||||
import io.grpc.Status.Code
|
||||
import io.grpc.StatusRuntimeException
|
||||
import io.grpc.protobuf.StatusProto
|
||||
import org.mockito.MockitoSugar
|
||||
import org.scalatest.BeforeAndAfter
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.prop.TableDrivenPropertyChecks
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import scala.annotation.nowarn
|
||||
import scala.jdk.CollectionConverters._
|
||||
|
||||
@nowarn("msg=deprecated")
|
||||
class ErrorFactoriesSpec
|
||||
extends AnyWordSpec
|
||||
with Matchers
|
||||
@ -55,6 +48,8 @@ class ErrorFactoriesSpec
|
||||
private val expectedCorrelationIdRequestInfo =
|
||||
ErrorDetails.RequestInfoDetail(originalCorrelationId)
|
||||
private val expectedLocationLogMarkerRegex =
|
||||
"\\{err-context: \"\\{location=ErrorFactoriesSpec.scala:\\d+\\}\"\\}"
|
||||
private val expectedLocationLogMarkerRegexErrorFactories =
|
||||
"\\{err-context: \"\\{location=ErrorFactories.scala:\\d+\\}\"\\}"
|
||||
private val expectedInternalErrorMessage =
|
||||
s"An error occurred. Please contact the operator and inquire about the request $originalCorrelationId"
|
||||
@ -73,7 +68,7 @@ class ErrorFactoriesSpec
|
||||
val msg =
|
||||
s"INDEX_DB_SQL_TRANSIENT_ERROR(1,$truncatedCorrelationId): Processing the request failed due to a transient database error: $failureReason"
|
||||
assertError(
|
||||
ErrorFactories.sqlTransientException(someSqlTransientException)
|
||||
IndexErrors.DatabaseErrors.SqlTransientError.Reject(someSqlTransientException)
|
||||
)(
|
||||
code = Code.UNAVAILABLE,
|
||||
message = msg,
|
||||
@ -98,8 +93,9 @@ class ErrorFactoriesSpec
|
||||
val msg =
|
||||
s"INDEX_DB_SQL_NON_TRANSIENT_ERROR(4,$truncatedCorrelationId): Processing the request failed due to a non-transient database error: $failureReason"
|
||||
assertError(
|
||||
ErrorFactories
|
||||
.sqlNonTransientException(new SQLNonTransientException(failureReason))
|
||||
IndexErrors.DatabaseErrors.SqlNonTransientError.Reject(
|
||||
new SQLNonTransientException(failureReason)
|
||||
)
|
||||
)(
|
||||
code = Code.INTERNAL,
|
||||
message = expectedInternalErrorMessage,
|
||||
@ -116,16 +112,18 @@ class ErrorFactoriesSpec
|
||||
"return failedToEnqueueCommandSubmission" in {
|
||||
val t = new Exception("message123")
|
||||
assertStatus(
|
||||
ErrorFactories.SubmissionQueueErrors.failedToEnqueueCommandSubmission("some message")(t)(
|
||||
contextualizedErrorLogger
|
||||
)
|
||||
LedgerApiErrors.InternalError
|
||||
.Generic("some message", Some(t))(
|
||||
contextualizedErrorLogger
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
)(
|
||||
code = Code.INTERNAL,
|
||||
message = expectedInternalErrorMessage,
|
||||
details = expectedInternalErrorDetails,
|
||||
logEntry = ExpectedLogEntry(
|
||||
Level.ERROR,
|
||||
s"LEDGER_API_INTERNAL_ERROR(4,$truncatedCorrelationId): some message: Exception: message123",
|
||||
s"LEDGER_API_INTERNAL_ERROR(4,$truncatedCorrelationId): some message",
|
||||
expectedMarkerRegex("throwableO=Some(java.lang.Exception: message123)"),
|
||||
),
|
||||
)
|
||||
@ -135,7 +133,9 @@ class ErrorFactoriesSpec
|
||||
val msg =
|
||||
s"PARTICIPANT_BACKPRESSURE(2,$truncatedCorrelationId): The participant is overloaded: Some buffer is full"
|
||||
assertStatus(
|
||||
ErrorFactories.bufferFull("Some buffer is full")(contextualizedErrorLogger)
|
||||
LedgerApiErrors.ParticipantBackpressure
|
||||
.Rejection("Some buffer is full")(contextualizedErrorLogger)
|
||||
.asGrpcStatusFromContext
|
||||
)(
|
||||
code = Code.ABORTED,
|
||||
message = msg,
|
||||
@ -163,9 +163,11 @@ class ErrorFactoriesSpec
|
||||
val msg =
|
||||
s"SERVICE_NOT_RUNNING(1,$truncatedCorrelationId): Some service has been shut down."
|
||||
assertStatus(
|
||||
ErrorFactories.SubmissionQueueErrors.queueClosed("Some service")(
|
||||
contextualizedErrorLogger = contextualizedErrorLogger
|
||||
)
|
||||
LedgerApiErrors.ServiceNotRunning
|
||||
.Reject("Some service")(
|
||||
contextualizedErrorLogger
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
)(
|
||||
code = Code.UNAVAILABLE,
|
||||
message = msg,
|
||||
@ -193,9 +195,14 @@ class ErrorFactoriesSpec
|
||||
val msg =
|
||||
s"REQUEST_TIME_OUT(3,$truncatedCorrelationId): Timed out while awaiting for a completion corresponding to a command submission."
|
||||
assertStatus(
|
||||
ErrorFactories.SubmissionQueueErrors.timedOutOnAwaitingForCommandCompletion()(
|
||||
contextualizedErrorLogger = contextualizedErrorLogger
|
||||
)
|
||||
LedgerApiErrors.RequestTimeOut
|
||||
.Reject(
|
||||
"Timed out while awaiting for a completion corresponding to a command submission.",
|
||||
_definiteAnswer = false,
|
||||
)(
|
||||
contextualizedErrorLogger
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
)(
|
||||
code = Code.DEADLINE_EXCEEDED,
|
||||
message = msg,
|
||||
@ -216,9 +223,12 @@ class ErrorFactoriesSpec
|
||||
}
|
||||
"return noStatusInResponse" in {
|
||||
assertStatus(
|
||||
ErrorFactories.SubmissionQueueErrors.noStatusInCompletionResponse()(
|
||||
contextualizedErrorLogger = contextualizedErrorLogger
|
||||
)
|
||||
LedgerApiErrors.InternalError
|
||||
.Generic(
|
||||
"Missing status in completion response.",
|
||||
throwableO = None,
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
)(
|
||||
code = Code.INTERNAL,
|
||||
message = expectedInternalErrorMessage,
|
||||
@ -236,7 +246,10 @@ class ErrorFactoriesSpec
|
||||
|
||||
"return packageNotFound" in {
|
||||
val msg = s"PACKAGE_NOT_FOUND(11,$truncatedCorrelationId): Could not find package."
|
||||
assertError(ErrorFactories.packageNotFound("packageId123"))(
|
||||
assertError(
|
||||
LedgerApiErrors.RequestValidation.NotFound.Package
|
||||
.Reject("packageId123")
|
||||
)(
|
||||
code = Code.NOT_FOUND,
|
||||
message = msg,
|
||||
details = Seq[ErrorDetails.ErrorDetail](
|
||||
@ -256,7 +269,7 @@ class ErrorFactoriesSpec
|
||||
}
|
||||
|
||||
"return the a versioned service internal error" in {
|
||||
assertError(ErrorFactories.versionServiceInternalError("message123"))(
|
||||
assertError(LedgerApiErrors.InternalError.VersionService("message123"))(
|
||||
code = Code.INTERNAL,
|
||||
message = expectedInternalErrorMessage,
|
||||
details = expectedInternalErrorDetails,
|
||||
@ -270,7 +283,7 @@ class ErrorFactoriesSpec
|
||||
|
||||
"return the configurationEntryRejected" in {
|
||||
val msg = s"CONFIGURATION_ENTRY_REJECTED(9,$truncatedCorrelationId): message123"
|
||||
assertError(ErrorFactories.configurationEntryRejected("message123"))(
|
||||
assertError(LedgerApiErrors.AdminServices.ConfigurationEntryRejected.Reject("message123"))(
|
||||
code = Code.FAILED_PRECONDITION,
|
||||
message = msg,
|
||||
details = Seq[ErrorDetails.ErrorDetail](
|
||||
@ -291,7 +304,10 @@ class ErrorFactoriesSpec
|
||||
"return a transactionNotFound error" in {
|
||||
val msg =
|
||||
s"TRANSACTION_NOT_FOUND(11,$truncatedCorrelationId): Transaction not found, or not visible."
|
||||
assertError(ErrorFactories.transactionNotFound(Ref.TransactionId.assertFromString("tId")))(
|
||||
assertError(
|
||||
LedgerApiErrors.RequestValidation.NotFound.Transaction
|
||||
.Reject(Ref.TransactionId.assertFromString("tId"))
|
||||
)(
|
||||
code = Code.NOT_FOUND,
|
||||
message = msg,
|
||||
details = Seq[ErrorDetails.ErrorDetail](
|
||||
@ -313,7 +329,10 @@ class ErrorFactoriesSpec
|
||||
"return the DuplicateCommandException" in {
|
||||
val msg =
|
||||
s"DUPLICATE_COMMAND(10,$truncatedCorrelationId): A command with the given command id has already been successfully processed"
|
||||
assertError(ErrorFactories.duplicateCommandException(None))(
|
||||
assertError(
|
||||
LedgerApiErrors.ConsistencyErrors.DuplicateCommand
|
||||
.Reject(_existingCommandSubmissionId = None)
|
||||
)(
|
||||
code = Code.ALREADY_EXISTS,
|
||||
message = msg,
|
||||
details = Seq[ErrorDetails.ErrorDetail](
|
||||
@ -332,7 +351,7 @@ class ErrorFactoriesSpec
|
||||
}
|
||||
|
||||
"return a permissionDenied error" in {
|
||||
assertError(ErrorFactories.permissionDenied("some cause"))(
|
||||
assertError(LedgerApiErrors.AuthorizationChecks.PermissionDenied.Reject("some cause"))(
|
||||
code = Code.PERMISSION_DENIED,
|
||||
message = expectedInternalErrorMessage,
|
||||
details = expectedInternalErrorDetails,
|
||||
@ -347,7 +366,8 @@ class ErrorFactoriesSpec
|
||||
"return a isTimeoutUnknown_wasAborted error" in {
|
||||
val msg = s"REQUEST_TIME_OUT(3,$truncatedCorrelationId): message123"
|
||||
assertError(
|
||||
ErrorFactories.isTimeoutUnknown_wasAborted("message123", definiteAnswer = Some(false))
|
||||
LedgerApiErrors.RequestTimeOut
|
||||
.Reject("message123", _definiteAnswer = false)
|
||||
)(
|
||||
code = Code.DEADLINE_EXCEEDED,
|
||||
message = msg,
|
||||
@ -371,11 +391,13 @@ class ErrorFactoriesSpec
|
||||
val msg =
|
||||
s"NON_HEXADECIMAL_OFFSET(8,$truncatedCorrelationId): Offset in fieldName123 not specified in hexadecimal: offsetValue123: message123"
|
||||
assertError(
|
||||
ErrorFactories.nonHexOffset(
|
||||
fieldName = "fieldName123",
|
||||
offsetValue = "offsetValue123",
|
||||
message = "message123",
|
||||
)
|
||||
LedgerApiErrors.RequestValidation.NonHexOffset
|
||||
.Error(
|
||||
_fieldName = "fieldName123",
|
||||
_offsetValue = "offsetValue123",
|
||||
_message = "message123",
|
||||
)
|
||||
.asGrpcError
|
||||
)(
|
||||
code = Code.INVALID_ARGUMENT,
|
||||
message = msg,
|
||||
@ -394,7 +416,10 @@ class ErrorFactoriesSpec
|
||||
"return an offsetAfterLedgerEnd error" in {
|
||||
val expectedMessage = s"Absolute offset (AABBCC) is after ledger end (E)"
|
||||
val msg = s"OFFSET_AFTER_LEDGER_END(12,$truncatedCorrelationId): $expectedMessage"
|
||||
assertError(ErrorFactories.offsetAfterLedgerEnd("Absolute", "AABBCC", "E"))(
|
||||
assertError(
|
||||
LedgerApiErrors.RequestValidation.OffsetAfterLedgerEnd
|
||||
.Reject("Absolute", "AABBCC", "E")
|
||||
)(
|
||||
code = Code.OUT_OF_RANGE,
|
||||
message = msg,
|
||||
details = Seq[ErrorDetails.ErrorDetail](
|
||||
@ -414,7 +439,10 @@ class ErrorFactoriesSpec
|
||||
|
||||
"return a offsetOutOfRange error" in {
|
||||
val msg = s"OFFSET_OUT_OF_RANGE(9,$truncatedCorrelationId): message123"
|
||||
assertError(ErrorFactories.offsetOutOfRange("message123"))(
|
||||
assertError(
|
||||
LedgerApiErrors.RequestValidation.OffsetOutOfRange
|
||||
.Reject("message123")
|
||||
)(
|
||||
code = Code.FAILED_PRECONDITION,
|
||||
message = msg,
|
||||
details = Seq[ErrorDetails.ErrorDetail](
|
||||
@ -433,7 +461,10 @@ class ErrorFactoriesSpec
|
||||
}
|
||||
|
||||
"return an unauthenticatedMissingJwtToken error" in {
|
||||
assertError(ErrorFactories.unauthenticatedMissingJwtToken())(
|
||||
assertError(
|
||||
LedgerApiErrors.AuthorizationChecks.Unauthenticated
|
||||
.MissingJwtToken()
|
||||
)(
|
||||
code = Code.UNAUTHENTICATED,
|
||||
message = expectedInternalErrorMessage,
|
||||
details = expectedInternalErrorDetails,
|
||||
@ -449,7 +480,8 @@ class ErrorFactoriesSpec
|
||||
val someSecuritySafeMessage = "nothing security sensitive in here"
|
||||
val someThrowable = new RuntimeException("some internal authentication error")
|
||||
assertError(
|
||||
ErrorFactories.internalAuthenticationError(someSecuritySafeMessage, someThrowable)
|
||||
LedgerApiErrors.AuthorizationChecks.InternalAuthorizationError
|
||||
.Reject(someSecuritySafeMessage, someThrowable)
|
||||
)(
|
||||
code = Code.INTERNAL,
|
||||
message = expectedInternalErrorMessage,
|
||||
@ -465,7 +497,10 @@ class ErrorFactoriesSpec
|
||||
"return a missingLedgerConfig error" in {
|
||||
val msg =
|
||||
s"LEDGER_CONFIGURATION_NOT_FOUND(11,$truncatedCorrelationId): The ledger configuration could not be retrieved."
|
||||
assertError(ErrorFactories.missingLedgerConfig())(
|
||||
assertError(
|
||||
LedgerApiErrors.RequestValidation.NotFound.LedgerConfiguration
|
||||
.Reject()
|
||||
)(
|
||||
code = Code.NOT_FOUND,
|
||||
message = msg,
|
||||
details = Seq[ErrorDetails.ErrorDetail](
|
||||
@ -483,32 +518,18 @@ class ErrorFactoriesSpec
|
||||
)
|
||||
}
|
||||
|
||||
"return an aborted error" in {
|
||||
val testCases = Table(
|
||||
("definite answer", "expected details"),
|
||||
(None, Seq.empty),
|
||||
(Some(false), Seq(definiteAnswers(false))),
|
||||
)
|
||||
|
||||
forEvery(testCases) { (definiteAnswer, expectedDetails) =>
|
||||
val exception = ErrorFactories.aborted("my message", definiteAnswer)
|
||||
val status = StatusProto.fromThrowable(exception)
|
||||
status.getCode shouldBe Code.ABORTED.value()
|
||||
status.getMessage shouldBe "my message"
|
||||
status.getDetailsList.asScala shouldBe expectedDetails
|
||||
}
|
||||
}
|
||||
|
||||
"return an invalid deduplication period error" in {
|
||||
val errorDetailMessage = "message"
|
||||
val maxDeduplicationDuration = Duration.ofSeconds(5)
|
||||
val msg =
|
||||
s"INVALID_DEDUPLICATION_PERIOD(9,$truncatedCorrelationId): The submitted command had an invalid deduplication period: $errorDetailMessage"
|
||||
assertError(
|
||||
ErrorFactories.invalidDeduplicationPeriod(
|
||||
message = errorDetailMessage,
|
||||
maxDeduplicationDuration = Some(maxDeduplicationDuration),
|
||||
)
|
||||
LedgerApiErrors.RequestValidation.InvalidDeduplicationPeriodField
|
||||
.Reject(
|
||||
_reason = errorDetailMessage,
|
||||
_maxDeduplicationDuration = Some(maxDeduplicationDuration),
|
||||
)
|
||||
.asGrpcError
|
||||
)(
|
||||
code = Code.FAILED_PRECONDITION,
|
||||
message = msg,
|
||||
@ -548,7 +569,7 @@ class ErrorFactoriesSpec
|
||||
logEntry = ExpectedLogEntry(
|
||||
Level.INFO,
|
||||
msg,
|
||||
Some(expectedLocationLogMarkerRegex),
|
||||
Some(expectedLocationLogMarkerRegexErrorFactories),
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -557,7 +578,8 @@ class ErrorFactoriesSpec
|
||||
val msg =
|
||||
s"LEDGER_ID_MISMATCH(11,$truncatedCorrelationId): Ledger ID 'received' not found. Actual Ledger ID is 'expected'."
|
||||
assertError(
|
||||
ErrorFactories.ledgerIdMismatch(LedgerId("expected"), LedgerId("received"))
|
||||
LedgerApiErrors.RequestValidation.LedgerIdMismatch
|
||||
.Reject("expected", "received")
|
||||
)(
|
||||
code = Code.NOT_FOUND,
|
||||
message = msg,
|
||||
@ -579,10 +601,11 @@ class ErrorFactoriesSpec
|
||||
"return a participantPrunedDataAccessed error" in {
|
||||
val msg = s"PARTICIPANT_PRUNED_DATA_ACCESSED(9,$truncatedCorrelationId): my message"
|
||||
assertError(
|
||||
ErrorFactories.participantPrunedDataAccessed(
|
||||
"my message",
|
||||
Offset.fromHexString(Ref.HexString.assertFromString("00")),
|
||||
)
|
||||
LedgerApiErrors.RequestValidation.ParticipantPrunedDataAccessed
|
||||
.Reject(
|
||||
"my message",
|
||||
"00",
|
||||
)
|
||||
)(
|
||||
code = Code.FAILED_PRECONDITION,
|
||||
message = msg,
|
||||
@ -606,7 +629,7 @@ class ErrorFactoriesSpec
|
||||
}
|
||||
|
||||
"return a trackerFailure error" in {
|
||||
assertError(ErrorFactories.trackerFailure("message123"))(
|
||||
assertError(LedgerApiErrors.InternalError.Generic("message123"))(
|
||||
code = Code.INTERNAL,
|
||||
message = expectedInternalErrorMessage,
|
||||
details = expectedInternalErrorDetails,
|
||||
@ -623,7 +646,7 @@ class ErrorFactoriesSpec
|
||||
|
||||
val msg =
|
||||
s"SERVICE_NOT_RUNNING(1,$truncatedCorrelationId): $serviceName has been shut down."
|
||||
assertError(ErrorFactories.serviceNotRunning(serviceName))(
|
||||
assertError(LedgerApiErrors.ServiceNotRunning.Reject(serviceName))(
|
||||
code = Code.UNAVAILABLE,
|
||||
message = msg,
|
||||
details = Seq[ErrorDetails.ErrorDetail](
|
||||
@ -660,7 +683,7 @@ class ErrorFactoriesSpec
|
||||
logEntry = ExpectedLogEntry(
|
||||
Level.INFO,
|
||||
msg,
|
||||
expectedMarkerRegex("field_name=my field"),
|
||||
expectedMarkerRegexErrorFactories("field_name=my field"),
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -681,7 +704,7 @@ class ErrorFactoriesSpec
|
||||
logEntry = ExpectedLogEntry(
|
||||
Level.INFO,
|
||||
msg,
|
||||
Some(expectedLocationLogMarkerRegex),
|
||||
Some(expectedLocationLogMarkerRegexErrorFactories),
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -694,6 +717,15 @@ class ErrorFactoriesSpec
|
||||
}
|
||||
|
||||
private def expectedMarkerRegex(extraInner: String): Some[String] = {
|
||||
val locationRegex = "location=ErrorFactoriesSpec.scala:\\d+"
|
||||
val inner = List(extraInner -> Pattern.quote(extraInner), locationRegex -> locationRegex)
|
||||
.sortBy(_._1)
|
||||
.map(_._2)
|
||||
.mkString("\"\\{", ", ", "\\}\"")
|
||||
Some(s"\\{err-context: $inner\\}")
|
||||
}
|
||||
|
||||
private def expectedMarkerRegexErrorFactories(extraInner: String): Some[String] = {
|
||||
val locationRegex = "location=ErrorFactories.scala:\\d+"
|
||||
val inner = List(extraInner -> Pattern.quote(extraInner), locationRegex -> locationRegex)
|
||||
.sortBy(_._1)
|
||||
@ -715,6 +747,22 @@ class ErrorFactoriesSpec
|
||||
logEntry,
|
||||
)
|
||||
|
||||
private def assertError(
|
||||
error: LoggingTransactionErrorImpl
|
||||
)(
|
||||
code: Code,
|
||||
message: String,
|
||||
details: Seq[ErrorDetails.ErrorDetail],
|
||||
logEntry: ExpectedLogEntry,
|
||||
): Unit =
|
||||
assertError[this.type, this.type](
|
||||
actual = error.asGrpcError,
|
||||
code,
|
||||
message,
|
||||
details,
|
||||
logEntry,
|
||||
)
|
||||
|
||||
private def assertError(
|
||||
statusRuntimeException: StatusRuntimeException
|
||||
)(
|
||||
|
@ -10,6 +10,7 @@ import akka.NotUsed
|
||||
import akka.stream.Materializer
|
||||
import akka.stream.scaladsl.{Flow, Keep, Source}
|
||||
import com.daml.api.util.TimeProvider
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.error.{ContextualizedErrorLogger, DamlContextualizedErrorLogger}
|
||||
import com.daml.ledger.api.SubmissionIdGenerator
|
||||
import com.daml.ledger.api.domain.LedgerId
|
||||
@ -44,7 +45,6 @@ import com.daml.platform.apiserver.services.ApiCommandService._
|
||||
import com.daml.platform.apiserver.services.tracking.{QueueBackedTracker, Tracker, TrackerMap}
|
||||
import com.daml.platform.server.api.services.domain.CommandCompletionService
|
||||
import com.daml.platform.server.api.services.grpc.GrpcCommandService
|
||||
import com.daml.platform.server.api.validation.ErrorFactories
|
||||
import com.daml.util.Ctx
|
||||
import com.daml.util.akkastreams.MaxInFlight
|
||||
import com.google.protobuf.empty.Empty
|
||||
@ -162,7 +162,7 @@ private[apiserver] final class ApiCommandService private[services] (
|
||||
} else {
|
||||
Future
|
||||
.failed(
|
||||
ErrorFactories.serviceNotRunning("Command Service")
|
||||
LedgerApiErrors.ServiceNotRunning.Reject("Command Service").asGrpcError
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
package com.daml.platform.apiserver.services
|
||||
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.error.{ContextualizedErrorLogger, DamlContextualizedErrorLogger}
|
||||
import com.daml.ledger.api.domain.LedgerId
|
||||
import com.daml.ledger.api.v1.ledger_identity_service.LedgerIdentityServiceGrpc.{
|
||||
@ -15,7 +16,6 @@ import com.daml.ledger.api.v1.ledger_identity_service.{
|
||||
}
|
||||
import com.daml.logging.{ContextualizedLogger, LoggingContext}
|
||||
import com.daml.platform.api.grpc.GrpcApiService
|
||||
import com.daml.platform.server.api.validation.ErrorFactories
|
||||
import io.grpc.{BindableService, ServerServiceDefinition}
|
||||
import scalaz.syntax.tag._
|
||||
|
||||
@ -39,7 +39,7 @@ private[apiserver] final class ApiLedgerIdentityService private (
|
||||
): Future[GetLedgerIdentityResponse] = {
|
||||
logger.info(s"Received request for ledger identity: $request")
|
||||
if (closed)
|
||||
Future.failed(ErrorFactories.serviceNotRunning("Ledger Identity Service"))
|
||||
Future.failed(LedgerApiErrors.ServiceNotRunning.Reject("Ledger Identity Service").asGrpcError)
|
||||
else
|
||||
getLedgerId()
|
||||
.map(ledgerId => GetLedgerIdentityResponse(ledgerId.unwrap))
|
||||
|
@ -5,6 +5,7 @@ package com.daml.platform.apiserver.services
|
||||
|
||||
import com.daml.daml_lf_dev.DamlLf.{Archive, HashFunction}
|
||||
import com.daml.error.DamlContextualizedErrorLogger
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.api.domain.LedgerId
|
||||
import com.daml.ledger.api.v1.package_service.PackageServiceGrpc.PackageService
|
||||
import com.daml.ledger.api.v1.package_service.{HashFunction => APIHashFunction, _}
|
||||
@ -49,9 +50,11 @@ private[apiserver] final class ApiPackageService private (
|
||||
.flatMap {
|
||||
case None =>
|
||||
Future.failed[GetPackageResponse](
|
||||
ErrorFactories.packageNotFound(packageId = packageId)(
|
||||
createContextualizedErrorLogger
|
||||
)
|
||||
LedgerApiErrors.RequestValidation.NotFound.Package
|
||||
.Reject(_packageId = packageId)(
|
||||
createContextualizedErrorLogger
|
||||
)
|
||||
.asGrpcError
|
||||
)
|
||||
case Some(archive) => Future.successful(toGetPackageResponse(archive))
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import java.util.UUID
|
||||
|
||||
import com.daml.api.util.TimeProvider
|
||||
import com.daml.error.ErrorCode.LoggingApiException
|
||||
import com.daml.error.definitions.{ErrorCauseExport, RejectionGenerators}
|
||||
import com.daml.error.definitions.{ErrorCauseExport, LedgerApiErrors, RejectionGenerators}
|
||||
import com.daml.error.{ContextualizedErrorLogger, DamlContextualizedErrorLogger, ErrorCause}
|
||||
import com.daml.ledger.api.domain.{LedgerId, SubmissionId, Commands => ApiCommands}
|
||||
import com.daml.ledger.api.messages.command.submission.SubmitRequest
|
||||
@ -28,7 +28,6 @@ import com.daml.platform.apiserver.configuration.LedgerConfigurationSubscription
|
||||
import com.daml.platform.apiserver.execution.{CommandExecutionResult, CommandExecutor}
|
||||
import com.daml.platform.server.api.services.domain.CommandSubmissionService
|
||||
import com.daml.platform.server.api.services.grpc.GrpcCommandSubmissionService
|
||||
import com.daml.platform.server.api.validation.ErrorFactories
|
||||
import com.daml.platform.services.time.TimeProviderType
|
||||
import com.daml.scalautil.future.FutureConversion.CompletionStageConversionOps
|
||||
import com.daml.telemetry.TelemetryContext
|
||||
@ -122,7 +121,9 @@ private[apiserver] final class ApiSubmissionService private[services] (
|
||||
.transform(handleSubmissionResult)
|
||||
case None =>
|
||||
Future.failed(
|
||||
ErrorFactories.missingLedgerConfig()
|
||||
LedgerApiErrors.RequestValidation.NotFound.LedgerConfiguration
|
||||
.Reject()
|
||||
.asGrpcError
|
||||
)
|
||||
}
|
||||
evaluatedCommand.andThen(logger.logErrorsOnCall[Unit])
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
package com.daml.platform.apiserver.services
|
||||
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.error.{ContextualizedErrorLogger, DamlContextualizedErrorLogger}
|
||||
import com.daml.ledger.api.v1.experimental_features.{
|
||||
ExperimentalFeatures,
|
||||
@ -21,7 +22,6 @@ import com.daml.ledger.api.v1.version_service.{
|
||||
import com.daml.logging.{ContextualizedLogger, LoggingContext}
|
||||
import com.daml.platform.api.grpc.GrpcApiService
|
||||
import com.daml.platform.apiserver.LedgerFeatures
|
||||
import com.daml.platform.server.api.validation.ErrorFactories
|
||||
import com.daml.platform.usermanagement.UserManagementConfig
|
||||
import io.grpc.ServerServiceDefinition
|
||||
|
||||
@ -93,7 +93,9 @@ private[apiserver] final class ApiVersionService private (
|
||||
|
||||
private lazy val internalError: Future[Nothing] =
|
||||
Future.failed(
|
||||
ErrorFactories.versionServiceInternalError(message = "Cannot read Ledger API version")
|
||||
LedgerApiErrors.InternalError
|
||||
.VersionService(message = "Cannot read Ledger API version")
|
||||
.asGrpcError
|
||||
)
|
||||
|
||||
private def readVersion(versionFileName: String): Try[String] =
|
||||
|
@ -4,9 +4,11 @@
|
||||
package com.daml.platform.apiserver.services.admin
|
||||
|
||||
import java.time.{Duration => JDuration}
|
||||
|
||||
import akka.stream.Materializer
|
||||
import akka.stream.scaladsl.Source
|
||||
import com.daml.api.util.{DurationConversion, TimeProvider, TimestampConversion}
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.error.{ContextualizedErrorLogger, DamlContextualizedErrorLogger}
|
||||
import com.daml.ledger.api.domain
|
||||
import com.daml.ledger.api.domain.{ConfigurationEntry, LedgerOffset}
|
||||
@ -60,9 +62,11 @@ private[apiserver] final class ApiConfigManagementService private (
|
||||
Future.successful(configurationToResponse(configuration))
|
||||
case None =>
|
||||
Future.failed(
|
||||
missingLedgerConfig()(
|
||||
new DamlContextualizedErrorLogger(logger, loggingContext, None)
|
||||
)
|
||||
LedgerApiErrors.RequestValidation.NotFound.LedgerConfiguration
|
||||
.Reject()(
|
||||
new DamlContextualizedErrorLogger(logger, loggingContext, None)
|
||||
)
|
||||
.asGrpcError
|
||||
)
|
||||
}
|
||||
.andThen(logger.logErrorsOnCall[GetTimeModelResponse])
|
||||
@ -109,7 +113,11 @@ private[apiserver] final class ApiConfigManagementService private (
|
||||
logger.warn(
|
||||
"Could not get the current time model. The index does not yet have any ledger configuration."
|
||||
)
|
||||
Future.failed(missingLedgerConfig())
|
||||
Future.failed(
|
||||
LedgerApiErrors.RequestValidation.NotFound.LedgerConfiguration
|
||||
.Reject()
|
||||
.asGrpcError
|
||||
)
|
||||
}
|
||||
(ledgerEndBeforeRequest, currentConfig) = configuration
|
||||
|
||||
@ -256,9 +264,11 @@ private[apiserver] object ApiConfigManagementService {
|
||||
submissionId: Ref.SubmissionId
|
||||
): PartialFunction[ConfigurationEntry, StatusRuntimeException] = {
|
||||
case domain.ConfigurationEntry.Rejected(`submissionId`, reason, _) =>
|
||||
ErrorFactories.configurationEntryRejected(reason)(
|
||||
new DamlContextualizedErrorLogger(logger, loggingContext, Some(submissionId))
|
||||
)
|
||||
LedgerApiErrors.AdminServices.ConfigurationEntryRejected
|
||||
.Reject(reason)(
|
||||
new DamlContextualizedErrorLogger(logger, loggingContext, Some(submissionId))
|
||||
)
|
||||
.asGrpcError
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,11 +5,12 @@ package com.daml.platform.apiserver.services.admin
|
||||
|
||||
import java.time.Duration
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
import akka.stream.Materializer
|
||||
import akka.stream.scaladsl.Source
|
||||
import com.daml.api.util.TimestampConversion
|
||||
import com.daml.daml_lf_dev.DamlLf.Archive
|
||||
import com.daml.error.definitions.LoggingPackageServiceError
|
||||
import com.daml.error.definitions.{LedgerApiErrors, LoggingPackageServiceError}
|
||||
import com.daml.error.definitions.PackageServiceError.Validation
|
||||
import com.daml.error.{ContextualizedErrorLogger, DamlContextualizedErrorLogger}
|
||||
import com.daml.ledger.api.domain.{LedgerOffset, PackageEntry}
|
||||
@ -29,7 +30,6 @@ import com.daml.logging.{ContextualizedLogger, LoggingContext}
|
||||
import com.daml.platform.api.grpc.GrpcApiService
|
||||
import com.daml.platform.apiserver.services.admin.ApiPackageManagementService._
|
||||
import com.daml.platform.apiserver.services.logging
|
||||
import com.daml.platform.server.api.validation.ErrorFactories
|
||||
import com.daml.telemetry.{DefaultTelemetry, TelemetryContext}
|
||||
import io.grpc.{ServerServiceDefinition, StatusRuntimeException}
|
||||
import scalaz.std.either._
|
||||
@ -202,9 +202,11 @@ private[apiserver] object ApiPackageManagementService {
|
||||
submissionId: Ref.SubmissionId
|
||||
): PartialFunction[PackageEntry, StatusRuntimeException] = {
|
||||
case PackageEntry.PackageUploadRejected(`submissionId`, _, reason) =>
|
||||
ErrorFactories.packageUploadRejected(reason)(
|
||||
new DamlContextualizedErrorLogger(logger, loggingContext, Some(submissionId))
|
||||
)
|
||||
LedgerApiErrors.AdminServices.PackageUploadRejected
|
||||
.Reject(reason)(
|
||||
new DamlContextualizedErrorLogger(logger, loggingContext, Some(submissionId))
|
||||
)
|
||||
.asGrpcError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,9 @@
|
||||
package com.daml.platform.apiserver.services.admin
|
||||
|
||||
import com.daml.error.{ContextualizedErrorLogger, DamlContextualizedErrorLogger}
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.api.v1.admin.participant_pruning_service.{
|
||||
ParticipantPruningServiceGrpc,
|
||||
PruneRequest,
|
||||
@ -148,12 +149,14 @@ final class ApiParticipantPruningService private (
|
||||
.toEither
|
||||
.left
|
||||
.map(t =>
|
||||
nonHexOffset(
|
||||
fieldName = "prune_up_to",
|
||||
offsetValue = pruneUpToString,
|
||||
message =
|
||||
s"prune_up_to needs to be a hexadecimal string and not $pruneUpToString: ${t.getMessage}",
|
||||
)
|
||||
LedgerApiErrors.RequestValidation.NonHexOffset
|
||||
.Error(
|
||||
_fieldName = "prune_up_to",
|
||||
_offsetValue = pruneUpToString,
|
||||
_message =
|
||||
s"prune_up_to needs to be a hexadecimal string and not $pruneUpToString: ${t.getMessage}",
|
||||
)
|
||||
.asGrpcError
|
||||
)
|
||||
|
||||
private def checkOffsetIsBeforeLedgerEnd(
|
||||
@ -171,9 +174,11 @@ final class ApiParticipantPruningService private (
|
||||
Future.failed(
|
||||
// TODO error codes: Relax the constraint (pruneUpToString <= ledgerEnd.value)
|
||||
// and use offsetAfterLedgerEnd
|
||||
offsetOutOfRange(
|
||||
s"prune_up_to needs to be before ledger end ${ledgerEnd.value}"
|
||||
)
|
||||
LedgerApiErrors.RequestValidation.OffsetOutOfRange
|
||||
.Reject(
|
||||
s"prune_up_to needs to be before ledger end ${ledgerEnd.value}"
|
||||
)
|
||||
.asGrpcError
|
||||
)
|
||||
} yield pruneUpToProto
|
||||
|
||||
|
@ -5,9 +5,11 @@ package com.daml.platform.apiserver.services.admin
|
||||
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import akka.stream.Materializer
|
||||
import akka.stream.scaladsl.{Sink, Source}
|
||||
import com.daml.error.DamlContextualizedErrorLogger
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.api.domain.LedgerOffset
|
||||
import com.daml.ledger.participant.state.{v2 => state}
|
||||
import com.daml.lf.data.Ref
|
||||
@ -57,22 +59,26 @@ class SynchronousResponse[Input, Entry, AcceptedEntry](
|
||||
.recoverWith {
|
||||
case _: TimeoutException =>
|
||||
Future.failed(
|
||||
ErrorFactories
|
||||
.isTimeoutUnknown_wasAborted("Request timed out", definiteAnswer = Some(false))(
|
||||
LedgerApiErrors.RequestTimeOut
|
||||
.Reject("Request timed out", _definiteAnswer = false)(
|
||||
new DamlContextualizedErrorLogger(logger, loggingContext, Some(submissionId))
|
||||
)
|
||||
.asGrpcError
|
||||
)
|
||||
case _: NoSuchElementException =>
|
||||
val errorLogger = new DamlContextualizedErrorLogger(
|
||||
logger,
|
||||
loggingContext,
|
||||
Some(submissionId),
|
||||
)
|
||||
Future.failed(
|
||||
// TODO error codes: simplify
|
||||
ErrorFactories.grpcError(
|
||||
ErrorFactories.SubmissionQueueErrors
|
||||
.queueClosed("Party submission")(
|
||||
new DamlContextualizedErrorLogger(
|
||||
logger,
|
||||
loggingContext,
|
||||
Some(submissionId),
|
||||
)
|
||||
LedgerApiErrors.ServiceNotRunning
|
||||
.Reject("Party submission")(
|
||||
errorLogger
|
||||
)
|
||||
.asGrpcStatusFromContext(errorLogger)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -8,13 +8,13 @@ import akka.stream.{BoundedSourceQueue, Materializer, QueueOfferResult}
|
||||
import akka.{Done, NotUsed}
|
||||
import com.codahale.metrics.{Counter, Timer}
|
||||
import com.daml.error.DamlContextualizedErrorLogger
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.client.services.commands.CommandSubmission
|
||||
import com.daml.ledger.client.services.commands.CommandTrackerFlow.Materialized
|
||||
import com.daml.ledger.client.services.commands.tracker.CompletionResponse._
|
||||
import com.daml.logging.{ContextualizedLogger, LoggingContext}
|
||||
import com.daml.metrics.InstrumentedSource
|
||||
import com.daml.platform.apiserver.services.tracking.QueueBackedTracker._
|
||||
import com.daml.platform.server.api.validation.ErrorFactories
|
||||
import com.daml.util.Ctx
|
||||
import com.google.rpc.Status
|
||||
|
||||
@ -52,20 +52,33 @@ private[services] final class QueueBackedTracker(
|
||||
)
|
||||
case Success(QueueOfferResult.Failure(throwable)) =>
|
||||
toQueueSubmitFailure(
|
||||
ErrorFactories.SubmissionQueueErrors
|
||||
.failedToEnqueueCommandSubmission("Failed to enqueue")(throwable)
|
||||
LedgerApiErrors.InternalError
|
||||
.Generic(
|
||||
s"Failed to enqueue: ${throwable.getClass.getSimpleName}: ${throwable.getMessage}",
|
||||
Some(throwable),
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
case Success(QueueOfferResult.Dropped) =>
|
||||
toQueueSubmitFailure(ErrorFactories.bufferFull("The submission ingress buffer is full"))
|
||||
toQueueSubmitFailure(
|
||||
LedgerApiErrors.ParticipantBackpressure
|
||||
.Rejection("The submission ingress buffer is full")
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
case Success(QueueOfferResult.QueueClosed) =>
|
||||
toQueueSubmitFailure(
|
||||
ErrorFactories.SubmissionQueueErrors.queueClosed("Command service queue")
|
||||
LedgerApiErrors.ServiceNotRunning
|
||||
.Reject("Command service queue")
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
case Failure(throwable) =>
|
||||
toQueueSubmitFailure(
|
||||
ErrorFactories.SubmissionQueueErrors.failedToEnqueueCommandSubmission(
|
||||
"Unexpected `BoundedSourceQueue.offer` exception"
|
||||
)(throwable)
|
||||
LedgerApiErrors.InternalError
|
||||
.Generic(
|
||||
s"Unexpected `BoundedSourceQueue.offer` exception: ${throwable.getClass.getSimpleName}: ${throwable.getMessage}",
|
||||
Some(throwable),
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -140,7 +153,9 @@ private[services] object QueueBackedTracker {
|
||||
val errorLogger = new DamlContextualizedErrorLogger(logger, loggingContext, None)
|
||||
promises.foreach(p =>
|
||||
p.failure(
|
||||
ErrorFactories.trackerFailure(msg = promiseCancellationDescription)(errorLogger)
|
||||
LedgerApiErrors.InternalError
|
||||
.Generic(promiseCancellationDescription)(errorLogger)
|
||||
.asGrpcError
|
||||
)
|
||||
)
|
||||
})(ExecutionContext.parasitic)
|
||||
|
@ -6,6 +6,7 @@ package com.daml.platform.apiserver.services.transaction
|
||||
import akka.NotUsed
|
||||
import akka.stream.Materializer
|
||||
import akka.stream.scaladsl.Source
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.error.{ContextualizedErrorLogger, DamlContextualizedErrorLogger}
|
||||
import com.daml.grpc.adapter.ExecutionSequencerFactory
|
||||
import com.daml.ledger.api.domain.{
|
||||
@ -65,8 +66,7 @@ private[apiserver] final class ApiTransactionService private (
|
||||
|
||||
private val logger: ContextualizedLogger = ContextualizedLogger.get(this.getClass)
|
||||
|
||||
import ErrorFactories.transactionNotFound
|
||||
import ErrorFactories.invalidArgumentWasNotFound
|
||||
import ErrorFactories.invalidArgument
|
||||
|
||||
override def getLedgerEnd(ledgerId: String): Future[LedgerOffset.Absolute] =
|
||||
transactionsService.currentLedgerEnd().andThen(logger.logErrorsOnCall[LedgerOffset.Absolute])
|
||||
@ -138,7 +138,7 @@ private[apiserver] final class ApiTransactionService private (
|
||||
}
|
||||
.getOrElse {
|
||||
Future.failed {
|
||||
invalidArgumentWasNotFound(s"invalid eventId: ${request.eventId}")
|
||||
invalidArgument(s"invalid eventId: ${request.eventId}")
|
||||
}
|
||||
}
|
||||
.andThen(logger.logErrorsOnCall[GetTransactionResponse])
|
||||
@ -181,7 +181,7 @@ private[apiserver] final class ApiTransactionService private (
|
||||
}
|
||||
.getOrElse {
|
||||
val msg = s"eventId: ${request.eventId}"
|
||||
Future.failed(invalidArgumentWasNotFound(msg))
|
||||
Future.failed(invalidArgument(msg))
|
||||
}
|
||||
.andThen(logger.logErrorsOnCall[GetFlatTransactionResponse])
|
||||
}
|
||||
@ -210,7 +210,12 @@ private[apiserver] final class ApiTransactionService private (
|
||||
transactionsService
|
||||
.getTransactionTreeById(transactionId, requestingParties)
|
||||
.flatMap {
|
||||
case None => Future.failed(transactionNotFound(transactionId.unwrap))
|
||||
case None =>
|
||||
Future.failed(
|
||||
LedgerApiErrors.RequestValidation.NotFound.Transaction
|
||||
.Reject(transactionId.unwrap)
|
||||
.asGrpcError
|
||||
)
|
||||
case Some(transaction) => Future.successful(transaction)
|
||||
}
|
||||
|
||||
@ -221,7 +226,12 @@ private[apiserver] final class ApiTransactionService private (
|
||||
transactionsService
|
||||
.getTransactionById(transactionId, requestingParties)
|
||||
.flatMap {
|
||||
case None => Future.failed(transactionNotFound(transactionId.unwrap))
|
||||
case None =>
|
||||
Future.failed(
|
||||
LedgerApiErrors.RequestValidation.NotFound.Transaction
|
||||
.Reject(transactionId.unwrap)
|
||||
.asGrpcError
|
||||
)
|
||||
case Some(transaction) => Future.successful(transaction)
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import akka.NotUsed
|
||||
import akka.stream.scaladsl.Source
|
||||
import com.daml.daml_lf_dev.DamlLf
|
||||
import com.daml.error.DamlContextualizedErrorLogger
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.api.{TraceIdentifiers, domain}
|
||||
import com.daml.ledger.api.domain.ConfigurationEntry.Accepted
|
||||
import com.daml.ledger.api.domain.{
|
||||
@ -46,7 +47,6 @@ import com.daml.platform.ApiOffset.ApiOffsetConverter
|
||||
import com.daml.platform.{ApiOffset, PruneBuffers}
|
||||
import com.daml.platform.akkastreams.dispatcher.Dispatcher
|
||||
import com.daml.platform.akkastreams.dispatcher.SubSource.RangeSource
|
||||
import com.daml.platform.server.api.validation.ErrorFactories
|
||||
import com.daml.platform.store.appendonlydao.{LedgerDaoTransactionsReader, LedgerReadDao}
|
||||
import com.daml.platform.store.entries.PartyLedgerEntry
|
||||
import com.daml.telemetry.{Event, SpanAttribute, Spans}
|
||||
@ -351,9 +351,11 @@ private[index] class IndexServiceImpl(
|
||||
Source.empty
|
||||
case Some(end) if begin > end =>
|
||||
Source.failed(
|
||||
ErrorFactories.offsetOutOfRange(
|
||||
s"End offset ${end.toApiString} is before Begin offset ${begin.toApiString}."
|
||||
)(new DamlContextualizedErrorLogger(logger, loggingContext, None))
|
||||
LedgerApiErrors.RequestValidation.OffsetOutOfRange
|
||||
.Reject(
|
||||
s"End offset ${end.toApiString} is before Begin offset ${begin.toApiString}."
|
||||
)(new DamlContextualizedErrorLogger(logger, loggingContext, None))
|
||||
.asGrpcError
|
||||
)
|
||||
case endOpt: Option[Offset] =>
|
||||
f(Some(begin), endOpt)
|
||||
|
@ -7,6 +7,7 @@ import akka.stream.Materializer
|
||||
import akka.stream.scaladsl.Source
|
||||
import com.daml.daml_lf_dev.DamlLf.Archive
|
||||
import com.daml.error.DamlContextualizedErrorLogger
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.api.domain.{LedgerId, ParticipantId, PartyDetails}
|
||||
import com.daml.ledger.api.health.HealthStatus
|
||||
import com.daml.ledger.configuration.Configuration
|
||||
@ -24,7 +25,6 @@ import com.daml.logging.LoggingContext.withEnrichedLoggingContext
|
||||
import com.daml.logging.entries.LoggingEntry
|
||||
import com.daml.logging.{ContextualizedLogger, LoggingContext}
|
||||
import com.daml.metrics.Metrics
|
||||
import com.daml.platform.server.api.validation.ErrorFactories
|
||||
import com.daml.platform.store._
|
||||
import com.daml.platform.store.appendonlydao.events._
|
||||
import com.daml.platform.store.backend.ParameterStorageBackend.LedgerEnd
|
||||
@ -410,9 +410,11 @@ private class JdbcLedgerDao(
|
||||
conn,
|
||||
)
|
||||
) {
|
||||
throw ErrorFactories.offsetOutOfRange(
|
||||
"Pruning offset for all divulged contracts needs to be after the migration offset"
|
||||
)(new DamlContextualizedErrorLogger(logger, loggingContext, None))
|
||||
throw LedgerApiErrors.RequestValidation.OffsetOutOfRange
|
||||
.Reject(
|
||||
"Pruning offset for all divulged contracts needs to be after the migration offset"
|
||||
)(new DamlContextualizedErrorLogger(logger, loggingContext, None))
|
||||
.asGrpcError
|
||||
}
|
||||
|
||||
readStorageBackend.eventStorageBackend.pruneEvents(
|
||||
|
@ -4,11 +4,11 @@
|
||||
package com.daml.platform.store.appendonlydao.events
|
||||
|
||||
import com.daml.error.DamlContextualizedErrorLogger
|
||||
|
||||
import java.sql.Connection
|
||||
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.offset.Offset
|
||||
import com.daml.logging.{ContextualizedLogger, LoggingContext}
|
||||
import com.daml.platform.server.api.validation.ErrorFactories
|
||||
import com.daml.platform.store.backend.ParameterStorageBackend
|
||||
|
||||
trait QueryNonPruned {
|
||||
@ -58,12 +58,14 @@ case class QueryNonPrunedImpl(
|
||||
result
|
||||
|
||||
case Some(pruningOffsetUpToInclusive) =>
|
||||
throw ErrorFactories.participantPrunedDataAccessed(
|
||||
message = error(pruningOffsetUpToInclusive),
|
||||
pruningOffsetUpToInclusive,
|
||||
)(
|
||||
new DamlContextualizedErrorLogger(logger, loggingContext, None)
|
||||
)
|
||||
throw LedgerApiErrors.RequestValidation.ParticipantPrunedDataAccessed
|
||||
.Reject(
|
||||
cause = error(pruningOffsetUpToInclusive),
|
||||
_earliestOffset = pruningOffsetUpToInclusive.toHexString,
|
||||
)(
|
||||
new DamlContextualizedErrorLogger(logger, loggingContext, None)
|
||||
)
|
||||
.asGrpcError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,12 @@ import java.time.{Duration, Instant}
|
||||
|
||||
import akka.stream.Materializer
|
||||
import com.daml.error.ContextualizedErrorLogger
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.api.DeduplicationPeriod
|
||||
import com.daml.ledger.configuration.LedgerTimeModel
|
||||
import com.daml.lf.data.{Ref, Time}
|
||||
import com.daml.logging.{ContextualizedLogger, LoggingContext}
|
||||
import com.daml.platform.server.api.validation.{DeduplicationPeriodValidator, ErrorFactories}
|
||||
import com.daml.platform.server.api.validation.DeduplicationPeriodValidator
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
@ -57,10 +58,12 @@ class DeduplicationPeriodSupport(
|
||||
s"Failed to convert deduplication offset $offset to duration: $reason"
|
||||
)
|
||||
Left(
|
||||
ErrorFactories.invalidDeduplicationPeriod(
|
||||
s"Cannot convert deduplication offset to duration because there is no completion at given offset $offset.",
|
||||
None,
|
||||
)
|
||||
LedgerApiErrors.RequestValidation.InvalidDeduplicationPeriodField
|
||||
.Reject(
|
||||
s"Cannot convert deduplication offset to duration because there is no completion at given offset $offset.",
|
||||
None,
|
||||
)
|
||||
.asGrpcError
|
||||
)
|
||||
},
|
||||
duration => {
|
||||
|
@ -5,8 +5,8 @@ package com.daml.ledger.participant.state.kvutils.deduplication
|
||||
|
||||
import java.time.{Duration, Instant}
|
||||
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.error.ErrorsAssertions
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.TestLoggers
|
||||
import com.daml.ledger.api.DeduplicationPeriod
|
||||
import com.daml.ledger.api.testing.utils.AkkaBeforeAndAfterAll
|
||||
|
@ -49,6 +49,7 @@ da_scala_library(
|
||||
"//libs-scala/build-info",
|
||||
"//libs-scala/concurrent",
|
||||
"//libs-scala/contextualized-logging",
|
||||
"//libs-scala/grpc-utils",
|
||||
"//libs-scala/logging-entries",
|
||||
"//libs-scala/ports",
|
||||
"//libs-scala/resources",
|
||||
|
@ -11,12 +11,12 @@ import error.definitions.LedgerApiErrors
|
||||
import ledger.configuration.LedgerTimeModel
|
||||
import lf.data.Time.Timestamp
|
||||
import lf.transaction.GlobalKey
|
||||
import platform.server.api.validation.ErrorFactories
|
||||
import platform.store.appendonlydao.events.ContractId
|
||||
import com.google.rpc.status.Status
|
||||
|
||||
import java.time.Duration
|
||||
|
||||
import com.daml.grpc.GrpcStatus
|
||||
|
||||
private[sandbox] sealed trait Rejection extends Product with Serializable {
|
||||
def toStatus: Status
|
||||
def completionInfo: CompletionInfo
|
||||
@ -36,9 +36,10 @@ private[sandbox] object Rejection {
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
) extends Rejection {
|
||||
override def toStatus: Status =
|
||||
ErrorFactories.CommandRejections.duplicateContractKey(
|
||||
reason = "DuplicateKey: contract key is not unique",
|
||||
key = key,
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.ConsistencyErrors.DuplicateContractKey
|
||||
.RejectWithContractKeyArg(cause = "DuplicateKey: contract key is not unique", _key = key)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
}
|
||||
|
||||
@ -49,7 +50,13 @@ private[sandbox] object Rejection {
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
) extends Rejection {
|
||||
override def toStatus: Status =
|
||||
ErrorFactories.CommandRejections.inconsistentContractKeys(expectation, result)
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.ConsistencyErrors.InconsistentContractKey
|
||||
.Reject(
|
||||
s"Contract key lookup with different results: expected [$expectation], actual [$result]"
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
}
|
||||
|
||||
final case class LedgerBridgeInternalError(_err: Throwable, completionInfo: CompletionInfo)(
|
||||
@ -102,8 +109,12 @@ private[sandbox] object Rejection {
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
) extends Rejection {
|
||||
override def toStatus: Status =
|
||||
ErrorFactories.CommandRejections.invalidLedgerTime(
|
||||
s"Ledger effective time for one of the contracts ($contractLedgerEffectiveTime) is greater than the ledger effective time of the transaction ($transactionLedgerEffectiveTime)"
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.ConsistencyErrors.InvalidLedgerTime
|
||||
.RejectSimple(
|
||||
s"Ledger effective time for one of the contracts ($contractLedgerEffectiveTime) is greater than the ledger effective time of the transaction ($transactionLedgerEffectiveTime)"
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
}
|
||||
|
||||
@ -112,8 +123,14 @@ private[sandbox] object Rejection {
|
||||
)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
) extends Rejection {
|
||||
override def toStatus: Status =
|
||||
ErrorFactories.CommandRejections.contractsNotFound(ids.map(_.coid))
|
||||
override def toStatus: Status = {
|
||||
val missingContractIds = ids.map(_.coid)
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.ConsistencyErrors.ContractNotFound
|
||||
.MultipleContractsNotFound(missingContractIds)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
final case class UnallocatedParties(unallocatedParties: Set[String])(
|
||||
@ -122,7 +139,11 @@ private[sandbox] object Rejection {
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
) extends Rejection {
|
||||
override def toStatus: Status =
|
||||
ErrorFactories.CommandRejections.partiesNotKnownToLedger(unallocatedParties)
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.WriteServiceRejections.PartyNotKnownOnLedger
|
||||
.Reject(unallocatedParties)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
}
|
||||
|
||||
final case class DuplicateCommand(
|
||||
@ -158,8 +179,12 @@ private[sandbox] object Rejection {
|
||||
)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
) extends Rejection {
|
||||
override def toStatus: Status = ErrorFactories.missingLedgerConfig(
|
||||
"Cannot validate ledger time"
|
||||
override def toStatus: Status = GrpcStatus.toProto(
|
||||
LedgerApiErrors.RequestValidation.NotFound.LedgerConfiguration
|
||||
.RejectWithMessage(
|
||||
"Cannot validate ledger time"
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
}
|
||||
|
||||
@ -169,10 +194,20 @@ private[sandbox] object Rejection {
|
||||
)(implicit
|
||||
contextualizedErrorLogger: ContextualizedErrorLogger
|
||||
) extends Rejection {
|
||||
override def toStatus: Status = ErrorFactories.CommandRejections.invalidLedgerTime(
|
||||
outOfRange.ledgerTime.toInstant,
|
||||
outOfRange.lowerBound.toInstant,
|
||||
outOfRange.upperBound.toInstant,
|
||||
)
|
||||
override def toStatus: Status = {
|
||||
val ledgerTime = outOfRange.ledgerTime.toInstant
|
||||
val ledgerTimeLowerBound = outOfRange.lowerBound.toInstant
|
||||
val ledgerTimeUpperBound = outOfRange.upperBound.toInstant
|
||||
GrpcStatus.toProto(
|
||||
LedgerApiErrors.ConsistencyErrors.InvalidLedgerTime
|
||||
.RejectEnriched(
|
||||
s"Ledger time $ledgerTime outside of range [$ledgerTimeLowerBound, $ledgerTimeUpperBound]",
|
||||
ledgerTime,
|
||||
ledgerTimeLowerBound,
|
||||
ledgerTimeUpperBound,
|
||||
)
|
||||
.asGrpcStatusFromContext
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user