-
Notifications
You must be signed in to change notification settings - Fork 205
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
DPP-432 Add exception tests to the JdbcLedgerDao suite (#10040)
* Add exception tests changelog_begin changelog_end * Add another test This one tests a transaction that can only be produced by a privacy-aware ledger. * Address review comments
- Loading branch information
1 parent
3d79cbf
commit 01e329f
Showing
8 changed files
with
216 additions
and
9 deletions.
There are no files selected for viewing
165 changes: 165 additions & 0 deletions
165
...nt-integration-api/src/test/lib/scala/platform/store/dao/JdbcLedgerDaoExceptionSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
// Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.daml.platform.store.dao | ||
|
||
import com.daml.lf.transaction.TransactionVersion | ||
import com.daml.lf.transaction.test.TransactionBuilder | ||
import com.daml.lf.value.Value.{ContractId, ContractInst} | ||
import org.scalatest.flatspec.AsyncFlatSpec | ||
import org.scalatest.matchers.should.Matchers | ||
import org.scalatest.{Inside, LoneElement, OptionValues} | ||
|
||
/** There are two important parts to cover with Daml exceptions: | ||
* - Create and exercise nodes under rollback nodes should not be indexed | ||
* - Lookup and fetch nodes under rollback nodes may lead to divulgence | ||
*/ | ||
private[dao] trait JdbcLedgerDaoExceptionSpec extends LoneElement with Inside with OptionValues { | ||
this: AsyncFlatSpec with Matchers with JdbcLedgerDaoSuite => | ||
|
||
private def contractsReader = ledgerDao.contractsReader | ||
|
||
behavior of "JdbcLedgerDao (exceptions)" | ||
|
||
it should "not find contracts created under rollback nodes" in { | ||
val builder = TransactionBuilder(TransactionVersion.VDev) | ||
val rollback = builder.add(builder.rollback()) | ||
val cid1 = builder.newCid | ||
val cid2 = builder.newCid | ||
builder.add( | ||
createNode(absCid = cid1, signatories = Set(alice), stakeholders = Set(alice)), | ||
rollback, | ||
) | ||
builder.add(createNode(absCid = cid2, signatories = Set(alice), stakeholders = Set(alice))) | ||
val offsetAndEntry = fromTransaction(builder.buildCommitted()) | ||
|
||
for { | ||
_ <- store(offsetAndEntry) | ||
result1 <- contractsReader.lookupActiveContractAndLoadArgument(Set(alice), cid1) | ||
result2 <- contractsReader.lookupActiveContractAndLoadArgument(Set(alice), cid2) | ||
} yield { | ||
result1 shouldBe None | ||
result2.value shouldBe a[ContractInst[_]] | ||
} | ||
} | ||
|
||
it should "divulge contracts fetched under rollback nodes" in { | ||
val stakeholders = Set(alice) | ||
val divulgees = Set(bob) | ||
|
||
// A transaction that fetches a contract under a rollback node | ||
def rolledBackFetch(createCid: ContractId, fetcherCid: ContractId) = { | ||
val builder = TransactionBuilder(TransactionVersion.VDev) | ||
val exercise1 = exerciseNode(fetcherCid).copy( | ||
consuming = false, | ||
actingParties = stakeholders, | ||
signatories = divulgees, | ||
stakeholders = stakeholders.union(divulgees), | ||
) | ||
val rollback = builder.rollback() | ||
val fetch1 = fetchNode(createCid).copy( | ||
actingParties = stakeholders, | ||
signatories = stakeholders, | ||
stakeholders = stakeholders, | ||
) | ||
|
||
val exercise1Nid = builder.add(exercise1) | ||
val rollbackNid = builder.add(rollback, exercise1Nid) | ||
builder.add(fetch1, rollbackNid) | ||
fromTransaction(builder.buildCommitted()).copy() | ||
} | ||
|
||
for { | ||
// Create contract to be divulged | ||
(_, tx1) <- createAndStoreContract( | ||
submittingParties = stakeholders, | ||
signatories = stakeholders, | ||
stakeholders = stakeholders, | ||
key = None, | ||
) | ||
create = nonTransient(tx1).loneElement | ||
createCid = ContractId.assertFromString(create.coid) | ||
|
||
// Create "Fetcher" contract | ||
(_, tx2) <- createAndStoreContract( | ||
submittingParties = divulgees, | ||
signatories = divulgees, | ||
stakeholders = stakeholders.union(divulgees), | ||
key = None, | ||
) | ||
fetcher = nonTransient(tx2).loneElement | ||
fetcherCid = ContractId.assertFromString(fetcher.coid) | ||
|
||
// Exercise a choice on the "Fetcher" contract that divulges the first contract | ||
_ <- store( | ||
divulgedContracts = Map((create, someVersionedContractInstance) -> divulgees), | ||
blindingInfo = None, | ||
offsetAndTx = rolledBackFetch(createCid, fetcherCid), | ||
) | ||
resultAlice <- contractsReader.lookupActiveContractAndLoadArgument(Set(alice), createCid) | ||
resultBob <- contractsReader.lookupActiveContractAndLoadArgument(Set(bob), createCid) | ||
resultCharlie <- contractsReader.lookupActiveContractAndLoadArgument(Set(charlie), createCid) | ||
} yield { | ||
withClue("Alice is stakeholder") { | ||
resultAlice.value shouldBe a[ContractInst[_]] | ||
} | ||
withClue("Contract was divulged to Bob under a rollback node") { | ||
resultBob.value shouldBe a[ContractInst[_]] | ||
} | ||
withClue("Charlie is unrelated and must not see the contract") { | ||
resultCharlie shouldBe None | ||
} | ||
} | ||
} | ||
|
||
it should "divulge contracts fetched under rollback nodes within a single transaction" in { | ||
val stakeholders = Set(alice) | ||
val divulgees = Set(bob) | ||
|
||
val builder = TransactionBuilder(TransactionVersion.VDev) | ||
val createCid = builder.newCid | ||
val fetcherCid = builder.newCid | ||
val create1 = createNode(createCid, stakeholders, stakeholders) | ||
val create2 = createNode(fetcherCid, divulgees, stakeholders.union(divulgees)) | ||
val exercise1 = exerciseNode(fetcherCid).copy( | ||
consuming = false, | ||
actingParties = stakeholders, | ||
signatories = divulgees, | ||
stakeholders = stakeholders.union(divulgees), | ||
) | ||
val rollback = builder.rollback() | ||
val fetch1 = fetchNode(createCid).copy( | ||
actingParties = stakeholders, | ||
signatories = stakeholders, | ||
stakeholders = stakeholders, | ||
) | ||
|
||
builder.add(create1) | ||
builder.add(create2) | ||
val exercise1Nid = builder.add(exercise1) | ||
val rollbackNid = builder.add(rollback, exercise1Nid) | ||
builder.add(fetch1, rollbackNid) | ||
val offsetAndEntry = fromTransaction(builder.buildCommitted()).copy() | ||
|
||
for { | ||
_ <- store( | ||
divulgedContracts = Map.empty, | ||
blindingInfo = None, | ||
offsetAndTx = offsetAndEntry, | ||
) | ||
resultAlice <- contractsReader.lookupActiveContractAndLoadArgument(Set(alice), createCid) | ||
resultBob <- contractsReader.lookupActiveContractAndLoadArgument(Set(bob), createCid) | ||
resultCharlie <- contractsReader.lookupActiveContractAndLoadArgument(Set(charlie), createCid) | ||
} yield { | ||
withClue("Alice is stakeholder") { | ||
resultAlice.value shouldBe a[ContractInst[_]] | ||
} | ||
withClue("Contract was divulged to Bob under a rollback node") { | ||
resultBob.value shouldBe a[ContractInst[_]] | ||
} | ||
withClue("Charlie is unrelated and must not see the contract") { | ||
resultCharlie shouldBe None | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters