Remove most of ErrorFactories [DPP-606] (#13146)

changelog_begin
changelog_end
This commit is contained in:
pbatko-da 2022-03-07 16:15:21 +01:00 committed by GitHub
parent 0a52e56ca1
commit c7c211e4df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 408 additions and 588 deletions

View File

@ -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,
)
}

View File

@ -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],

View File

@ -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)
})

View File

@ -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 =

View File

@ -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(

View File

@ -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
}
}

View File

@ -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",

View File

@ -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))),

View File

@ -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(())
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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))
}
}
}

View File

@ -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

View File

@ -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
)(

View File

@ -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
)
}

View File

@ -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))

View File

@ -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))
}

View File

@ -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])

View File

@ -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] =

View File

@ -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
}
}

View File

@ -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
}
}
}

View File

@ -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

View File

@ -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)
)
)
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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)

View File

@ -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(

View File

@ -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
}
}
}

View File

@ -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 => {

View File

@ -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

View File

@ -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",

View File

@ -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
)
}
}
}