diff --git a/ledger-service/http-json-testing/src/main/scala/com/daml/http/HttpServiceTestFixture.scala b/ledger-service/http-json-testing/src/main/scala/com/daml/http/HttpServiceTestFixture.scala index 4cc6ee1681b9..e88ccf106f9d 100644 --- a/ledger-service/http-json-testing/src/main/scala/com/daml/http/HttpServiceTestFixture.scala +++ b/ledger-service/http-json-testing/src/main/scala/com/daml/http/HttpServiceTestFixture.scala @@ -15,7 +15,7 @@ import com.daml.api.util.TimestampConversion import com.daml.bazeltools.BazelRunfiles.rlocation import com.daml.grpc.adapter.ExecutionSequencerFactory import com.daml.http.dbbackend.ContractDao -import com.daml.http.json.{DomainJsonDecoder, DomainJsonEncoder, SprayJson} +import com.daml.http.json.{DomainJsonDecoder, DomainJsonEncoder} import com.daml.http.util.ClientUtil.boxedRecord import com.daml.http.util.Logging.{InstanceUUID, instanceUUIDLogCtx} import com.daml.http.util.TestUtil.getResponseDataBytes @@ -346,7 +346,7 @@ object HttpServiceTestFixture extends LazyLogging with Assertions with Inside { postJsonStringRequest(uri, json.prettyPrint, headers) def postCreateCommand( - cmd: domain.CreateCommand[v.Record], + cmd: domain.CreateCommand[v.Record, domain.TemplateId.OptionalPkg], encoder: DomainJsonEncoder, uri: Uri, headers: List[HttpHeader], @@ -355,9 +355,8 @@ object HttpServiceTestFixture extends LazyLogging with Assertions with Inside { ec: ExecutionContext, mat: Materializer, ): Future[(StatusCode, JsValue)] = { - import encoder.implicits._ for { - json <- FutureUtil.toFuture(SprayJson.encode1(cmd)): Future[JsValue] + json <- FutureUtil.toFuture(encoder.encodeCreateCommand(cmd)): Future[JsValue] result <- postJsonRequest(uri.withPath(Uri.Path("/v1/create")), json, headers = headers) } yield result } @@ -415,7 +414,7 @@ object HttpServiceTestFixture extends LazyLogging with Assertions with Inside { owner: domain.Party, number: String, time: v.Value.Sum.Timestamp = TimestampConversion.instantToMicros(Instant.now), - ): domain.CreateCommand[v.Record] = { + ): domain.CreateCommand[v.Record, domain.TemplateId.OptionalPkg] = { val templateId = domain.TemplateId(None, "Account", "Account") val timeValue = v.Value(time) val enabledVariantValue = @@ -435,7 +434,7 @@ object HttpServiceTestFixture extends LazyLogging with Assertions with Inside { owners: Seq[String], number: String, time: v.Value.Sum.Timestamp = TimestampConversion.instantToMicros(Instant.now), - ): domain.CreateCommand[v.Record] = { + ): domain.CreateCommand[v.Record, domain.TemplateId.OptionalPkg] = { val templateId = domain.TemplateId(None, "Account", "SharedAccount") val timeValue = v.Value(time) val enabledVariantValue = diff --git a/ledger-service/http-json/src/failure/scala/http/FailureTests.scala b/ledger-service/http-json/src/failure/scala/http/FailureTests.scala index bfa550a35c67..b2d2adb1c0a3 100644 --- a/ledger-service/http-json/src/failure/scala/http/FailureTests.scala +++ b/ledger-service/http-json/src/failure/scala/http/FailureTests.scala @@ -90,7 +90,6 @@ final class FailureTests } "Command submission timeouts" in withHttpService { (uri, encoder, _, client) => - import encoder.implicits._ import json.JsonProtocol._ for { p <- allocateParty(client, "Alice") @@ -103,7 +102,9 @@ final class FailureTests _ = status shouldBe StatusCodes.OK // Client -> Server connection _ = proxy.toxics().timeout("timeout", ToxicDirection.UPSTREAM, 0) - body <- FutureUtil.toFuture(SprayJson.encode1(accountCreateCommand(p, "24"))): Future[JsValue] + body <- FutureUtil.toFuture( + encoder.encodeCreateCommand(accountCreateCommand(p, "24")) + ): Future[JsValue] (status, output) <- postJsonStringRequestEncoded( uri.withPath(Uri.Path("/v1/create")), body.compactPrint, diff --git a/ledger-service/http-json/src/itlib/scala/http/AbstractHttpServiceIntegrationTest.scala b/ledger-service/http-json/src/itlib/scala/http/AbstractHttpServiceIntegrationTest.scala index 8e9e58cd5799..d10cb857e90f 100644 --- a/ledger-service/http-json/src/itlib/scala/http/AbstractHttpServiceIntegrationTest.scala +++ b/ledger-service/http-json/src/itlib/scala/http/AbstractHttpServiceIntegrationTest.scala @@ -167,7 +167,7 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging { } protected def postCreateCommand( - cmd: domain.CreateCommand[v.Record], + cmd: domain.CreateCommand[v.Record, OptionalPkg], encoder: DomainJsonEncoder, uri: Uri, headers: List[HttpHeader] = headersWithAuth, @@ -175,7 +175,7 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging { HttpServiceTestFixture.postCreateCommand(cmd, encoder, uri, headers) protected def postArchiveCommand( - templateId: domain.TemplateId.OptionalPkg, + templateId: OptionalPkg, contractId: domain.ContractId, encoder: DomainJsonEncoder, uri: Uri, @@ -185,7 +185,7 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging { protected def lookupContractAndAssert(contractLocator: domain.ContractLocator[JsValue])( contractId: ContractId, - create: domain.CreateCommand[v.Record], + create: domain.CreateCommand[v.Record, OptionalPkg], encoder: DomainJsonEncoder, uri: Uri, ): Future[Assertion] = @@ -206,10 +206,13 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging { protected def removeRecordId(a: v.Record): v.Record = a.copy(recordId = None) + protected def removePackageId(tmplId: domain.TemplateId.RequiredPkg): OptionalPkg = + tmplId.copy(packageId = None) + protected def iouCreateCommand( amount: String = "999.9900000000", currency: String = "USD", - ): domain.CreateCommand[v.Record] = { + ): domain.CreateCommand[v.Record, OptionalPkg] = { val templateId: OptionalPkg = domain.TemplateId(None, "Iou", "Iou") val arg = v.Record( fields = List( @@ -239,7 +242,7 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging { protected def iouCreateAndExerciseTransferCommand( amount: String = "999.9900000000", currency: String = "USD", - ): domain.CreateAndExerciseCommand[v.Record, v.Value] = { + ): domain.CreateAndExerciseCommand[v.Record, v.Value, OptionalPkg] = { val templateId: OptionalPkg = domain.TemplateId(None, "Iou", "Iou") val payload = v.Record( fields = List( @@ -400,7 +403,7 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging { protected def assertActiveContract( decoder: DomainJsonDecoder, actual: domain.ActiveContract[JsValue], - create: domain.CreateCommand[v.Record], + create: domain.CreateCommand[v.Record, OptionalPkg], exercise: domain.ExerciseCommand[v.Value, _], ): Assertion = { @@ -429,13 +432,16 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging { protected def assertActiveContract( jsVal: JsValue - )(command: domain.CreateCommand[v.Record], encoder: DomainJsonEncoder): Assertion = { + )( + command: domain.CreateCommand[v.Record, OptionalPkg], + encoder: DomainJsonEncoder, + ): Assertion = { import encoder.implicits._ - val expected: domain.CreateCommand[JsValue] = + val expected: domain.CreateCommand[JsValue, OptionalPkg] = command - .traverse(SprayJson.encode[v.Record]) + .traversePayload(SprayJson.encode[v.Record](_)) .getOrElse(fail(s"Failed to encode command: $command")) inside(SprayJson.decode[domain.ActiveContract[JsValue]](jsVal)) { case \/-(activeContract) => @@ -445,7 +451,7 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging { protected def assertTemplateId( actual: domain.TemplateId.RequiredPkg, - expected: domain.TemplateId.OptionalPkg, + expected: OptionalPkg, ): Assertion = { expected.packageId.foreach(x => actual.packageId shouldBe x) actual.moduleName shouldBe expected.moduleName @@ -486,7 +492,7 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging { } protected def searchExpectOk( - commands: List[domain.CreateCommand[v.Record]], + commands: List[domain.CreateCommand[v.Record, OptionalPkg]], query: JsObject, uri: Uri, encoder: DomainJsonEncoder, @@ -496,7 +502,7 @@ trait AbstractHttpServiceIntegrationTestFuns extends StrictLogging { } protected def search( - commands: List[domain.CreateCommand[v.Record]], + commands: List[domain.CreateCommand[v.Record, OptionalPkg]], query: JsObject, uri: Uri, encoder: DomainJsonEncoder, @@ -544,12 +550,13 @@ abstract class AbstractHttpServiceIntegrationTest } - protected val searchDataSet: List[domain.CreateCommand[v.Record]] = List( - iouCreateCommand(amount = "111.11", currency = "EUR"), - iouCreateCommand(amount = "222.22", currency = "EUR"), - iouCreateCommand(amount = "333.33", currency = "GBP"), - iouCreateCommand(amount = "444.44", currency = "BTC"), - ) + protected val searchDataSet: List[domain.CreateCommand[v.Record, OptionalPkg]] = + List( + iouCreateCommand(amount = "111.11", currency = "EUR"), + iouCreateCommand(amount = "222.22", currency = "EUR"), + iouCreateCommand(amount = "333.33", currency = "GBP"), + iouCreateCommand(amount = "444.44", currency = "BTC"), + ) "query GET" in withHttpService { (uri: Uri, encoder, _) => searchDataSet.traverse(c => postCreateCommand(c, encoder, uri)).flatMap { rs => @@ -814,7 +821,7 @@ abstract class AbstractHttpServiceIntegrationTest } "create IOU" in withHttpService { (uri, encoder, _) => - val command: domain.CreateCommand[v.Record] = iouCreateCommand() + val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand() postCreateCommand(command, encoder, uri).flatMap { case (status, output) => status shouldBe StatusCodes.OK @@ -826,10 +833,9 @@ abstract class AbstractHttpServiceIntegrationTest "create IOU should fail if authorization header is missing" in withHttpService { (uri, encoder, _) => - import encoder.implicits._ - - val command: domain.CreateCommand[v.Record] = iouCreateCommand() - val input: JsValue = SprayJson.encode1(command).valueOr(e => fail(e.shows)) + val command: domain.CreateCommand[v.Record, OptionalPkg] = + iouCreateCommand() + val input: JsValue = encoder.encodeCreateCommand(command).valueOr(e => fail(e.shows)) postJsonRequest(uri.withPath(Uri.Path("/v1/create")), input, List()).flatMap { case (status, output) => @@ -842,10 +848,8 @@ abstract class AbstractHttpServiceIntegrationTest } "create IOU should support extra readAs parties" in withHttpService { (uri, encoder, _) => - import encoder.implicits._ - - val command: domain.CreateCommand[v.Record] = iouCreateCommand() - val input: JsValue = SprayJson.encode1(command).valueOr(e => fail(e.shows)) + val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand() + val input: JsValue = encoder.encodeCreateCommand(command).valueOr(e => fail(e.shows)) postJsonRequest( uri.withPath(Uri.Path("/v1/create")), @@ -861,26 +865,24 @@ abstract class AbstractHttpServiceIntegrationTest "create IOU with unsupported templateId should return proper error" in withHttpService { (uri, encoder, _) => - import encoder.implicits._ - - val command: domain.CreateCommand[v.Record] = + val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand().copy(templateId = domain.TemplateId(None, "Iou", "Dummy")) - val input: JsValue = SprayJson.encode1(command).valueOr(e => fail(e.shows)) + val input: JsValue = encoder.encodeCreateCommand(command).valueOr(e => fail(e.shows)) postJsonRequest(uri.withPath(Uri.Path("/v1/create")), input).flatMap { case (status, output) => status shouldBe StatusCodes.BadRequest assertStatus(output, StatusCodes.BadRequest) - val unknownTemplateId: domain.TemplateId.OptionalPkg = + val unknownTemplateId: OptionalPkg = domain.TemplateId(None, command.templateId.moduleName, command.templateId.entityName) expectedOneErrorMessage(output) should include( - s"Cannot resolve template ID, given: ${unknownTemplateId: domain.TemplateId.OptionalPkg}" + s"Cannot resolve template ID, given: ${unknownTemplateId: OptionalPkg}" ) }: Future[Assertion] } "exercise IOU_Transfer" in withHttpService { (uri, encoder, decoder) => - val create: domain.CreateCommand[v.Record] = iouCreateCommand() + val create: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand() postCreateCommand(create, encoder, uri) .flatMap { case (createStatus, createOutput) => createStatus shouldBe StatusCodes.OK @@ -907,12 +909,10 @@ abstract class AbstractHttpServiceIntegrationTest } "create-and-exercise IOU_Transfer" in withHttpService { (uri, encoder, _) => - import encoder.implicits._ - - val cmd: domain.CreateAndExerciseCommand[v.Record, v.Value] = + val cmd: domain.CreateAndExerciseCommand[v.Record, v.Value, OptionalPkg] = iouCreateAndExerciseTransferCommand() - val json: JsValue = SprayJson.encode2(cmd).valueOr(e => fail(e.shows)) + val json: JsValue = encoder.encodeCreateAndExerciseCommand(cmd).valueOr(e => fail(e.shows)) postJsonRequest(uri.withPath(Uri.Path("/v1/create-and-exercise")), json) .flatMap { case (status, output) => @@ -940,7 +940,7 @@ abstract class AbstractHttpServiceIntegrationTest private def assertExerciseResponseNewActiveContract( exerciseResponse: JsValue, - createCmd: domain.CreateCommand[v.Record], + createCmd: domain.CreateCommand[v.Record, OptionalPkg], exerciseCmd: domain.ExerciseCommand[v.Value, domain.EnrichedContractId], decoder: DomainJsonDecoder, uri: Uri, @@ -984,7 +984,7 @@ abstract class AbstractHttpServiceIntegrationTest } "exercise Archive" in withHttpService { (uri, encoder, _) => - val create: domain.CreateCommand[v.Record] = iouCreateCommand() + val create: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand() postCreateCommand(create, encoder, uri) .flatMap { case (createStatus, createOutput) => createStatus shouldBe StatusCodes.OK @@ -1087,16 +1087,15 @@ abstract class AbstractHttpServiceIntegrationTest encoder: DomainJsonEncoder, decoder: DomainJsonDecoder, ): Assertion = { - import encoder.implicits._ import json.JsonProtocol._ import util.ErrorOps._ - val command0: domain.CreateCommand[v.Record] = iouCreateCommand() + val command0: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand() val x = for { - jsVal <- SprayJson.encode1(command0).liftErr(JsonError) + jsVal <- encoder.encodeCreateCommand(command0).liftErr(JsonError) command1 <- decoder.decodeCreateCommand(jsVal) - } yield command1.map(removeRecordId) should ===(command0) + } yield command1.bimap(removeRecordId, removePackageId) should ===(command0) x.fold(e => fail(e.shows), identity) } @@ -1315,7 +1314,7 @@ abstract class AbstractHttpServiceIntegrationTest } "fetch by contractId" in withHttpService { (uri, encoder, _) => - val command: domain.CreateCommand[v.Record] = iouCreateCommand() + val command: domain.CreateCommand[v.Record, OptionalPkg] = iouCreateCommand() postCreateCommand(command, encoder, uri).flatMap { case (status, output) => status shouldBe StatusCodes.OK @@ -1348,7 +1347,7 @@ abstract class AbstractHttpServiceIntegrationTest "fetch by key" in withHttpService { (uri, encoder, _) => val owner = domain.Party("Alice") val accountNumber = "abc123" - val command: domain.CreateCommand[v.Record] = + val command: domain.CreateCommand[v.Record, OptionalPkg] = accountCreateCommand(owner, accountNumber) postCreateCommand(command, encoder, uri).flatMap { case (status, output) => @@ -1366,7 +1365,7 @@ abstract class AbstractHttpServiceIntegrationTest "commands/exercise Archive by key" in withHttpService { (uri, encoder, _) => val owner = domain.Party("Alice") val accountNumber = "abc123" - val create: domain.CreateCommand[v.Record] = + val create: domain.CreateCommand[v.Record, OptionalPkg] = accountCreateCommand(owner, accountNumber) val keyRecord = v.Record( @@ -1457,7 +1456,7 @@ abstract class AbstractHttpServiceIntegrationTest val accountNumber = "abc123" val now = TimestampConversion.instantToMicros(Instant.now) val nowStr = TimestampConversion.microsToInstant(now).toString - val command: domain.CreateCommand[v.Record] = + val command: domain.CreateCommand[v.Record, OptionalPkg] = accountCreateCommand(owner, accountNumber, now) val packageId: Ref.PackageId = MetadataReader diff --git a/ledger-service/http-json/src/main/scala/com/digitalasset/http/CommandService.scala b/ledger-service/http-json/src/main/scala/com/digitalasset/http/CommandService.scala index 68c4b5f08e34..39dcc324e961 100644 --- a/ledger-service/http-json/src/main/scala/com/digitalasset/http/CommandService.scala +++ b/ledger-service/http-json/src/main/scala/com/digitalasset/http/CommandService.scala @@ -4,7 +4,6 @@ package com.daml.http import com.daml.lf.data.ImmArray.ImmArraySeq -import com.daml.http.ErrorMessages.cannotResolveTemplateId import com.daml.http.domain.{ ActiveContract, Contract, @@ -13,6 +12,7 @@ import com.daml.http.domain.{ ExerciseCommand, ExerciseResponse, JwtWritePayload, + TemplateId, } import com.daml.http.util.ClientUtil.uniqueCommandId import com.daml.http.util.FutureUtil._ @@ -33,7 +33,6 @@ import scala.concurrent.{ExecutionContext, Future} import scala.util.{Failure, Success} class CommandService( - resolveTemplateId: PackageService.ResolveTemplateId, submitAndWaitForTransaction: LedgerClientJwt.SubmitAndWaitForTransaction, submitAndWaitForTransactionTree: LedgerClientJwt.SubmitAndWaitForTransactionTree, )(implicit ec: ExecutionContext) { @@ -43,14 +42,14 @@ class CommandService( def create( jwt: Jwt, jwtPayload: JwtWritePayload, - input: CreateCommand[lav1.value.Record], + input: CreateCommand[lav1.value.Record, TemplateId.RequiredPkg], )(implicit lc: LoggingContextOf[InstanceUUID with RequestID] ): Future[Error \/ ActiveContract[lav1.value.Value]] = { logger.trace("sending create command to ledger") + val command = createCommand(input) + val request = submitAndWaitRequest(jwtPayload, input.meta, command) val et: ET[ActiveContract[lav1.value.Value]] = for { - command <- either(createCommand(input)) - request = submitAndWaitRequest(jwtPayload, input.meta, command) response <- rightT(logResult(Symbol("create"), submitAndWaitForTransaction(jwt, request))) contract <- either(exactlyOneActiveContract(response)) } yield contract @@ -82,14 +81,14 @@ class CommandService( def createAndExercise( jwt: Jwt, jwtPayload: JwtWritePayload, - input: CreateAndExerciseCommand[lav1.value.Record, lav1.value.Value], + input: CreateAndExerciseCommand[lav1.value.Record, lav1.value.Value, TemplateId.RequiredPkg], )(implicit lc: LoggingContextOf[InstanceUUID with RequestID] ): Future[Error \/ ExerciseResponse[lav1.value.Value]] = { logger.trace("sending create and exercise command to ledger") + val command = createAndExerciseCommand(input) + val request = submitAndWaitRequest(jwtPayload, input.meta, command) val et: ET[ExerciseResponse[lav1.value.Value]] = for { - command <- either(createAndExerciseCommand(input)) - request = submitAndWaitRequest(jwtPayload, input.meta, command) response <- rightT( logResult(Symbol("createAndExercise"), submitAndWaitForTransactionTree(jwt, request)) ) @@ -111,11 +110,9 @@ class CommandService( } private def createCommand( - input: CreateCommand[lav1.value.Record] - ): Error \/ lav1.commands.Command.Command.Create = { - resolveTemplateId(input.templateId) - .toRightDisjunction(Error(Symbol("createCommand"), cannotResolveTemplateId(input.templateId))) - .map(tpId => Commands.create(refApiIdentifier(tpId), input.payload)) + input: CreateCommand[lav1.value.Record, TemplateId.RequiredPkg] + ): lav1.commands.Command.Command.Create = { + Commands.create(refApiIdentifier(input.templateId), input.payload) } private def exerciseCommand( @@ -139,15 +136,14 @@ class CommandService( } private def createAndExerciseCommand( - input: CreateAndExerciseCommand[lav1.value.Record, lav1.value.Value] - ): Error \/ lav1.commands.Command.Command.CreateAndExercise = - resolveTemplateId(input.templateId) - .toRightDisjunction( - Error(Symbol("createAndExerciseCommand"), cannotResolveTemplateId(input.templateId)) - ) - .map(tpId => - Commands - .createAndExercise(refApiIdentifier(tpId), input.payload, input.choice, input.argument) + input: CreateAndExerciseCommand[lav1.value.Record, lav1.value.Value, TemplateId.RequiredPkg] + ): lav1.commands.Command.Command.CreateAndExercise = + Commands + .createAndExercise( + refApiIdentifier(input.templateId), + input.payload, + input.choice, + input.argument, ) private def submitAndWaitRequest( diff --git a/ledger-service/http-json/src/main/scala/com/digitalasset/http/Endpoints.scala b/ledger-service/http-json/src/main/scala/com/digitalasset/http/Endpoints.scala index a3640691556f..100342beb57a 100644 --- a/ledger-service/http-json/src/main/scala/com/digitalasset/http/Endpoints.scala +++ b/ledger-service/http-json/src/main/scala/com/digitalasset/http/Endpoints.scala @@ -20,7 +20,7 @@ import com.daml.lf import com.daml.http.ContractsService.SearchResult import com.daml.http.EndpointsCompanion._ import com.daml.scalautil.Statement.discard -import com.daml.http.domain.{JwtPayload, JwtWritePayload} +import com.daml.http.domain.{JwtPayload, JwtWritePayload, TemplateId} import com.daml.http.json._ import com.daml.http.util.Collections.toNonEmptySet import com.daml.http.util.FutureUtil.{either, eitherT} @@ -126,7 +126,7 @@ class Endpoints( cmd <- either( decoder.decodeCreateCommand(reqBody).liftErr(InvalidUserInput) - ): ET[domain.CreateCommand[ApiRecord]] + ): ET[domain.CreateCommand[ApiRecord, TemplateId.RequiredPkg]] ac <- eitherT( handleFutureEitherFailure(commandService.create(jwt, jwtPayload, cmd)) @@ -174,7 +174,7 @@ class Endpoints( cmd <- either( decoder.decodeCreateAndExerciseCommand(reqBody).liftErr(InvalidUserInput) - ): ET[domain.CreateAndExerciseCommand[ApiRecord, ApiValue]] + ): ET[domain.CreateAndExerciseCommand[ApiRecord, ApiValue, TemplateId.RequiredPkg]] resp <- eitherT( handleFutureEitherFailure(commandService.createAndExercise(jwt, jwtPayload, cmd)) diff --git a/ledger-service/http-json/src/main/scala/com/digitalasset/http/HttpService.scala b/ledger-service/http-json/src/main/scala/com/digitalasset/http/HttpService.scala index 4b4bd1d36ad6..dca38c6a5e46 100644 --- a/ledger-service/http-json/src/main/scala/com/digitalasset/http/HttpService.scala +++ b/ledger-service/http-json/src/main/scala/com/digitalasset/http/HttpService.scala @@ -126,7 +126,6 @@ object HttpService { _ = schedulePackageReload(packageService, packageReloadInterval) commandService = new CommandService( - packageService.resolveTemplateId, LedgerClientJwt.submitAndWaitForTransaction(client), LedgerClientJwt.submitAndWaitForTransactionTree(client), ) diff --git a/ledger-service/http-json/src/main/scala/com/digitalasset/http/domain.scala b/ledger-service/http-json/src/main/scala/com/digitalasset/http/domain.scala index 92062efecee3..8a23a03e7aaa 100644 --- a/ledger-service/http-json/src/main/scala/com/digitalasset/http/domain.scala +++ b/ledger-service/http-json/src/main/scala/com/digitalasset/http/domain.scala @@ -146,11 +146,16 @@ object domain { // TODO(Leo): add Option[WorkflowId] back ) - final case class CreateCommand[+LfV]( - templateId: TemplateId.OptionalPkg, + final case class CreateCommand[+LfV, TmplId]( + templateId: TmplId, payload: LfV, meta: Option[CommandMeta], - ) + ) { + def traversePayload[G[_]: Applicative, LfVB]( + f: LfV => G[LfVB] + ): G[CreateCommand[LfVB, TmplId]] = + Bitraverse[CreateCommand].leftTraverse.traverse(this)(f) + } final case class ExerciseCommand[+LfV, +Ref]( reference: Ref, @@ -159,8 +164,8 @@ object domain { meta: Option[CommandMeta], ) - final case class CreateAndExerciseCommand[+Payload, +Arg]( - templateId: TemplateId.OptionalPkg, + final case class CreateAndExerciseCommand[+Payload, +Arg, +TmplId]( + templateId: TmplId, payload: Payload, choice: domain.Choice, argument: Arg, @@ -518,11 +523,13 @@ object domain { } object CreateCommand { - implicit val traverseInstance: Traverse[CreateCommand] = new Traverse[CreateCommand] { - override def traverseImpl[G[_]: Applicative, A, B]( - fa: CreateCommand[A] - )(f: A => G[B]): G[CreateCommand[B]] = - f(fa.payload).map(a => fa.copy(payload = a)) + implicit val bitraverseInstance: Bitraverse[CreateCommand] = new Bitraverse[CreateCommand] { + override def bitraverseImpl[G[_]: Applicative, A, B, C, D]( + fab: CreateCommand[A, B] + )(f: A => G[C], g: B => G[D]): G[CreateCommand[C, D]] = { + import scalaz.syntax.applicative._ + ^(f(fab.payload), g(fab.templateId))((c, d) => fab.copy(payload = c, templateId = d)) + } } } @@ -567,18 +574,6 @@ object domain { } } - object CreateAndExerciseCommand { - implicit val bitraverseInstance: Bitraverse[CreateAndExerciseCommand] = - new Bitraverse[CreateAndExerciseCommand] { - override def bitraverseImpl[G[_]: Applicative, A, B, C, D]( - fab: CreateAndExerciseCommand[A, B] - )(f: A => G[C], g: B => G[D]): G[CreateAndExerciseCommand[C, D]] = { - import scalaz.syntax.applicative._ - ^(f(fab.payload), g(fab.argument))((p, a) => fab.copy(payload = p, argument = a)) - } - } - } - object ExerciseResponse { implicit val traverseInstance: Traverse[ExerciseResponse] = new Traverse[ExerciseResponse] { override def traverseImpl[G[_]: Applicative, A, B]( diff --git a/ledger-service/http-json/src/main/scala/com/digitalasset/http/json/DomainJsonDecoder.scala b/ledger-service/http-json/src/main/scala/com/digitalasset/http/json/DomainJsonDecoder.scala index 55733df6d7a0..09a62c005c3a 100644 --- a/ledger-service/http-json/src/main/scala/com/digitalasset/http/json/DomainJsonDecoder.scala +++ b/ledger-service/http-json/src/main/scala/com/digitalasset/http/json/DomainJsonDecoder.scala @@ -4,7 +4,7 @@ package com.daml.http.json import com.daml.http.ErrorMessages.cannotResolveTemplateId -import com.daml.http.domain.HasTemplateId +import com.daml.http.domain.{HasTemplateId, TemplateId} import com.daml.http.json.JsValueToApiValueConverter.mustBeApiRecord import com.daml.http.{PackageService, domain} import com.daml.ledger.api.{v1 => lav1} @@ -27,17 +27,21 @@ class DomainJsonDecoder( import com.daml.http.util.ErrorOps._ def decodeCreateCommand(a: JsValue)(implicit - ev1: JsonReader[domain.CreateCommand[JsValue]] - ): JsonError \/ domain.CreateCommand[lav1.value.Record] = { + ev1: JsonReader[domain.CreateCommand[JsValue, TemplateId.OptionalPkg]] + ): JsonError \/ domain.CreateCommand[lav1.value.Record, TemplateId.RequiredPkg] = { val err = "DomainJsonDecoder_decodeCreateCommand" for { fj <- SprayJson - .decode[domain.CreateCommand[JsValue]](a) + .decode[domain.CreateCommand[JsValue, TemplateId.OptionalPkg]](a) .liftErrS(err)(JsonError) - payloadT <- templateRecordType(fj.templateId) + tmplId <- templateId_(fj.templateId) - fv <- fj.traverse(x => jsValueToApiValue(payloadT, x).flatMap(mustBeApiRecord)) + payloadT <- templateRecordType(tmplId) + + fv <- fj + .copy(templateId = tmplId) + .traversePayload(x => jsValueToApiValue(payloadT, x).flatMap(mustBeApiRecord)) } yield fv } @@ -107,12 +111,16 @@ class DomainJsonDecoder( } yield cmd1 def decodeCreateAndExerciseCommand(a: JsValue)(implicit - ev1: JsonReader[domain.CreateAndExerciseCommand[JsValue, JsValue]] - ): JsonError \/ domain.CreateAndExerciseCommand[lav1.value.Record, lav1.value.Value] = { + ev1: JsonReader[domain.CreateAndExerciseCommand[JsValue, JsValue, TemplateId.OptionalPkg]] + ): JsonError \/ domain.CreateAndExerciseCommand[ + lav1.value.Record, + lav1.value.Value, + TemplateId.RequiredPkg, + ] = { val err = "DomainJsonDecoder_decodeCreateAndExerciseCommand" for { fjj <- SprayJson - .decode[domain.CreateAndExerciseCommand[JsValue, JsValue]](a) + .decode[domain.CreateAndExerciseCommand[JsValue, JsValue, TemplateId.OptionalPkg]](a) .liftErrS(err)(JsonError) tId <- templateId_(fjj.templateId) @@ -121,12 +129,9 @@ class DomainJsonDecoder( argT <- resolveChoiceArgType(tId, fjj.choice).liftErr(JsonError) - fvv <- fjj.bitraverse( - x => jsValueToApiValue(payloadT, x).flatMap(mustBeApiRecord), - x => jsValueToApiValue(argT, x), - ) - - } yield fvv + payload <- jsValueToApiValue(payloadT, fjj.payload).flatMap(mustBeApiRecord) + argument <- jsValueToApiValue(argT, fjj.argument) + } yield fjj.copy(payload = payload, argument = argument, templateId = tId) } private def templateId_( @@ -147,8 +152,8 @@ class DomainJsonDecoder( .flatMap(jsObj => jsValueToApiValue(lfType, jsObj).flatMap(mustBeApiRecord)) .valueOr(e => spray.json.deserializationError(e.shows)) - def templateRecordType(id: domain.TemplateId.OptionalPkg): JsonError \/ domain.LfType = - templateId_(id).flatMap(resolveTemplateRecordType(_).liftErr(JsonError)) + def templateRecordType(id: domain.TemplateId.RequiredPkg): JsonError \/ domain.LfType = + resolveTemplateRecordType(id).liftErr(JsonError) def choiceArgType( id: domain.TemplateId.OptionalPkg, diff --git a/ledger-service/http-json/src/main/scala/com/digitalasset/http/json/DomainJsonEncoder.scala b/ledger-service/http-json/src/main/scala/com/digitalasset/http/json/DomainJsonEncoder.scala index 9b99e37b2d3b..34f7afffc372 100644 --- a/ledger-service/http-json/src/main/scala/com/digitalasset/http/json/DomainJsonEncoder.scala +++ b/ledger-service/http-json/src/main/scala/com/digitalasset/http/json/DomainJsonEncoder.scala @@ -33,6 +33,37 @@ class DomainJsonEncoder( } yield y + def encodeCreateCommand( + cmd: domain.CreateCommand[lav1.value.Record, domain.TemplateId.OptionalPkg] + )(implicit + ev: JsonWriter[domain.CreateCommand[JsValue, domain.TemplateId.OptionalPkg]] + ): JsonError \/ JsValue = + for { + x <- cmd.traversePayload( + apiRecordToJsObject(_) + ): JsonError \/ domain.CreateCommand[JsValue, domain.TemplateId.OptionalPkg] + y <- SprayJson.encode(x).liftErr(JsonError) + + } yield y + + def encodeCreateAndExerciseCommand( + cmd: domain.CreateAndExerciseCommand[ + lav1.value.Record, + lav1.value.Value, + domain.TemplateId.OptionalPkg, + ] + )(implicit + ev: JsonWriter[ + domain.CreateAndExerciseCommand[JsValue, JsValue, domain.TemplateId.OptionalPkg] + ] + ): JsonError \/ JsValue = + for { + payload <- apiRecordToJsObject(cmd.payload): JsonError \/ JsValue + argument <- apiValueToJsValue(cmd.argument) + y <- SprayJson.encode(cmd.copy(payload = payload, argument = argument)).liftErr(JsonError) + + } yield y + object implicits { implicit val ApiValueJsonWriter: JsonWriter[lav1.value.Value] = (obj: lav1.value.Value) => apiValueToJsValue(obj).valueOr(e => spray.json.serializationError(e.shows)) diff --git a/ledger-service/http-json/src/main/scala/com/digitalasset/http/json/JsonProtocol.scala b/ledger-service/http-json/src/main/scala/com/digitalasset/http/json/JsonProtocol.scala index 5d2872626415..ee81c100760b 100644 --- a/ledger-service/http-json/src/main/scala/com/digitalasset/http/json/JsonProtocol.scala +++ b/ledger-service/http-json/src/main/scala/com/digitalasset/http/json/JsonProtocol.scala @@ -271,8 +271,9 @@ object JsonProtocol extends DefaultJsonProtocol with ExtraFormats { domain.CommandMeta ) - implicit val CreateCommandFormat: RootJsonFormat[domain.CreateCommand[JsValue]] = jsonFormat3( - domain.CreateCommand[JsValue] + implicit val CreateCommandFormat + : RootJsonFormat[domain.CreateCommand[JsValue, domain.TemplateId.OptionalPkg]] = jsonFormat3( + domain.CreateCommand[JsValue, domain.TemplateId.OptionalPkg] ) implicit val ExerciseCommandFormat @@ -310,9 +311,10 @@ object JsonProtocol extends DefaultJsonProtocol with ExtraFormats { } } - implicit val CreateAndExerciseCommandFormat - : RootJsonFormat[domain.CreateAndExerciseCommand[JsValue, JsValue]] = - jsonFormat5(domain.CreateAndExerciseCommand[JsValue, JsValue]) + implicit val CreateAndExerciseCommandFormat: RootJsonFormat[ + domain.CreateAndExerciseCommand[JsValue, JsValue, domain.TemplateId.OptionalPkg] + ] = + jsonFormat5(domain.CreateAndExerciseCommand[JsValue, JsValue, domain.TemplateId.OptionalPkg]) implicit val ExerciseResponseFormat: RootJsonFormat[domain.ExerciseResponse[JsValue]] = jsonFormat2(domain.ExerciseResponse[JsValue])