diff --git a/ledger/error/src/main/scala/com/daml/error/ErrorResource.scala b/ledger/error/src/main/scala/com/daml/error/ErrorResource.scala index aa4dcc83444b..7953e482e639 100644 --- a/ledger/error/src/main/scala/com/daml/error/ErrorResource.scala +++ b/ledger/error/src/main/scala/com/daml/error/ErrorResource.scala @@ -26,6 +26,9 @@ object ErrorResource { object ContractKey extends ErrorResource { def asString: String = "CONTRACT_KEY" } + object TransactionId extends ErrorResource { + def asString: String = "TRANSACTION_ID" + } object DalfPackage extends ErrorResource { def asString: String = "PACKAGE" } diff --git a/ledger/error/src/main/scala/com/daml/error/definitions/LedgerApiErrors.scala b/ledger/error/src/main/scala/com/daml/error/definitions/LedgerApiErrors.scala index 4d389a0b2f39..1740d6b357d1 100644 --- a/ledger/error/src/main/scala/com/daml/error/definitions/LedgerApiErrors.scala +++ b/ledger/error/src/main/scala/com/daml/error/definitions/LedgerApiErrors.scala @@ -398,6 +398,23 @@ object LedgerApiErrors extends LedgerApiErrorGroup { ) } + @Explanation( + """TODO: Explanations needs yet to be filled out""" + ) + @Resolution("TODO: Resolution needs yet to be filled out") + object TransactionNotFound + extends ErrorCode( + id = "TRANSACTION_NOT_FOUND", + ErrorCategory.InvalidGivenCurrentSystemStateResourceMissing, + ) { + + case class Reject(transactionId: String)(implicit loggingContext: ErrorCodeLoggingContext) + extends LoggingTransactionErrorImpl(cause = "Transaction not found, or not visible.") { + override def resources: Seq[(ErrorResource, String)] = Seq( + (ErrorResource.ContractKey, transactionId) + ) + } + } } @Explanation("""This error occurs if the Daml transaction fails due to an authorization error. diff --git a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/transaction/ApiTransactionService.scala b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/transaction/ApiTransactionService.scala index 6d38168360d8..489d74f9f3e7 100644 --- a/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/transaction/ApiTransactionService.scala +++ b/ledger/participant-integration-api/src/main/scala/platform/apiserver/services/transaction/ApiTransactionService.scala @@ -32,7 +32,6 @@ import com.daml.logging.entries.LoggingEntries import com.daml.logging.{ContextualizedLogger, LoggingContext} import com.daml.metrics.Metrics import com.daml.platform.apiserver.ErrorCodesVersionSwitcher -import com.daml.platform.apiserver.services.transaction.ApiTransactionService._ import com.daml.platform.apiserver.services.{StreamMetrics, logging} import com.daml.platform.server.api.services.domain.TransactionService import com.daml.platform.server.api.services.grpc.GrpcTransactionService @@ -59,14 +58,6 @@ private[apiserver] object ApiTransactionService { ledgerId, PartyNameChecker.AllowAllParties, ) - - @throws[StatusRuntimeException] - private def getOrElseThrowNotFound[A](a: Option[A]): A = - a.getOrElse( - throw Status.NOT_FOUND - .withDescription("Transaction not found, or not visible.") - .asRuntimeException() - ) } private[apiserver] final class ApiTransactionService private ( @@ -188,8 +179,13 @@ private[apiserver] final class ApiTransactionService private ( .fromString(request.eventId.unwrap) .fold( err => - Future.failed[GetFlatTransactionResponse]( - Status.NOT_FOUND.withDescription(s"invalid eventId: $err").asRuntimeException() + errorsVersionsSwitcher.chooseAsFailedFuture[GetFlatTransactionResponse]( + v1 = Status.NOT_FOUND.withDescription(s"invalid eventId: $err").asRuntimeException(), + v2 = LedgerApiErrors.CommandValidation.InvalidArgument + .Reject(s"invalid eventId: $err")( + new DamlErrorCodeLoggingContext(logger, loggingContext, None) + ) + .asGrpcError, ), eventId => lookUpFlatByTransactionId( @@ -221,15 +217,32 @@ private[apiserver] final class ApiTransactionService private ( ): Future[GetTransactionResponse] = transactionsService .getTransactionTreeById(transactionId, requestingParties) - .map(getOrElseThrowNotFound) + .map(getOrElseThrowNotFound(transactionId)) private def lookUpFlatByTransactionId( transactionId: TransactionId, requestingParties: Set[Party], - ): Future[GetFlatTransactionResponse] = + ): Future[GetFlatTransactionResponse] = { transactionsService .getTransactionById(transactionId, requestingParties) - .map(getOrElseThrowNotFound) + .map(getOrElseThrowNotFound(transactionId)) + } + + @throws[StatusRuntimeException] + private def getOrElseThrowNotFound[A](transactionId: TransactionId)(a: Option[A]): A = + a.getOrElse { + val exception = errorsVersionsSwitcher.choose( + v1 = Status.NOT_FOUND + .withDescription("Transaction not found, or not visible.") + .asRuntimeException(), + v2 = LedgerApiErrors.InterpreterErrors.LookupErrors.TransactionNotFound + .Reject( + transactionId = transactionId.unwrap + )(new DamlErrorCodeLoggingContext(logger, loggingContext, None)) + .asGrpcError, + ) + throw exception + } private def transactionsLoggable(transactions: GetTransactionsResponse): String = s"Responding with transactions: ${transactions.transactions.toList