mirror of
https://github.com/digital-asset/daml.git
synced 2024-11-10 10:46:11 +03:00
[ED] Enable explicit disclosure in conformance tests [DPP-1206] (#14974)
* Allow enabling explicit disclosure in Sandbox-on-X changelog_begin changelog_end * Fix conformance tests * Disable tests testing yet unsupported features * Addressed Martino's review comments
This commit is contained in:
parent
dd5543eaf2
commit
e0dc3f8679
@ -278,6 +278,10 @@ final class CommandsValidator(
|
||||
}
|
||||
|
||||
object CommandsValidator {
|
||||
def apply(ledgerId: LedgerId, explicitDisclosureUnsafeEnabled: Boolean) = new CommandsValidator(
|
||||
ledgerId = ledgerId,
|
||||
validateDisclosedContracts = new ValidateDisclosedContracts(explicitDisclosureUnsafeEnabled),
|
||||
)
|
||||
|
||||
/** Effective submitters of a command
|
||||
* @param actAs Guaranteed to be non-empty. Will contain exactly one element in most cases.
|
||||
|
@ -26,6 +26,7 @@ class GrpcCommandService(
|
||||
currentUtcTime: () => Instant,
|
||||
maxDeduplicationDuration: () => Option[Duration],
|
||||
generateSubmissionId: SubmissionIdGenerator,
|
||||
explicitDisclosureUnsafeEnabled: Boolean,
|
||||
)(implicit executionContext: ExecutionContext, loggingContext: LoggingContext)
|
||||
extends CommandService
|
||||
with GrpcApiService
|
||||
@ -34,7 +35,7 @@ class GrpcCommandService(
|
||||
protected implicit val logger: ContextualizedLogger = ContextualizedLogger.get(getClass)
|
||||
|
||||
private[this] val validator = new SubmitAndWaitRequestValidator(
|
||||
new CommandsValidator(ledgerId)
|
||||
CommandsValidator(ledgerId, explicitDisclosureUnsafeEnabled)
|
||||
)
|
||||
|
||||
override def submitAndWait(request: SubmitAndWaitRequest): Future[Empty] =
|
||||
|
@ -34,6 +34,7 @@ class GrpcCommandSubmissionService(
|
||||
maxDeduplicationDuration: () => Option[Duration],
|
||||
submissionIdGenerator: SubmissionIdGenerator,
|
||||
metrics: Metrics,
|
||||
explicitDisclosureUnsafeEnabled: Boolean,
|
||||
)(implicit executionContext: ExecutionContext, loggingContext: LoggingContext)
|
||||
extends ApiCommandSubmissionService
|
||||
with ProxyCloseable
|
||||
@ -41,7 +42,7 @@ class GrpcCommandSubmissionService(
|
||||
|
||||
protected implicit val logger: ContextualizedLogger = ContextualizedLogger.get(getClass)
|
||||
private val validator = new SubmitRequestValidator(
|
||||
new CommandsValidator(ledgerId)
|
||||
CommandsValidator(ledgerId, explicitDisclosureUnsafeEnabled)
|
||||
)
|
||||
|
||||
override def submit(request: ApiSubmitRequest): Future[Empty] = {
|
||||
|
@ -12,18 +12,20 @@ import com.daml.ledger.api.v1.command_service.{
|
||||
SubmitAndWaitForTransactionTreeResponse,
|
||||
SubmitAndWaitRequest,
|
||||
}
|
||||
import com.daml.ledger.api.v1.commands.{Command, CreateCommand}
|
||||
import com.daml.ledger.api.v1.commands.{Command, CreateCommand, DisclosedContract}
|
||||
import com.daml.ledger.api.v1.value.{Identifier, Record, RecordField, Value}
|
||||
import com.daml.lf.data.Ref
|
||||
import com.daml.logging.LoggingContext
|
||||
import com.google.protobuf.empty.Empty
|
||||
import org.mockito.{ArgumentMatchersSugar, MockitoSugar}
|
||||
import org.scalatest.Assertion
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AsyncWordSpec
|
||||
|
||||
import java.time.{Duration, Instant}
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import scala.concurrent.Future
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
class GrpcCommandServiceSpec
|
||||
extends AsyncWordSpec
|
||||
@ -59,6 +61,7 @@ class GrpcCommandServiceSpec
|
||||
Ref.SubmissionId.assertFromString(
|
||||
s"$submissionIdPrefix${submissionCounter.incrementAndGet()}"
|
||||
),
|
||||
explicitDisclosureUnsafeEnabled = false,
|
||||
)
|
||||
|
||||
for {
|
||||
@ -85,6 +88,51 @@ class GrpcCommandServiceSpec
|
||||
succeed
|
||||
}
|
||||
}
|
||||
"reject submission on explicit disclosure disabled with provided disclosed contracts" in {
|
||||
val mockCommandService = mock[CommandService with AutoCloseable]
|
||||
|
||||
val grpcCommandService = new GrpcCommandService(
|
||||
mockCommandService,
|
||||
ledgerId = LedgerId(ledgerId),
|
||||
currentLedgerTime = () => Instant.EPOCH,
|
||||
currentUtcTime = () => Instant.EPOCH,
|
||||
maxDeduplicationDuration = () => Some(Duration.ZERO),
|
||||
generateSubmissionId = () => Ref.SubmissionId.assertFromString(s"submissionId"),
|
||||
explicitDisclosureUnsafeEnabled = false,
|
||||
)
|
||||
|
||||
val submissionWithDisclosedContracts = aSubmitAndWaitRequestWithNoSubmissionId.update(
|
||||
_.commands.disclosedContracts.set(Seq(DisclosedContract()))
|
||||
)
|
||||
|
||||
def expectFailedOnProvidedDisclosedContracts(f: Future[_]): Future[Assertion] = f.transform {
|
||||
case Failure(exception)
|
||||
if exception.getMessage.contains(
|
||||
"feature in development: disclosed_contracts should not be set"
|
||||
) =>
|
||||
Success(succeed)
|
||||
case other => fail(s"Unexpected result: $other")
|
||||
}
|
||||
|
||||
for {
|
||||
_ <- expectFailedOnProvidedDisclosedContracts(
|
||||
grpcCommandService.submitAndWait(submissionWithDisclosedContracts)
|
||||
)
|
||||
_ <- expectFailedOnProvidedDisclosedContracts(
|
||||
grpcCommandService.submitAndWaitForTransaction(submissionWithDisclosedContracts)
|
||||
)
|
||||
_ <- expectFailedOnProvidedDisclosedContracts(
|
||||
grpcCommandService.submitAndWaitForTransactionId(submissionWithDisclosedContracts)
|
||||
)
|
||||
_ <- expectFailedOnProvidedDisclosedContracts(
|
||||
grpcCommandService.submitAndWaitForTransactionTree(submissionWithDisclosedContracts)
|
||||
)
|
||||
} yield {
|
||||
verifyZeroInteractions(mockCommandService)
|
||||
succeed
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import com.codahale.metrics.MetricRegistry
|
||||
import com.daml.ledger.api.domain.LedgerId
|
||||
import com.daml.ledger.api.messages.command.submission.SubmitRequest
|
||||
import com.daml.ledger.api.testing.utils.MockMessages._
|
||||
import com.daml.ledger.api.v1.commands.{Command, CreateCommand}
|
||||
import com.daml.ledger.api.v1.commands.{Command, CreateCommand, DisclosedContract}
|
||||
import com.daml.ledger.api.v1.value.{Identifier, Record, RecordField, Value}
|
||||
import com.daml.lf.data.Ref
|
||||
import com.daml.logging.LoggingContext
|
||||
@ -21,6 +21,7 @@ import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AsyncWordSpec
|
||||
|
||||
import scala.concurrent.Future
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
class GrpcCommandSubmissionServiceSpec
|
||||
extends AsyncWordSpec
|
||||
@ -87,6 +88,28 @@ class GrpcCommandSubmissionServiceSpec
|
||||
requestCaptor.value.commands.submissionId shouldBe Some(generatedSubmissionId)
|
||||
}
|
||||
}
|
||||
|
||||
"reject submission on explicit disclosure disabled with provided disclosed contracts" in {
|
||||
val mockCommandSubmissionService = mock[CommandSubmissionService with AutoCloseable]
|
||||
|
||||
val submissionWithDisclosedContracts =
|
||||
aSubmitRequest.update(_.commands.disclosedContracts.set(Seq(DisclosedContract())))
|
||||
|
||||
grpcCommandSubmissionService(mockCommandSubmissionService)
|
||||
.submit(submissionWithDisclosedContracts)
|
||||
.map { _ =>
|
||||
verifyZeroInteractions(mockCommandSubmissionService)
|
||||
succeed
|
||||
}
|
||||
.transform {
|
||||
case Failure(exception)
|
||||
if exception.getMessage.contains(
|
||||
"feature in development: disclosed_contracts should not be set"
|
||||
) =>
|
||||
Success(succeed)
|
||||
case other => fail(s"Unexpected result: $other")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def grpcCommandSubmissionService(
|
||||
@ -100,6 +123,7 @@ class GrpcCommandSubmissionServiceSpec
|
||||
maxDeduplicationDuration = () => Some(Duration.ZERO),
|
||||
submissionIdGenerator = () => Ref.SubmissionId.assertFromString(generatedSubmissionId),
|
||||
metrics = new Metrics(new MetricRegistry),
|
||||
explicitDisclosureUnsafeEnabled = false,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
package com.daml.ledger.api.testtool.suites.v1_dev
|
||||
|
||||
import com.daml.error.definitions.LedgerApiErrors
|
||||
import com.daml.ledger.api.refinements.ApiTypes.Party
|
||||
import com.daml.ledger.api.testtool.infrastructure.Allocation._
|
||||
import com.daml.ledger.api.testtool.infrastructure.Assertions._
|
||||
import com.daml.ledger.api.testtool.infrastructure.LedgerTestSuite
|
||||
@ -100,7 +101,7 @@ final class ExplicitDisclosureIT extends LedgerTestSuite {
|
||||
// Create contract with `owner` as only stakeholder
|
||||
_ <- ledger.create(owner, WithKey(owner))
|
||||
withKeyTxIds <- ledger.flatTransactionsByTemplateId(WithKey.id, owner)
|
||||
withKeyCreate = createdEvents(withKeyTxIds(1)).head
|
||||
withKeyCreate = createdEvents(withKeyTxIds(0)).head
|
||||
withKeyDisclosedContract = createEventToDisclosedContract(withKeyCreate)
|
||||
exerciseByKeyError <- ledger
|
||||
.submitAndWait(
|
||||
@ -224,8 +225,8 @@ final class ExplicitDisclosureIT extends LedgerTestSuite {
|
||||
for {
|
||||
contractId <- ledger1.create(party1, Dummy(party1))
|
||||
|
||||
transactions <- ledger1.flatTransactionsByTemplateId(WithKey.id, party1)
|
||||
create = createdEvents(transactions(1)).head
|
||||
transactions <- ledger1.flatTransactionsByTemplateId(Dummy.id, party1)
|
||||
create = createdEvents(transactions(0)).head
|
||||
disclosedContract = createEventToDisclosedContract(create)
|
||||
|
||||
// Submit concurrently two consuming exercise choices (with and without disclosed contract)
|
||||
@ -266,13 +267,14 @@ final class ExplicitDisclosureIT extends LedgerTestSuite {
|
||||
for {
|
||||
testContext <- initializeTest(ledger, owner, delegate)
|
||||
|
||||
// Exercise a choice using invalid explicit disclosure (bad contract key)
|
||||
errorBadKey <- testContext
|
||||
.exerciseFetchDelegated(
|
||||
testContext.disclosedContract
|
||||
.update(_.metadata.contractKeyHash := ByteString.copyFromUtf8("badKeyMeta"))
|
||||
)
|
||||
.mustFail("using a mismatching contract key hash in metadata")
|
||||
// // TODO ED: Enable once the check is implemented in command interpretation
|
||||
// // Exercise a choice using invalid explicit disclosure (bad contract key)
|
||||
// errorBadKey <- testContext
|
||||
// .exerciseFetchDelegated(
|
||||
// testContext.disclosedContract
|
||||
// .update(_.metadata.contractKeyHash := ByteString.copyFromUtf8("BadKeyBadKeyBadKeyBadKeyBadKey00"))
|
||||
// )
|
||||
// .mustFail("using a mismatching contract key hash in metadata")
|
||||
|
||||
// Exercise a choice using invalid explicit disclosure (bad ledger time)
|
||||
errorBadLet <- testContext
|
||||
@ -290,12 +292,13 @@ final class ExplicitDisclosureIT extends LedgerTestSuite {
|
||||
)
|
||||
.mustFail("using an invalid disclosed contract payload")
|
||||
} yield {
|
||||
assertGrpcError(
|
||||
errorBadKey,
|
||||
LedgerApiErrors.ConsistencyErrors.DisclosedContractInvalid,
|
||||
None,
|
||||
checkDefiniteAnswerMetadata = true,
|
||||
)
|
||||
// // TODO ED: Enable once the check is implemented in command interpretation
|
||||
// assertGrpcError(
|
||||
// errorBadKey,
|
||||
// LedgerApiErrors.ConsistencyErrors.DisclosedContractInvalid,
|
||||
// None,
|
||||
// checkDefiniteAnswerMetadata = true,
|
||||
// )
|
||||
assertGrpcError(
|
||||
errorBadLet,
|
||||
LedgerApiErrors.ConsistencyErrors.DisclosedContractInvalid,
|
||||
@ -370,15 +373,15 @@ final class ExplicitDisclosureIT extends LedgerTestSuite {
|
||||
)
|
||||
.mustFail("using a disclosed contract with missing createdAt in contract metadata")
|
||||
|
||||
// // TODO ED: Assert missing contract key hash when ledger side metadata validation is implemented
|
||||
// // Exercise a choice using an invalid disclosed contract (missing key hash in contract metadata for a contract that has a contract key associated)
|
||||
// errorMissingKeyHash <- testContext
|
||||
// .exerciseFetchDelegated(
|
||||
// testContext.disclosedContract.update(_.metadata.contractKeyHash.set(ByteString.EMPTY))
|
||||
// )
|
||||
// .mustFail(
|
||||
// "using a disclosed contract with missing key hash in contract metadata for a contract that has a contract key associated"
|
||||
// )
|
||||
// // TODO ED: Assert missing contract key hash when ledger side metadata validation is implemented
|
||||
// // Exercise a choice using an invalid disclosed contract (missing key hash in contract metadata for a contract that has a contract key associated)
|
||||
// errorMissingKeyHash <- testContext
|
||||
// .exerciseFetchDelegated(
|
||||
// testContext.disclosedContract.update(_.metadata.contractKeyHash.set(ByteString.EMPTY))
|
||||
// )
|
||||
// .mustFail(
|
||||
// "using a disclosed contract with missing key hash in contract metadata for a contract that has a contract key associated"
|
||||
// )
|
||||
} yield {
|
||||
assertGrpcError(
|
||||
errorMalformedPayload,
|
||||
@ -430,25 +433,40 @@ final class ExplicitDisclosureIT extends LedgerTestSuite {
|
||||
for {
|
||||
testContext <- initializeTest(ledger, owner, delegate)
|
||||
|
||||
_ <- ledger.create(owner, Dummy(owner))
|
||||
dummyTxs <- ledger.flatTransactionsByTemplateId(Dummy.id, owner)
|
||||
dummyCreate = createdEvents(dummyTxs(0)).head
|
||||
dummyDisclosedContract = createEventToDisclosedContract(dummyCreate)
|
||||
|
||||
// Exercise a choice using invalid explicit disclosure (bad contract key)
|
||||
_ <- testContext
|
||||
.exerciseFetchDelegated(
|
||||
testContext.disclosedContract
|
||||
.update(_.metadata.contractKeyHash := ByteString.copyFromUtf8("badKeyMeta"))
|
||||
testContext.disclosedContract,
|
||||
// Provide a superfluous disclosed contract with mismatching key hash
|
||||
dummyDisclosedContract
|
||||
.update(
|
||||
_.metadata.contractKeyHash := ByteString.copyFromUtf8(
|
||||
"BadKeyBadKeyBadKeyBadKeyBadKey00"
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
// Exercise a choice using invalid explicit disclosure (bad ledger time)
|
||||
_ <- testContext
|
||||
.exerciseFetchDelegated(
|
||||
testContext.disclosedContract
|
||||
.update(_.metadata.createdAt := com.google.protobuf.timestamp.Timestamp.of(1, 0))
|
||||
testContext.disclosedContract,
|
||||
// Provide a superfluous disclosed contract with mismatching createdAt
|
||||
dummyDisclosedContract
|
||||
.update(_.metadata.createdAt := com.google.protobuf.timestamp.Timestamp.of(1, 0)),
|
||||
)
|
||||
|
||||
// Exercise a choice using invalid explicit disclosure (bad payload)
|
||||
_ <- testContext
|
||||
.exerciseFetchDelegated(
|
||||
testContext.disclosedContract
|
||||
.update(_.arguments := Delegated(delegate, testContext.contractKey).arguments)
|
||||
testContext.disclosedContract,
|
||||
// Provide a superfluous disclosed contract with mismatching contract arguments
|
||||
dummyDisclosedContract
|
||||
.update(_.arguments := Dummy(delegate).arguments),
|
||||
)
|
||||
} yield ()
|
||||
})
|
||||
@ -554,8 +572,7 @@ final class ExplicitDisclosureIT extends LedgerTestSuite {
|
||||
"EDFeatureDisabled",
|
||||
"Submission fails when disclosed contracts provided on feature disabled",
|
||||
allocate(Parties(2)),
|
||||
// TODO ED: Toggle after feature flag implementation
|
||||
// enabled = feature => !feature.explicitDisclosure,
|
||||
enabled = feature => !feature.explicitDisclosure,
|
||||
)(implicit ec => { case Participants(Participant(ledger, owner, delegate)) =>
|
||||
for {
|
||||
testContext <- initializeTest(ledger, owner, delegate)
|
||||
@ -593,7 +610,7 @@ final class ExplicitDisclosureIT extends LedgerTestSuite {
|
||||
verbose = !normalizedDisclosedContract,
|
||||
)
|
||||
)
|
||||
createdEvent = createdEvents(txs(1)).head
|
||||
createdEvent = createdEvents(txs(0)).head
|
||||
disclosedContract = createEventToDisclosedContract(createdEvent)
|
||||
|
||||
_ <- ledger.submitAndWait(
|
||||
@ -749,9 +766,18 @@ object ExplicitDisclosureIT {
|
||||
Command.Command.ExerciseByKey(
|
||||
ExerciseByKeyCommand(
|
||||
Some(WithKey.id.unwrap),
|
||||
Option(Value(Value.Sum.Party(owner.unwrap))),
|
||||
Option(Value(Value.Sum.Party(Party.unwrap(owner)))),
|
||||
"WithKey_NoOp",
|
||||
Option(Value(Value.Sum.Party(party.unwrap))),
|
||||
Option(
|
||||
Value(
|
||||
Value.Sum.Record(
|
||||
Record(
|
||||
None,
|
||||
List(RecordField("", Some(Value(Value.Sum.Party(Party.unwrap(party)))))),
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
),
|
||||
|
@ -43,6 +43,11 @@ class LedgerApiServer(
|
||||
timeServiceBackendO: Option[TimeServiceBackend],
|
||||
servicesExecutionContext: ExecutionContextExecutorService,
|
||||
metrics: Metrics,
|
||||
// TODO ED: Remove flag once explicit disclosure is deemed stable and all
|
||||
// backing ledgers implement proper validation against malicious clients.
|
||||
// Currently, we provide this flag outside the HOCON configuration objects
|
||||
// in order to ensure that participants cannot be configured to accept explicitly disclosed contracts.
|
||||
explicitDisclosureUnsafeEnabled: Boolean = false,
|
||||
)(implicit actorSystem: ActorSystem, materializer: Materializer) {
|
||||
|
||||
def owner: ResourceOwner[ApiService] = {
|
||||
@ -109,6 +114,7 @@ class LedgerApiServer(
|
||||
ledgerId,
|
||||
participantConfig.apiServer,
|
||||
participantId,
|
||||
explicitDisclosureUnsafeEnabled,
|
||||
)
|
||||
} yield apiService
|
||||
}
|
||||
@ -127,6 +133,7 @@ class LedgerApiServer(
|
||||
ledgerId: LedgerId,
|
||||
apiServerConfig: ApiServerConfig,
|
||||
participantId: Ref.ParticipantId,
|
||||
explicitDisclosureUnsafeEnabled: Boolean,
|
||||
)(implicit
|
||||
actorSystem: ActorSystem,
|
||||
loggingContext: LoggingContext,
|
||||
@ -155,6 +162,7 @@ class LedgerApiServer(
|
||||
participantId = participantId,
|
||||
authService = authService,
|
||||
jwtTimestampLeeway = participantConfig.jwtTimestampLeeway,
|
||||
explicitDisclosureUnsafeEnabled = explicitDisclosureUnsafeEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,7 @@ object ApiServiceOwner {
|
||||
authService: AuthService,
|
||||
meteringReportKey: MeteringReportKey = CommunityKey,
|
||||
jwtTimestampLeeway: Option[JwtTimestampLeeway],
|
||||
explicitDisclosureUnsafeEnabled: Boolean = false,
|
||||
)(implicit
|
||||
actorSystem: ActorSystem,
|
||||
materializer: Materializer,
|
||||
@ -114,6 +115,7 @@ object ApiServiceOwner {
|
||||
userManagementConfig = config.userManagement,
|
||||
apiStreamShutdownTimeout = config.apiStreamShutdownTimeout,
|
||||
meteringReportKey = meteringReportKey,
|
||||
explicitDisclosureUnsafeEnabled = explicitDisclosureUnsafeEnabled,
|
||||
)(materializer, executionSequencerFactory, loggingContext)
|
||||
.map(_.withServices(otherServices))
|
||||
apiService <- new LedgerApiService(
|
||||
|
@ -86,6 +86,7 @@ private[daml] object ApiServices {
|
||||
userManagementConfig: UserManagementConfig,
|
||||
apiStreamShutdownTimeout: scala.concurrent.duration.Duration,
|
||||
meteringReportKey: MeteringReportKey,
|
||||
explicitDisclosureUnsafeEnabled: Boolean,
|
||||
)(implicit
|
||||
materializer: Materializer,
|
||||
esf: ExecutionSequencerFactory,
|
||||
@ -259,6 +260,7 @@ private[daml] object ApiServices {
|
||||
commandExecutor,
|
||||
checkOverloaded,
|
||||
metrics,
|
||||
explicitDisclosureUnsafeEnabled = explicitDisclosureUnsafeEnabled,
|
||||
)
|
||||
|
||||
// Note: the command service uses the command submission, command completion, and transaction
|
||||
@ -282,6 +284,7 @@ private[daml] object ApiServices {
|
||||
timeProvider = timeProvider,
|
||||
ledgerConfigurationSubscription = ledgerConfigurationSubscription,
|
||||
metrics = metrics,
|
||||
explicitDisclosureUnsafeEnabled = explicitDisclosureUnsafeEnabled,
|
||||
)
|
||||
|
||||
val apiPartyManagementService = ApiPartyManagementService.createApiService(
|
||||
|
@ -8,6 +8,7 @@ import com.daml.ledger.api.v1.experimental_features.{
|
||||
CommandDeduplicationFeatures,
|
||||
ExperimentalCommitterEventLog,
|
||||
ExperimentalContractIds,
|
||||
ExperimentalExplicitDisclosure,
|
||||
}
|
||||
|
||||
case class LedgerFeatures(
|
||||
@ -17,4 +18,6 @@ case class LedgerFeatures(
|
||||
contractIdFeatures: ExperimentalContractIds = ExperimentalContractIds.defaultInstance,
|
||||
committerEventLog: ExperimentalCommitterEventLog =
|
||||
ExperimentalCommitterEventLog.of(eventLogType = CENTRALIZED),
|
||||
explicitDisclosure: ExperimentalExplicitDisclosure =
|
||||
ExperimentalExplicitDisclosure.of(supported = false),
|
||||
)
|
||||
|
@ -208,6 +208,7 @@ private[apiserver] object ApiCommandService {
|
||||
timeProvider: TimeProvider,
|
||||
ledgerConfigurationSubscription: LedgerConfigurationSubscription,
|
||||
metrics: Metrics,
|
||||
explicitDisclosureUnsafeEnabled: Boolean,
|
||||
)(implicit
|
||||
materializer: Materializer,
|
||||
executionContext: ExecutionContext,
|
||||
@ -232,6 +233,7 @@ private[apiserver] object ApiCommandService {
|
||||
maxDeduplicationDuration = () =>
|
||||
ledgerConfigurationSubscription.latestConfiguration().map(_.maxDeduplicationDuration),
|
||||
generateSubmissionId = SubmissionIdGenerator.Random,
|
||||
explicitDisclosureUnsafeEnabled = explicitDisclosureUnsafeEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,7 @@ private[apiserver] object ApiSubmissionService {
|
||||
commandExecutor: CommandExecutor,
|
||||
checkOverloaded: TelemetryContext => Option[state.SubmissionResult],
|
||||
metrics: Metrics,
|
||||
explicitDisclosureUnsafeEnabled: Boolean,
|
||||
)(implicit
|
||||
executionContext: ExecutionContext,
|
||||
loggingContext: LoggingContext,
|
||||
@ -65,6 +66,7 @@ private[apiserver] object ApiSubmissionService {
|
||||
ledgerConfigurationSubscription.latestConfiguration().map(_.maxDeduplicationDuration),
|
||||
submissionIdGenerator = SubmissionIdGenerator.Random,
|
||||
metrics = metrics,
|
||||
explicitDisclosureUnsafeEnabled = explicitDisclosureUnsafeEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ private[apiserver] final class ApiVersionService private (
|
||||
optionalLedgerId = Some(ExperimentalOptionalLedgerId()),
|
||||
contractIds = Some(ledgerFeatures.contractIdFeatures),
|
||||
committerEventLog = Some(ledgerFeatures.committerEventLog),
|
||||
explicitDisclosure = None, // TODO[ED]: Wire-up with participant configuration flag
|
||||
explicitDisclosure = Some(ledgerFeatures.explicitDisclosure),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
@ -575,6 +575,24 @@ server_conformance_test(
|
||||
],
|
||||
)
|
||||
|
||||
SERVERS_EXPLICIT_DISCLOSURE = {
|
||||
"h2database": {
|
||||
"binary": ":app",
|
||||
"server_args": ["explicit-disclosure-unsafe-enabled run"],
|
||||
},
|
||||
"postgresql": {
|
||||
"binary": ":conformance-test-postgres-bin",
|
||||
"server_args": ["explicit-disclosure-unsafe-enabled run -c $(rootpath :postgres.conf)"],
|
||||
"extra_data": [":postgres.conf"],
|
||||
},
|
||||
"oracle": {
|
||||
"binary": ":conformance-test-oracle-bin",
|
||||
"tags": oracle_tags,
|
||||
"server_args": ["explicit-disclosure-unsafe-enabled run -c $(rootpath :oracle.conf)"],
|
||||
"extra_data": [":oracle.conf"],
|
||||
},
|
||||
}
|
||||
|
||||
server_conformance_test(
|
||||
name = "conformance-test-explicit-disclosure",
|
||||
hocon = True,
|
||||
@ -584,7 +602,32 @@ server_conformance_test(
|
||||
lf_versions = [
|
||||
"1.dev",
|
||||
],
|
||||
servers = SERVERS,
|
||||
servers = SERVERS_EXPLICIT_DISCLOSURE,
|
||||
test_tool_args = [
|
||||
"--verbose",
|
||||
"--include=ExplicitDisclosureIT",
|
||||
# TODO ED: Enable the following test once https://github.com/digital-asset/daml/issues/14200 is solved
|
||||
"--exclude=ExplicitDisclosureIT:EDDuplicates",
|
||||
# TODO ED: Enable the following tests once https://github.com/digital-asset/daml/issues/14199 is solved
|
||||
"--exclude=ExplicitDisclosureIT:EDExerciseByKeyDisclosedContract",
|
||||
"--exclude=ExplicitDisclosureIT:EDLocalKeyVisibility",
|
||||
"--exclude=ExplicitDisclosureIT:EDNonNormalizedDisclosedContract",
|
||||
"--exclude=ExplicitDisclosureIT:EDNormalizedDisclosedContract",
|
||||
],
|
||||
)
|
||||
|
||||
# Suite asserting that tests targeting disabled explicit disclosure are successful
|
||||
# (i.e. test asserting that submissions using disclosed contracts are rejected)
|
||||
# TODO ED: Remove once feature deemed stable
|
||||
conformance_test(
|
||||
name = "conformance-test-explicit-disclosure-disabled-lf-dev-h2",
|
||||
hocon = True,
|
||||
lf_versions = [
|
||||
"1.dev",
|
||||
],
|
||||
ports = [6865],
|
||||
server = ":app",
|
||||
server_args = ["run"],
|
||||
test_tool_args = [
|
||||
"--verbose",
|
||||
"--include=ExplicitDisclosureIT",
|
||||
|
@ -9,6 +9,13 @@ import com.daml.logging.ContextualizedLogger
|
||||
import com.daml.resources.ProgramResource
|
||||
|
||||
object CliSandboxOnXRunner {
|
||||
// TODO ED: Remove flag once explicit disclosure is deemed stable and all
|
||||
// backing ledgers implement proper validation against malicious clients
|
||||
//
|
||||
// NOTE: The flag is explicitly extracted out of the provided program arguments
|
||||
// and not passed via the HOCON config in order to prevent accidental
|
||||
// enablement, which could render participants vulnerable to malicious clients.
|
||||
private val ExplicitDisclosureEnabledArg = "explicit-disclosure-unsafe-enabled"
|
||||
private val logger = ContextualizedLogger.get(getClass)
|
||||
val RunnerName = "sandbox-on-x"
|
||||
|
||||
@ -19,14 +26,23 @@ object CliSandboxOnXRunner {
|
||||
args: collection.Seq[String],
|
||||
manipulateConfig: CliConfig[BridgeConfig] => CliConfig[BridgeConfig] = identity,
|
||||
): Unit = {
|
||||
val explicitDisclosureEnabled = args.contains(ExplicitDisclosureEnabledArg)
|
||||
val config = CliConfig
|
||||
.parse(RunnerName, BridgeConfig.Parser, BridgeConfig.Default, args)
|
||||
.parse(
|
||||
RunnerName,
|
||||
BridgeConfig.Parser,
|
||||
BridgeConfig.Default,
|
||||
args.filterNot(_ == ExplicitDisclosureEnabledArg),
|
||||
)
|
||||
.map(manipulateConfig)
|
||||
.getOrElse(sys.exit(1))
|
||||
runProgram(config)
|
||||
runProgram(config, explicitDisclosureEnabled)
|
||||
}
|
||||
|
||||
private def runProgram(config: CliConfig[BridgeConfig]): Unit =
|
||||
private def runProgram(
|
||||
config: CliConfig[BridgeConfig],
|
||||
explicitDisclosureUnsafeEnabled: Boolean,
|
||||
): Unit =
|
||||
config.mode match {
|
||||
case Mode.Run =>
|
||||
SandboxOnXConfig
|
||||
@ -34,7 +50,9 @@ object CliSandboxOnXRunner {
|
||||
.fold(
|
||||
System.err.println,
|
||||
{ sandboxOnXConfig =>
|
||||
program(sox(new BridgeConfigAdaptor, sandboxOnXConfig))
|
||||
program(
|
||||
sox(new BridgeConfigAdaptor, sandboxOnXConfig, explicitDisclosureUnsafeEnabled)
|
||||
)
|
||||
},
|
||||
)
|
||||
case Mode.DumpIndexMetadata(jdbcUrls) =>
|
||||
@ -46,12 +64,13 @@ object CliSandboxOnXRunner {
|
||||
case Mode.RunLegacyCliConfig =>
|
||||
val configAdaptor: BridgeConfigAdaptor = new BridgeConfigAdaptor
|
||||
val sandboxOnXConfig: SandboxOnXConfig = SandboxOnXConfig.fromLegacy(configAdaptor, config)
|
||||
program(sox(configAdaptor, sandboxOnXConfig))
|
||||
program(sox(configAdaptor, sandboxOnXConfig, explicitDisclosureUnsafeEnabled))
|
||||
}
|
||||
|
||||
private def sox(
|
||||
configAdaptor: BridgeConfigAdaptor,
|
||||
sandboxOnXConfig: SandboxOnXConfig,
|
||||
explicitDisclosureUnsafeEnabled: Boolean,
|
||||
): ResourceOwner[Unit] = {
|
||||
Banner.show(Console.out)
|
||||
logger.withoutContext.info(
|
||||
@ -62,6 +81,7 @@ object CliSandboxOnXRunner {
|
||||
configAdaptor,
|
||||
sandboxOnXConfig.ledger,
|
||||
sandboxOnXConfig.bridge,
|
||||
explicitDisclosureUnsafeEnabled,
|
||||
)
|
||||
.map(_ => ())
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import com.daml.ledger.api.v1.experimental_features.{
|
||||
CommandDeduplicationPeriodSupport,
|
||||
CommandDeduplicationType,
|
||||
ExperimentalContractIds,
|
||||
ExperimentalExplicitDisclosure,
|
||||
}
|
||||
import com.daml.ledger.offset.Offset
|
||||
import com.daml.ledger.participant.state.index.v2.IndexService
|
||||
@ -56,16 +57,20 @@ object SandboxOnXRunner {
|
||||
configAdaptor: BridgeConfigAdaptor,
|
||||
config: Config,
|
||||
bridgeConfig: BridgeConfig,
|
||||
explicitDisclosureUnsafeEnabled: Boolean = false,
|
||||
): ResourceOwner[Port] =
|
||||
new ResourceOwner[Port] {
|
||||
override def acquire()(implicit context: ResourceContext): Resource[Port] =
|
||||
SandboxOnXRunner.run(bridgeConfig, config, configAdaptor).acquire()
|
||||
SandboxOnXRunner
|
||||
.run(bridgeConfig, config, configAdaptor, explicitDisclosureUnsafeEnabled)
|
||||
.acquire()
|
||||
}
|
||||
|
||||
def run(
|
||||
bridgeConfig: BridgeConfig,
|
||||
config: Config,
|
||||
configAdaptor: BridgeConfigAdaptor,
|
||||
explicitDisclosureUnsafeEnabled: Boolean,
|
||||
): ResourceOwner[Port] = newLoggingContext { implicit loggingContext =>
|
||||
implicit val actorSystem: ActorSystem = ActorSystem(RunnerName)
|
||||
implicit val materializer: Materializer = Materializer(actorSystem)
|
||||
@ -111,6 +116,7 @@ object SandboxOnXRunner {
|
||||
contractIdFeatures = ExperimentalContractIds.of(
|
||||
v1 = ExperimentalContractIds.ContractIdV1Support.NON_SUFFIXED
|
||||
),
|
||||
explicitDisclosure = ExperimentalExplicitDisclosure.of(explicitDisclosureUnsafeEnabled),
|
||||
),
|
||||
authService = configAdaptor.authService(participantConfig),
|
||||
buildWriteService = buildWriteServiceLambda,
|
||||
@ -127,6 +133,7 @@ object SandboxOnXRunner {
|
||||
timeServiceBackendO = timeServiceBackendO,
|
||||
servicesExecutionContext = servicesExecutionContext,
|
||||
metrics = metrics,
|
||||
explicitDisclosureUnsafeEnabled = explicitDisclosureUnsafeEnabled,
|
||||
)(actorSystem, materializer).owner
|
||||
} yield {
|
||||
logInitializationHeader(
|
||||
|
Loading…
Reference in New Issue
Block a user