Make ApplicationId in DAML Script configurable (#7074)

This is set per participant since it is similar to the token file.

fixes #7029

changelog_begin

- [DAML Script/DAML REPL] You can now configure the application id via
  `--application-id` or the `--participant-config`. This is primarily
  useful if you are working against a ledger with authentication and
  need to match the application id in your token.

changelog_end
This commit is contained in:
Moritz Kiefer 2020-08-10 17:24:38 +02:00 committed by GitHub
parent 23a46e55ec
commit e1236d42ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 162 additions and 71 deletions

View File

@ -269,6 +269,13 @@ cmdRepl numProcessors =
<*> strOption (long "ledger-port" <> help "Port of the ledger API")
)
<*> accessTokenFileFlag
<*> optional
(ReplClient.ApplicationId <$>
strOption
(long "application-id" <>
help "Application ID used for command submissions"
)
)
<*> sslConfig
<*> optional
(option auto $
@ -603,11 +610,12 @@ execRepl
-> FilePath -> [FilePath] -> [(LF.PackageName, Maybe LF.PackageVersion)]
-> Maybe (String, String)
-> Maybe FilePath
-> Maybe ReplClient.ApplicationId
-> Maybe ReplClient.ClientSSLConfig
-> Maybe ReplClient.MaxInboundMessageSize
-> ReplClient.ReplTimeMode
-> Command
execRepl projectOpts opts scriptDar dars importPkgs mbLedgerConfig mbAuthToken mbSslConf mbMaxInboundMessageSize timeMode = Command Repl (Just projectOpts) effect
execRepl projectOpts opts scriptDar dars importPkgs mbLedgerConfig mbAuthToken mbAppId mbSslConf mbMaxInboundMessageSize timeMode = Command Repl (Just projectOpts) effect
where effect = do
-- We change directory so make this absolute
dars <- mapM makeAbsolute dars
@ -618,7 +626,7 @@ execRepl projectOpts opts scriptDar dars importPkgs mbLedgerConfig mbAuthToken m
logger <- getLogger opts "repl"
runfilesDir <- locateRunfiles (mainWorkspace </> "compiler/repl-service/server")
let jar = runfilesDir </> "repl-service.jar"
ReplClient.withReplClient (ReplClient.Options jar mbLedgerConfig mbAuthToken mbSslConf mbMaxInboundMessageSize timeMode Inherit) $ \replHandle _stdout _ph ->
ReplClient.withReplClient (ReplClient.Options jar mbLedgerConfig mbAuthToken mbAppId mbSslConf mbMaxInboundMessageSize timeMode Inherit) $ \replHandle _stdout _ph ->
withTempDir $ \dir ->
withCurrentDirectory dir $ do
sdkVer <- fromMaybe SdkVersion.sdkVersion <$> lookupEnv sdkVersionEnvVar

View File

@ -63,7 +63,7 @@ main = do
withTempFile $ \portFile ->
withBinaryFile nullDevice WriteMode $ \devNull ->
bracket (createSandbox portFile devNull defaultSandboxConf { dars = testDars }) destroySandbox $ \SandboxResource{sandboxPort} ->
ReplClient.withReplClient (ReplClient.Options replJar (Just ("localhost", show sandboxPort)) Nothing Nothing Nothing ReplClient.ReplWallClock CreatePipe) $ \replHandle mbServiceOut processHandle ->
ReplClient.withReplClient (ReplClient.Options replJar (Just ("localhost", show sandboxPort)) Nothing Nothing Nothing Nothing ReplClient.ReplWallClock CreatePipe) $ \replHandle mbServiceOut processHandle ->
-- TODO We could share some of this setup with the actual repl code in damlc.
withTempDir $ \dir ->
withCurrentDirectory dir $ do

View File

@ -5,6 +5,7 @@
{-# LANGUAGE GADTs #-}
module DA.Daml.LF.ReplClient
( Options(..)
, ApplicationId(..)
, MaxInboundMessageSize(..)
, ReplTimeMode(..)
, Handle
@ -41,10 +42,13 @@ newtype MaxInboundMessageSize = MaxInboundMessageSize Int
data ReplTimeMode = ReplWallClock | ReplStatic
newtype ApplicationId = ApplicationId String
data Options = Options
{ optServerJar :: FilePath
, optLedgerConfig :: Maybe (String, String)
, optMbAuthTokenFile :: Maybe FilePath
, optMbApplicationId :: Maybe ApplicationId
, optMbSslConfig :: Maybe ClientSSLConfig
, optMaxInboundMessageSize :: Maybe MaxInboundMessageSize
, optTimeMode :: ReplTimeMode
@ -87,6 +91,7 @@ withReplClient opts@Options{..} f = withTempFile $ \portFile -> do
| Just (host, port) <- [optLedgerConfig]
]
, [ "--access-token-file=" <> tokenFile | Just tokenFile <- [optMbAuthTokenFile] ]
, [ "--application-id=" <> appId | Just (ApplicationId appId) <- [ optMbApplicationId] ]
, do Just tlsConf <- [ optMbSslConfig ]
"--tls" :
concat

View File

@ -33,6 +33,7 @@ object ReplServiceMain extends App {
ledgerHost: Option[String],
ledgerPort: Option[Int],
accessTokenFile: Option[Path],
applicationId: Option[ApplicationId],
maxInboundMessageSize: Int,
tlsConfig: TlsConfiguration,
// optional so we can detect if both --static-time and --wall-clock-time are passed.
@ -68,6 +69,12 @@ object ReplServiceMain extends App {
c.copy(accessTokenFile = Some(Paths.get(tokenFile)))
}
opt[String]("application-id")
.optional()
.action { (appId, c) =>
c.copy(applicationId = Some(ApplicationId(appId)))
}
TlsConfigurationCli.parse(this, colSpacer = " ")((f, c) =>
c copy (tlsConfig = f(c.tlsConfig)))
@ -109,6 +116,7 @@ object ReplServiceMain extends App {
tlsConfig = TlsConfiguration(false, None, None, None),
maxInboundMessageSize = RunnerConfig.DefaultMaxInboundMessageSize,
timeMode = None,
applicationId = None,
)
)
}
@ -129,15 +137,15 @@ object ReplServiceMain extends App {
val tokenHolder = config.accessTokenFile.map(new TokenHolder(_))
val defaultParticipant = (config.ledgerHost, config.ledgerPort) match {
case (Some(host), Some(port)) => Some(ApiParameters(host, port, tokenHolder.flatMap(_.token)))
case (Some(host), Some(port)) =>
Some(ApiParameters(host, port, tokenHolder.flatMap(_.token), config.applicationId))
case _ => None
}
val participantParams =
Participants(defaultParticipant, Map.empty, Map.empty)
val applicationId = ApplicationId("daml repl")
val clients = Await.result(
Runner
.connect(participantParams, applicationId, config.tlsConfig, config.maxInboundMessageSize),
.connect(participantParams, config.tlsConfig, config.maxInboundMessageSize),
30.seconds)
val timeMode = config.timeMode.getOrElse(ScriptTimeMode.WallClock)

View File

@ -513,7 +513,7 @@ class JsonLedgerClient(
case -\/(e) => throw new IllegalArgumentException(e.toString)
case \/-(a) => a
}
private val tokenPayload: AuthServiceJWTPayload =
private[script] val tokenPayload: AuthServiceJWTPayload =
AuthServiceJWTCodec.readFromString(decodedJwt.payload) match {
case Failure(e) => throw e
case Success(s) => s

View File

@ -51,7 +51,11 @@ object LfValueCodec extends ApiCodecCompressed[ContractId](false, false)
case class Participant(participant: String)
case class Party(party: String)
case class ApiParameters(host: String, port: Int, access_token: Option[String])
case class ApiParameters(
host: String,
port: Int,
access_token: Option[String],
application_id: Option[ApplicationId])
case class Participants[+T](
default_participant: Option[T],
participants: Map[Participant, T],
@ -121,7 +125,14 @@ object ParticipantsJsonProtocol extends DefaultJsonProtocol {
case _ => deserializationError("ContractId must be a string")
}
}
implicit val apiParametersFormat = jsonFormat3(ApiParameters)
implicit object ApplicationIdFormat extends JsonFormat[ApplicationId] {
def read(value: JsValue) = value match {
case JsString(s) => ApplicationId(s)
case _ => deserializationError("Expected ApplicationId string")
}
def write(id: ApplicationId) = JsString(ApplicationId.unwrap(id))
}
implicit val apiParametersFormat = jsonFormat4(ApiParameters)
implicit val participantsFormat = jsonFormat3(Participants[ApiParameters])
}
@ -165,11 +176,11 @@ object Runner {
val DEFAULT_APPLICATION_ID: ApplicationId = ApplicationId("daml-script")
private def connectApiParameters(
params: ApiParameters,
applicationId: ApplicationId,
tlsConfig: TlsConfiguration,
maxInboundMessageSize: Int)(
implicit ec: ExecutionContext,
seq: ExecutionSequencerFactory): Future[GrpcLedgerClient] = {
val applicationId = params.application_id.getOrElse(Runner.DEFAULT_APPLICATION_ID)
val clientConfig = LedgerClientConfiguration(
applicationId = ApplicationId.unwrap(applicationId),
ledgerIdRequirement = LedgerIdRequirement.none,
@ -189,16 +200,15 @@ object Runner {
// We might want to have one config per participant at some point but for now this should be sufficient.
def connect(
participantParams: Participants[ApiParameters],
applicationId: ApplicationId,
tlsConfig: TlsConfiguration,
maxInboundMessageSize: Int)(
implicit ec: ExecutionContext,
seq: ExecutionSequencerFactory): Future[Participants[GrpcLedgerClient]] = {
for {
defaultClient <- participantParams.default_participant.traverse(x =>
connectApiParameters(x, applicationId, tlsConfig, maxInboundMessageSize))
connectApiParameters(x, tlsConfig, maxInboundMessageSize))
participantClients <- participantParams.participants.traverse(v =>
connectApiParameters(v, applicationId, tlsConfig, maxInboundMessageSize))
connectApiParameters(v, tlsConfig, maxInboundMessageSize))
} yield Participants(defaultClient, participantClients, participantParams.party_participants)
}
@ -211,7 +221,13 @@ object Runner {
case None =>
Future.failed(new RuntimeException(s"The JSON API always requires access tokens"))
case Some(token) =>
Future.successful(new JsonLedgerClient(uri, Jwt(token), envIface, system))
val client = new JsonLedgerClient(uri, Jwt(token), envIface, system)
if (params.application_id.isDefined && params.application_id != client.tokenPayload.applicationId) {
Future.failed(new RuntimeException(
s"ApplicationId specified in token ${client.tokenPayload.applicationId} must match ${params.application_id}"))
} else {
Future.successful(new JsonLedgerClient(uri, Jwt(token), envIface, system))
}
}
}

View File

@ -7,6 +7,7 @@ import java.nio.file.{Path, Paths}
import java.io.File
import java.time.Duration
import com.daml.ledger.api.refinements.ApiTypes.ApplicationId
import com.daml.ledger.api.tls.{TlsConfiguration, TlsConfigurationCli}
case class RunnerConfig(
@ -24,6 +25,10 @@ case class RunnerConfig(
tlsConfig: TlsConfiguration,
jsonApi: Boolean,
maxInboundMessageSize: Int,
// While we do have a default application id, we
// want to differentiate between not specifying the application id
// and specifying the default for better error messages.
applicationId: Option[ApplicationId],
)
object RunnerConfig {
@ -110,6 +115,12 @@ object RunnerConfig {
.text(
s"Optional max inbound message size in bytes. Defaults to $DefaultMaxInboundMessageSize")
opt[String]("application-id")
.action((x, c) => c.copy(applicationId = Some(ApplicationId(x))))
.optional()
.text(
s"Application ID used to interact with the ledger. Defaults to ${Runner.DEFAULT_APPLICATION_ID}")
help("help").text("Print this usage text")
checkConfig(c => {
@ -154,6 +165,7 @@ object RunnerConfig {
tlsConfig = TlsConfiguration(false, None, None, None),
jsonApi = false,
maxInboundMessageSize = DefaultMaxInboundMessageSize,
applicationId = None,
)
)
}

View File

@ -40,7 +40,6 @@ object RunnerMain {
val scriptId: Identifier =
Identifier(dar.main._1, QualifiedName.assertFromString(config.scriptIdentifier))
val applicationId = Runner.DEFAULT_APPLICATION_ID
val timeMode: ScriptTimeMode = config.timeMode.getOrElse(RunnerConfig.DefaultTimeMode)
implicit val system: ActorSystem = ActorSystem("ScriptRunner")
@ -61,10 +60,9 @@ object RunnerMain {
val participantParams = config.participantConfig match {
case Some(file) => {
// To avoid a breaking change, we allow specifying
// --access-token-file and --participant-config
// together and use the token file as the default for all participants
// that do not specify an explicit token.
// We allow specifying --access-token-file/--application-id together with
// --participant-config and use the values as the default for
// all participants that do not specify an explicit token.
val source = Source.fromFile(file)
val fileContent = try {
source.mkString
@ -76,7 +74,11 @@ object RunnerMain {
import ParticipantsJsonProtocol._
jsVal
.convertTo[Participants[ApiParameters]]
.map(params => params.copy(access_token = params.access_token.orElse(token)))
.map(
params =>
params.copy(
access_token = params.access_token.orElse(token),
application_id = params.application_id.orElse(config.applicationId)))
}
case None =>
val tokenHolder = config.accessTokenFile.map(new TokenHolder(_))
@ -85,7 +87,8 @@ object RunnerMain {
ApiParameters(
config.ledgerHost.get,
config.ledgerPort.get,
tokenHolder.flatMap(_.token))),
tokenHolder.flatMap(_.token),
config.applicationId)),
participants = Map.empty,
party_participants = Map.empty
)
@ -97,11 +100,7 @@ object RunnerMain {
val envIface = EnvironmentInterface.fromReaderInterfaces(ifaceDar)
Runner.jsonClients(participantParams, envIface)
} else {
Runner.connect(
participantParams,
applicationId,
config.tlsConfig,
config.maxInboundMessageSize)
Runner.connect(participantParams, config.tlsConfig, config.maxInboundMessageSize)
}
result <- Runner.run(dar, scriptId, inputValue, clients, timeMode)
_ <- Future {

View File

@ -54,7 +54,6 @@ object TestMain extends StrictLogging {
case (pkgId, pkgArchive) => Decode.readArchivePayload(pkgId, pkgArchive)
}
val applicationId = Runner.DEFAULT_APPLICATION_ID
val system: ActorSystem = ActorSystem("ScriptTest")
implicit val sequencer: ExecutionSequencerFactory =
new AkkaExecutionSequencerPool("ScriptTestPool")(system)
@ -85,10 +84,10 @@ object TestMain extends StrictLogging {
val sandboxResource = SandboxServer.owner(sandboxConfig).acquire()
val sandboxPort =
Await.result(sandboxResource.asFuture.flatMap(_.portF).map(_.value), Duration.Inf)
(ApiParameters("localhost", sandboxPort, None), () => sandboxResource.release())
(ApiParameters("localhost", sandboxPort, None, None), () => sandboxResource.release())
} else {
(
ApiParameters(config.ledgerHost.get, config.ledgerPort.get, None),
ApiParameters(config.ledgerHost.get, config.ledgerPort.get, None, None),
() => Future.successful(()),
)
}
@ -120,7 +119,6 @@ object TestMain extends StrictLogging {
val flow: Future[Boolean] = for {
clients <- Runner.connect(
participantParams,
applicationId,
TlsConfiguration(false, None, None, None),
config.maxInboundMessageSize,
)

View File

@ -97,10 +97,9 @@ da_scala_library(
"//language-support/scala/bindings",
"//language-support/scala/bindings-akka",
"//ledger-api/rs-grpc-bridge",
"//ledger/ledger-api-common",
# "//libs-scala/auth-utils",
"//ledger/ledger-api-auth",
"//ledger-service/jwt",
"//ledger/ledger-api-auth",
"//ledger/ledger-api-common",
"@maven//:com_github_scopt_scopt_2_12",
"@maven//:com_typesafe_akka_akka_stream_2_12",
"@maven//:io_spray_spray_json_2_12",
@ -163,6 +162,7 @@ da_scala_test_suite(
"//libs-scala/auth-utils",
"//libs-scala/ports",
"//libs-scala/resources",
"@maven//:com_auth0_java_jwt",
"@maven//:com_github_scopt_scopt_2_12",
"@maven//:com_google_guava_guava",
"@maven//:com_typesafe_akka_akka_http_core_2_12",

View File

@ -8,15 +8,18 @@ import akka.http.scaladsl.Http.ServerBinding
import akka.stream.Materializer
import io.grpc.Channel
import java.io.File
import java.nio.file.Files
import org.scalatest._
import scala.concurrent.{Await, ExecutionContext, Future}
import scala.concurrent.duration.DurationInt
import scala.util.control.NonFatal
import scalaz.{-\/, \/-}
import scalaz.syntax.traverse._
import spray.json._
import com.daml.bazeltools.BazelRunfiles._
import com.daml.ledger.api.refinements.ApiTypes.ApplicationId
import com.daml.lf.archive.{Dar, DarReader}
import com.daml.lf.archive.Decode
import com.daml.lf.data.Ref._
@ -37,7 +40,7 @@ import com.daml.lf.speedy.SValue
import com.daml.lf.speedy.SValue._
import com.daml.grpc.adapter.{AkkaExecutionSequencerPool, ExecutionSequencerFactory}
import com.daml.http.HttpService
import com.daml.jwt.JwtSigner
import com.daml.jwt.{JwtSigner, HMAC256Verifier}
import com.daml.jwt.domain.DecodedJwt
import com.daml.ledger.api.domain.LedgerId
import com.daml.ledger.api.testing.utils.{
@ -46,7 +49,7 @@ import com.daml.ledger.api.testing.utils.{
SuiteResourceManagementAroundAll,
Resource => TestResource
}
import com.daml.ledger.api.auth.{AuthServiceJWTCodec, AuthServiceJWTPayload}
import com.daml.ledger.api.auth.{AuthServiceJWT, AuthServiceJWTCodec, AuthServiceJWTPayload}
import com.daml.ledger.api.tls.TlsConfiguration
import com.daml.platform.apiserver.services.GrpcClientResource
import com.daml.platform.common.LedgerIdMode
@ -68,8 +71,13 @@ trait JsonApiFixture
override protected def channel: Channel = suiteResource.value._2
override protected def config: SandboxConfig =
super.config
.copy(ledgerIdMode = LedgerIdMode.Static(LedgerId("MyLedger")))
.copy(
ledgerIdMode = LedgerIdMode.Static(LedgerId("MyLedger")),
authService = Some(AuthServiceJWT(HMAC256Verifier(secret).valueOr(err =>
sys.error(s"Failed to create HMAC256 verifierd $err")))),
)
def httpPort: Int = suiteResource.value._3.localAddress.getPort
protected val secret: String = "secret"
// We have to use a different actorsystem for the JSON API since package reloading
// blocks everything so it will timeout as sandbox cannot make progres simultaneously.
@ -77,14 +85,38 @@ trait JsonApiFixture
private val jsonApiMaterializer: Materializer = Materializer(system)
private val jsonApiExecutionSequencerFactory: ExecutionSequencerFactory =
new AkkaExecutionSequencerPool(poolName = "json-api", actorCount = 1)
private val jsonAccessTokenFile = Files.createTempFile("http-jsn", "auth")
override protected def afterAll(): Unit = {
jsonApiExecutionSequencerFactory.close()
materializer.shutdown()
Await.result(jsonApiActorSystem.terminate(), 30.seconds)
try {
Files.delete(jsonAccessTokenFile)
} catch {
case NonFatal(_) =>
}
super.afterAll()
}
protected def getToken(parties: List[String], admin: Boolean): String = {
val payload = AuthServiceJWTPayload(
ledgerId = Some("MyLedger"),
participantId = None,
exp = None,
applicationId = Some("foobar"),
actAs = parties,
admin = admin,
readAs = List()
)
val header = """{"alg": "HS256", "typ": "JWT"}"""
val jwt = DecodedJwt[String](header, AuthServiceJWTCodec.writeToString(payload))
JwtSigner.HMAC256.sign(jwt, secret) match {
case -\/(e) => throw new IllegalStateException(e.toString)
case \/-(a) => a.value
}
}
override protected lazy val suiteResource
: TestResource[(SandboxServer, Channel, ServerBinding)] = {
implicit val ec: ExecutionContext = system.dispatcher
@ -98,6 +130,7 @@ trait JsonApiFixture
httpService <- new ResourceOwner[ServerBinding] {
override def acquire()(implicit ec: ExecutionContext): Resource[ServerBinding] = {
Resource[ServerBinding] {
Files.write(jsonAccessTokenFile, getToken(List(), false).getBytes())
val config = new HttpService.DefaultStartSettings {
override val ledgerHost = "localhost"
override val ledgerPort = server.port.value
@ -107,7 +140,7 @@ trait JsonApiFixture
override val portFile = None
override val tlsConfig = TlsConfiguration(enabled = false, None, None, None)
override val wsConfig = None
override val accessTokenFile = None
override val accessTokenFile = Some(jsonAccessTokenFile)
override val allowNonHttps = true
}
HttpService
@ -148,40 +181,31 @@ final class JsonApiIt
val (dar, envIface) = readDar(darFile)
val (darNoLedger, envIfaceNoLedger) = readDar(darFileNoLedger)
def getToken(parties: List[String], admin: Boolean): String = {
val payload = AuthServiceJWTPayload(
ledgerId = Some("MyLedger"),
participantId = None,
exp = None,
applicationId = Some("foobar"),
actAs = parties,
admin = admin,
readAs = List()
)
val header = """{"alg": "HS256", "typ": "JWT"}"""
val jwt = DecodedJwt[String](header, AuthServiceJWTCodec.writeToString(payload))
JwtSigner.HMAC256.sign(jwt, "secret") match {
case -\/(e) => throw new IllegalStateException(e.toString)
case \/-(a) => a.value
}
}
private def getClients(
parties: List[String] = List(party),
defaultParty: Option[String] = None,
admin: Boolean = false,
applicationId: Option[ApplicationId] = None,
envIface: EnvironmentInterface = envIface) = {
// We give the default participant some nonsense party so the checks for party mismatch fail
// due to the mismatch and not because the token does not allow inferring a party
val defaultParticipant =
ApiParameters("http://localhost", httpPort, Some(getToken(defaultParty.toList, true)))
ApiParameters(
"http://localhost",
httpPort,
Some(getToken(defaultParty.toList, true)),
applicationId)
val partyMap = parties.map(p => (ScriptParty(p), Participant(p))).toMap
val participantMap = parties
.map(
p =>
(
Participant(p),
ApiParameters("http://localhost", httpPort, Some(getToken(List(p), admin)))))
ApiParameters(
"http://localhost",
httpPort,
Some(getToken(List(p), admin)),
applicationId)))
.toMap
val participantParams = Participants(Some(defaultParticipant), participantMap, partyMap)
Runner.jsonClients(participantParams, envIface)
@ -246,6 +270,22 @@ final class JsonApiIt
exception.getMessage === "Tried to submit a command as Bob but token is only valid for Alice")
}
}
"application id mismatch" in {
for {
exception <- recoverToExceptionIf[RuntimeException](
getClients(applicationId = Some(ApplicationId("wrong"))))
} yield
assert(
exception.getMessage === "ApplicationId specified in token Some(foobar) must match Some(wrong)")
}
"application id correct" in {
for {
clients <- getClients(
defaultParty = Some("Alice"),
applicationId = Some(ApplicationId("foobar")))
r <- run(clients, QualifiedName.assertFromString("ScriptTest:jsonCreateAndExercise"))
} yield assert(r == SInt64(42))
}
"query with party mismatch fails" in {
for {
clients <- getClients(defaultParty = Some("Alice"))

View File

@ -148,8 +148,10 @@ object MultiParticipant {
val participantParams = Participants(
None,
Seq(
(Participant("one"), ApiParameters("localhost", config.ledgerPort, None)),
(Participant("two"), ApiParameters("localhost", config.extraParticipantPort, None))
(Participant("one"), ApiParameters("localhost", config.ledgerPort, None, None)),
(
Participant("two"),
ApiParameters("localhost", config.extraParticipantPort, None, None))
).toMap,
Map.empty
)

View File

@ -20,6 +20,7 @@ import com.daml.lf.language.Ast._
import com.daml.lf.speedy.SValue._
import com.daml.daml_lf_dev.DamlLf
import com.daml.ledger.api.auth.{AuthServiceJWTCodec, AuthServiceJWTPayload}
import com.daml.ledger.api.refinements.ApiTypes.ApplicationId
import com.daml.jwt.JwtSigner
import com.daml.jwt.domain.DecodedJwt
@ -416,7 +417,8 @@ object SingleParticipant {
ledgerId = None,
participantId = None,
exp = None,
applicationId = None,
// Set the application id to make sure it is set correctly.
applicationId = Some("daml-script-test"),
actAs = parties,
admin = admin,
readAs = List()
@ -449,10 +451,15 @@ object SingleParticipant {
ApiParameters(
"localhost",
config.ledgerPort,
Some(getToken(List("Alice"), false)))),
Some(getToken(List("Alice"), false)),
Some(ApplicationId("daml-script-test")))),
(
Participant("bob"),
ApiParameters("localhost", config.ledgerPort, Some(getToken(List("Bob"), false))))
ApiParameters(
"localhost",
config.ledgerPort,
Some(getToken(List("Bob"), false)),
Some(ApplicationId("daml-script-test"))))
).toMap,
List(
(ScriptParty("Alice"), Participant("alice")),
@ -460,7 +467,7 @@ object SingleParticipant {
)
} else {
Participants(
Some(ApiParameters("localhost", config.ledgerPort, None)),
Some(ApiParameters("localhost", config.ledgerPort, None, None)),
Map.empty,
Map.empty)
}

View File

@ -91,11 +91,7 @@ class TestRunner(
implicit val ec: ExecutionContext = system.dispatcher
val clientsF =
Runner.connect(
participantParams,
Runner.DEFAULT_APPLICATION_ID,
tlsConfig,
maxInboundMessageSize)
Runner.connect(participantParams, tlsConfig, maxInboundMessageSize)
val testFlow: Future[Unit] = for {
clients <- clientsF

View File

@ -1,8 +1,8 @@
{
"default_participant": {"host": "localhost", "port": 6866, "access_token": "default_jwt"},
"default_participant": {"host": "localhost", "port": 6866, "access_token": "default_jwt", "application_id": "myapp"},
"participants": {
"one": {"host": "localhost", "port": 6865, "access_token": "jwt_for_alice"},
"two": {"host": "localhost", "port": 6865, "access_token": "jwt_for_bob"}
"one": {"host": "localhost", "port": 6865, "access_token": "jwt_for_alice", "application_id": "myapp"},
"two": {"host": "localhost", "port": 6865, "access_token": "jwt_for_bob", "application_id": "myapp"}
},
"party_participants": {"alice": "one", "bob": "two"}
}