Manage Dars and Packages¶
A package is a unit of compiled Daml code corresponding to one Daml project. A DAR is a collection of packages including a main package and all other packages from the dependencies of this Daml project.
Uploading DARs¶
To use a Daml application on a participant, you need to upload it to your participant node. The application always comes packaged as one or more DARs that need to be uploaded in the order of their dependency. There are two ways to upload DARs to a Canton node: either via the Ledger Api, or through Canton console command:
@ participant2.dars.upload("dars/CantonExamples.dar")
res1: String = "12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698"
Inspecting DARs and Packages¶
You can get a list of uploaded DARs using:
@ participant2.dars.list()
res2: Seq[com.digitalasset.canton.participant.admin.v0.DarDescription] = Vector(
DarDescription(
hash = "12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698",
name = "CantonExamples"
),
DarDescription(
hash = "122013b262b1caf41344a5e50b865bdad2995d88bde816326e307b48ea8047a76f8f",
name = "AdminWorkflowsWithVacuuming"
)
)
Please note that the package “AdminWorkflows” is a package that ships with Canton. It contains the Daml templates
used by the participant.health.ping
command.
In order to inspect the contents of the DAR, you need to grab the hash identifying it:
@ val dars = participant2.dars.list(filterName = "CantonExamples")
dars : Seq[com.digitalasset.canton.participant.admin.v0.DarDescription] = Vector(
DarDescription(
hash = "12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698",
name = "CantonExamples"
)
)
@ val hash = dars.head.hash
hash : String = "12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698"
Using that hash, you can inspect the contents of the DAR using:
@ val darContent = participant2.dars.list_contents(hash)
darContent : DarMetadata = DarMetadata(
name = "CantonExamples",
main = "b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975",
packages = Vector(
"b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975",
"94f7c83923aa273fb90b907f57385ae951ca1195fb35806275cbd03e9e4faab6",
"cb0552debf219cc909f51cbb5c3b41e9981d39f8f645b1f35e2ef5be2e0b858a",
"3f4deaf145a15cdcfa762c058005e2edb9baa75bb7f95a4f8f6f937378e86415",
..
You can also directly look at the packages, using:
@ participant2.packages.list()
res6: Seq[com.digitalasset.canton.participant.admin.v0.PackageDescription] = Vector(
PackageDescription(
packageId = "86828b9843465f419db1ef8a8ee741d1eef645df02375ebf509cdc8c3ddd16cb",
sourceDescription = "CantonExamples"
),
PackageDescription(
packageId = "cc348d369011362a5190fe96dd1f0dfbc697fdfd10e382b9e9666f0da05961b7",
sourceDescription = "CantonExamples"
..
Please note that a DAR can include packages that are already included in other DARs. In particular the Daml standard library
are shipped with every DAR. Therefore, the sourceDescription
will always contain only one textual reference to a DAR.
You can also inspect the content of a package, using:
@ participant2.packages.list_contents(darContent.main)
res7: Seq[com.digitalasset.canton.participant.admin.v0.ModuleDescription] = Vector(
ModuleDescription(name = "CantonExamples"),
ModuleDescription(name = "ContractKeys"),
ModuleDescription(name = "SafePaint"),
ModuleDescription(name = "LockIou"),
ModuleDescription(name = "Iou"),
ModuleDescription(name = "Divulgence"),
ModuleDescription(name = "Paint"),
..
Understanding Package Vetting¶
Every participant operator uploads DARs individually to their participant node. There is no global DAR repository anywhere and participants do not have access to each others DAR repositories. Therefore, for two participants to synchronise on a transaction that uses packages contained in a certain DAR, we need both participant operators to have uploaded the same DAR before the transaction was submitted.
If one of the involved participants doesn’t know about a certain DAR, then the transaction will bounce with an error PACKAGE_NO_VETTED_BY_RECIPIENTS.
This error goes back to the fact that both participants not only upload the DAR, but also publicly declare towards their peers that they are ready to receive transactions referring to certain packages. This declaration happens automatically when you upload a DAR. The package vettings can be inspected using (preview):
@ participant2.topology.vetted_packages.list()
res8: Seq[ListVettedPackagesResult] = Vector(
ListVettedPackagesResult(
context = BaseResult(
domain = "Authorized",
validFrom = 2023-01-18T07:30:24.393842Z,
validUntil = None,
operation = Add,
serialized = <ByteString@7514014c size=2384 contents="\n\315\022\n\373\017\n\366\017\n\363\017\022 MKnZCTKBttMbsv6LJYd5XdES1eFPloT0J...">,
..
Vetting is necessary, as otherwise, a malicious participant might send a transaction referring to package a receiver does not have, which would make it impossible for the receiver to process the transaction, leading to a ledger fork. As transactions are valid only if all involved participants have vetted the used packages, this attack cannot happen.
Removing Packages and DARs¶
Note
Note that package and DAR removal is under active development. The behaviour described in this documentation may change in the future. Package and DAR removal is a preview feature and should not be used in production.
Canton supports removal of both packages and DARs that are no longer in use. Removing unused packages and DARs has the following advantages:
- Freeing up storage
- Preventing accidental use of the old package / DAR
- Reducing the number of packages / DARs that are trusted and may potentially have to be audited
Certain conditions must to be met in order to remove packages or DARs. These conditions are designed to prevent removal of packages or DARs that are currently in use. The rest of this page describes the requirements.
Removing DARs¶
The following checks are performed before a DAR can be removed:
- The main package of the DAR must be unused – there should be no active contract from this package
- All package dependencies of the DAR should either be unused or contained in another of the participant node’s uploaded DARs. Canton uses this restriction to ensure that the package dependencies of the DAR don’t become “stranded” if they’re in use.
- The main package of the dar should not be vetted. If it is vetted, Canton will try to automatically revoke the vetting for the main package of the DAR, but this automatic vetting revocation will only succeed if the main package vetting originates from a standard
dars.upload
. Even if the automatic revocation fails, you can always manually revoke the package vetting.
The following tutorial shows how to remove a DAR with the Canton console. The first step is to upload a DAR so that we have one to removed. Additionally, store the packages that are present before the DAR is uploaded, as these can be used to double-check that DAR removal reverts to a clean state.
@ val packagesBefore = participant1.packages.list().map(_.packageId).toSet
packagesBefore : Set[String] = HashSet(
"86828b9843465f419db1ef8a8ee741d1eef645df02375ebf509cdc8c3ddd16cb",
"cc348d369011362a5190fe96dd1f0dfbc697fdfd10e382b9e9666f0da05961b7",
"8f2bee967b24bdf41ad1e2c4af0df252b90d3825388bd097a3a16f6f673b0bda",
"6839a6d3d430c569b2425e9391717b44ca324b88ba621d597778811b2d05031d",
"99a2705ed38c1c26cbb8fe7acf36bbf626668e167a33335de932599219e0a235",
"e22bce619ae24ca3b8e6519281cb5a33b64b3190cc763248b4c3f9ad5087a92c",
"d58cf9939847921b2aab78eaa7b427dc4c649d25e6bee3c749ace4c3f52f5c97",
"a8a0503a014f41cb4e82304b51aeb7091b0108b8c6c28e8efb44a3411ca35dfe",
"c1f1f00558799eec139fb4f4c76f95fb52fa1837a5dd29600baa1c8ed1bdccfd",
..
@ val darHash = participant1.dars.upload("dars/CantonExamples.dar")
darHash : String = "12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698"
If the DAR hash is unknown, it can be found using dars.list
:
@ val darHash_ = participant1.dars.list().filter(_.name == "CantonExamples").head.hash
darHash_ : String = "12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698"
The DAR can then be removed with the following command:
@ participant1.dars.remove(darHash)
Note that, right now, DAR removal will only remove the main packages associated with the DAR:
@ val packageIds = participant1.packages.list().filter(_.sourceDescription == "CantonExamples").map(_.packageId)
packageIds : Seq[String] = Vector(
"86828b9843465f419db1ef8a8ee741d1eef645df02375ebf509cdc8c3ddd16cb",
"cc348d369011362a5190fe96dd1f0dfbc697fdfd10e382b9e9666f0da05961b7",
"e491352788e56ca4603acc411ffe1a49fefd76ed8b163af86cf5ee5f4c38645b",
"cb0552debf219cc909f51cbb5c3b41e9981d39f8f645b1f35e2ef5be2e0b858a",
"38e6274601b21d7202bb995bc5ec147decda5a01b68d57dda422425038772af7",
"99a2705ed38c1c26cbb8fe7acf36bbf626668e167a33335de932599219e0a235",
"8f2bee967b24bdf41ad1e2c4af0df252b90d3825388bd097a3a16f6f673b0bda",
"f20de1e4e37b92280264c08bf15eca0be0bc5babd7a7b5e574997f154c00cb78",
"3333acae29deb873d437d0f64ccefd2d81c6ca4b81e5958132690bba92729859",
..
It’s possible to remove each of these manually, using package removal. There is a complication here that packages needed for admin workflows (e.g. the Ping command) cannot be removed, so these are skipped.
@ packageIds.filter(id => ! packagesBefore.contains(id)).foreach(id => participant1.packages.remove(id))
The following command verifies that all the packages have been removed.
@ val packages = participant1.packages.list().map(_.packageId).toSet
packages : Set[String] = HashSet(
"86828b9843465f419db1ef8a8ee741d1eef645df02375ebf509cdc8c3ddd16cb",
"cc348d369011362a5190fe96dd1f0dfbc697fdfd10e382b9e9666f0da05961b7",
"8f2bee967b24bdf41ad1e2c4af0df252b90d3825388bd097a3a16f6f673b0bda",
"6839a6d3d430c569b2425e9391717b44ca324b88ba621d597778811b2d05031d",
"99a2705ed38c1c26cbb8fe7acf36bbf626668e167a33335de932599219e0a235",
"e22bce619ae24ca3b8e6519281cb5a33b64b3190cc763248b4c3f9ad5087a92c",
"d58cf9939847921b2aab78eaa7b427dc4c649d25e6bee3c749ace4c3f52f5c97",
"a8a0503a014f41cb4e82304b51aeb7091b0108b8c6c28e8efb44a3411ca35dfe",
"c1f1f00558799eec139fb4f4c76f95fb52fa1837a5dd29600baa1c8ed1bdccfd",
..
@ assert(packages == packagesBefore)
The following sections explain what happens when the DAR removal operation goes wrong, for various reasons.
Main package of the DAR is in use¶
The first step to illustrate this is to upload a DAR and create a contract using the main package of the DAR:
@ val darHash = participant1.dars.upload("dars/CantonExamples.dar")
darHash : String = "12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698"
@ val packageId = participant1.packages.find("Iou").head.packageId
packageId : String = "b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975"
@ participant1.domains.connect_local(mydomain)
@ val createIouCmd = ledger_api_utils.create(packageId,"Iou","Iou",Map("payer" -> participant1.adminParty,"owner" -> participant1.adminParty,"amount" -> Map("value" -> 100.0, "currency" -> "EUR"),"viewers" -> List()))
..
@ participant1.ledger_api.commands.submit(Seq(participant1.adminParty), Seq(createIouCmd))
res21: com.daml.ledger.api.v1.transaction.TransactionTree = TransactionTree(
transactionId = "122064486a693faf3387165a58dd06ef3f0aa70fd617dada7d3047313e5b058c8726",
commandId = "1ad906ca-5e12-4cfb-97d2-ec2d530be268",
workflowId = "",
effectiveAt = Some(
..
Now that a contract exists using the main package of the DAR, a subsequent DAR removal operation will fail:
@ participant1.dars.remove(darHash)
ERROR com.digitalasset.canton.integration.EnterpriseEnvironmentDefinition$$anon$3 - Request failed for participant1.
GrpcRequestRefusedByServer: FAILED_PRECONDITION/PACKAGE_OR_DAR_REMOVAL_ERROR(9,bc381c36): The DAR DarDescriptor(SHA-256:8d2c191a3e47...,CantonExamples) cannot be removed because its main package b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975 is in-use by contract ContractId(00024bd543a4b32b90b6b24ac2d77d0b678151783a2a92b24a4ea7f7adf9fdfd1cca01122098e5b6d3d4065603a672f79469b9ea259e3677c2ce04e266a33d4f6d47d9a8c7)
on domain mydomain::12205eb65d75....
Request: RemoveDar(12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698)
CorrelationId: bc381c3600327055f118c9e5856b28d5
Context: Map(participant -> participant1, test -> PackageDarManagementDocumentationIntegrationTest, pkg -> b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975)
Command ParticipantAdministration$dars$.remove invoked from cmd10000056.sc:1
In order to remove the DAR, we must archive this contract. Note that the contract ID for this contract can also be found in the error message above.
@ val iou = participant1.ledger_api.acs.find_generic(participant1.adminParty, _.templateId == "Iou.Iou")
iou : com.digitalasset.canton.admin.api.client.commands.LedgerApiTypeWrappers.WrappedCreatedEvent = WrappedCreatedEvent(
event = CreatedEvent(
eventId = "#122064486a693faf3387165a58dd06ef3f0aa70fd617dada7d3047313e5b058c8726:0",
contractId = "00024bd543a4b32b90b6b24ac2d77d0b678151783a2a92b24a4ea7f7adf9fdfd1cca01122098e5b6d3d4065603a672f79469b9ea259e3677c2ce04e266a33d4f6d47d9a8c7",
templateId = Some(
value = Identifier(
packageId = "b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975",
moduleName = "Iou",
entityName = "Iou"
)
..
@ val archiveIouCmd = ledger_api_utils.exercise("Archive", Map.empty, iou.event)
..
@ participant1.ledger_api.commands.submit(Seq(participant1.adminParty), Seq(archiveIouCmd))
res24: com.daml.ledger.api.v1.transaction.TransactionTree = TransactionTree(
transactionId = "12200ed763aa7d22936e387f5a2b6e6de8bbc02ef6f045c5449385f9839b17345f21",
commandId = "13a8291e-7638-4b7f-ab42-a69bab07424f",
workflowId = "",
effectiveAt = Some(
..
The DAR removal operation will now succeed.
@ participant1.dars.remove(darHash)
Main package of the DAR can’t be automatically removed¶
Similarly, DAR removal may fail because the DAR can’t be automatically removed. To illustrate this, upload the DAR without automatic vetting and subsequently vet all the packages manually.
@ val darHash = participant1.dars.upload("dars/CantonExamples.dar", vetAllPackages = false)
darHash : String = "12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698"
@ import com.daml.lf.data.Ref.IdString.PackageId
@ val packageIds = participant1.packages.list().filter(_.sourceDescription == "CantonExamples").map(_.packageId).map(PackageId.assertFromString)
packageIds : Seq[PackageId] = Vector(
"86828b9843465f419db1ef8a8ee741d1eef645df02375ebf509cdc8c3ddd16cb",
"cc348d369011362a5190fe96dd1f0dfbc697fdfd10e382b9e9666f0da05961b7",
..
@ participant1.topology.vetted_packages.authorize(TopologyChangeOp.Add, participant1.id, packageIds)
res29: com.google.protobuf.ByteString = <ByteString@1d4fcc90 size=2186 contents="\n\207\021\n\265\016\n\260\016\n\255\016\022 tmjuwEiW49kLbLmoBCj338DL216XJ6GYJ...">
The DAR removal operation will now fail:
@ participant1.dars.remove(darHash)
ERROR com.digitalasset.canton.integration.EnterpriseEnvironmentDefinition$$anon$3 - Request failed for participant1.
GrpcRequestRefusedByServer: FAILED_PRECONDITION/PACKAGE_OR_DAR_REMOVAL_ERROR(9,54f915ec): An error was encountered whilst trying to unvet the DAR DarDescriptor(SHA-256:8d2c191a3e47...,CantonExamples) with main package b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975 for DAR removal. Details: IdentityManagerParentError(Mapping(VettedPackages(
participant = participant1::122043845af7...,
packages = Seq(
b6a223f572fe...,
94f7c83923aa...,
cb0552debf21...,
3f4deaf145a1...,
86828b984346...,
f20de1e4e37b...,
76bf0fd12bd9...,
38e6274601b2...,
d58cf...
Request: RemoveDar(12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698)
CorrelationId: 54f915ec744633a58c63545cc67a3098
Context: Map(participant -> participant1, test -> PackageDarManagementDocumentationIntegrationTest)
Command ParticipantAdministration$dars$.remove invoked from cmd10000076.sc:1
The DAR can be successfully removed after manually revoking the vetting for the main package:
@ participant1.topology.vetted_packages.authorize(TopologyChangeOp.Remove, participant1.id, packageIds, force = true)
res30: com.google.protobuf.ByteString = <ByteString@58500b55 size=2188 contents="\n\211\021\n\267\016\n\262\016\n\257\016\b\001\022 tmjuwEiW49kLbLmoBCj338DL216XJ6G...">
@ participant1.dars.remove(darHash)
Note that a force
flag is needed used to revoke the package vetting; throughout this tutorial force
will be used whenever a package vetting is being removed.
See topology.vetted_packages.authorize for more detail.
Removing Packages¶
Canton also supports removing individual packages, giving the user more fine-grained control over the system. Packages can be removed if the package satisfies the following two requirements:
- The package must be unused. This means that there shouldn’t be an active contract corresponding to the package.
- The package must not be vetted. This means there shouldn’t be an active vetting transaction corresponding to the package.
The following tutorial shows how to remove a package using the Canton console. The first step is to upload and identify the package ID for the package to be removed.
@ val darHash = participant1.dars.upload("dars/CantonExamples.dar")
darHash : String = "12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698"
@ val packageId = participant1.packages.find("Iou").head.packageId
packageId : String = "b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975"
Package removal will initially fail as, by default, uploading the DAR will add a vetting transaction for the package:
@ participant1.packages.remove(packageId)
ERROR com.digitalasset.canton.integration.EnterpriseEnvironmentDefinition$$anon$3 - Request failed for participant1.
GrpcRequestRefusedByServer: FAILED_PRECONDITION/PACKAGE_OR_DAR_REMOVAL_ERROR(9,fafb874e): Package b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975 is currently vetted and available to use.
Request: RemovePackage(b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975,false)
CorrelationId: fafb874e5c28458addbaed39737e3c20
Context: Map(participant -> participant1, test -> PackageDarManagementDocumentationIntegrationTest)
Command ParticipantAdministration$packages$.remove invoked from cmd10000087.sc:1
The vetting transaction must be manually revoked:
@ val packageIds = participant1.topology.vetted_packages.list().map(_.item.packageIds).filter(_.contains(packageId)).head
packageIds : Seq[com.digitalasset.canton.package.LfPackageId] = Vector(
"b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975",
"94f7c83923aa273fb90b907f57385ae951ca1195fb35806275cbd03e9e4faab6",
..
@ participant1.topology.vetted_packages.authorize(TopologyChangeOp.Remove, participant1.id, packageIds, force = true)
res35: com.google.protobuf.ByteString = <ByteString@50a20a56 size=2188 contents="\n\211\021\n\267\016\n\262\016\n\257\016\b\001\022 LlWKjTgwySEucVnYRT3xT0XDmN5nuXb...">
And then the package can be removed:
@ participant1.packages.remove(packageId)
Package is in use¶
The operations above will fail if the package is in use. To illustrate this, first re-upload the package (uploading the associated DAR will work):
@ val darHash = participant1.dars.upload("dars/CantonExamples.dar")
darHash : String = "12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698"
Then create a contract using the package:
@ val createIouCmd = ledger_api_utils.create(packageId,"Iou","Iou",Map("payer" -> participant1.adminParty,"owner" -> participant1.adminParty,"amount" -> Map("value" -> 100.0, "currency" -> "EUR"),"viewers" -> List()))
createIouCmd : com.daml.ledger.api.v1.commands.Command = Command(
command = Create(
value = CreateCommand(
templateId = Some(
value = Identifier(
..
@ participant1.ledger_api.commands.submit(Seq(participant1.adminParty), Seq(createIouCmd))
res39: com.daml.ledger.api.v1.transaction.TransactionTree = TransactionTree(
transactionId = "1220f391c4445282bac2146d0ba0e7d290ad269a71b0bb34e9e918eb6ddc7e38b0bf",
commandId = "38ff63e2-964c-4c18-b1a5-319fcdb5b1f9",
workflowId = "",
effectiveAt = Some(
value = Timestamp(
seconds = 1674027037L,
nanos = 968295000,
unknownFields = UnknownFieldSet(fields = Map())
)
..
In this situation, the package cannot be removed:
@ participant1.packages.remove(packageId)
ERROR com.digitalasset.canton.integration.EnterpriseEnvironmentDefinition$$anon$3 - Request failed for participant1.
GrpcRequestRefusedByServer: FAILED_PRECONDITION/PACKAGE_OR_DAR_REMOVAL_ERROR(9,f4272378): Package b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975 is currently in-use by contract ContractId(0075aaeade7074817d33a8128263b84a7563191fb2bdd4b9b82a10118eea717570ca0112205e646ba0e338ebc9552e871804752f665c28a90e5c8902ffda54b1747e946e94) on domain mydomain::12205eb65d75.... It may also be in-use by other contracts.
Request: RemovePackage(b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975,false)
CorrelationId: f4272378306f86c1e00f986b47bbe385
Context: HashMap(participant -> participant1, test -> PackageDarManagementDocumentationIntegrationTest, domain -> mydomain::12205eb65d75..., pkg -> b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975, contract -> ContractId(0075aaeade7074817d33a8128263b84a7563191fb2bdd4b9b82a10118eea717570ca0112205e646ba0e338ebc9552e871804752f665c28a90e5c8902ffda54b1747e946e94))
Command ParticipantAdministration$packages$.remove invoked from cmd10000103.sc:1
To remove the package, first archive the contract:
@ val iou = participant1.ledger_api.acs.find_generic(participant1.adminParty, _.templateId == "Iou.Iou")
iou : com.digitalasset.canton.admin.api.client.commands.LedgerApiTypeWrappers.WrappedCreatedEvent = WrappedCreatedEvent(
event = CreatedEvent(
eventId = "#1220f391c4445282bac2146d0ba0e7d290ad269a71b0bb34e9e918eb6ddc7e38b0bf:0",
contractId = "0075aaeade7074817d33a8128263b84a7563191fb2bdd4b9b82a10118eea717570ca0112205e646ba0e338ebc9552e871804752f665c28a90e5c8902ffda54b1747e946e94",
templateId = Some(
value = Identifier(
packageId = "b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975",
moduleName = "Iou",
entityName = "Iou"
)
..
@ val archiveIouCmd = ledger_api_utils.exercise("Archive", Map.empty, iou.event)
archiveIouCmd : com.daml.ledger.api.v1.commands.Command = Command(
command = Exercise(
value = ExerciseCommand(
templateId = Some(
value = Identifier(
packageId = "b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975",
moduleName = "Iou",
entityName = "Iou"
)
),
..
@ participant1.ledger_api.commands.submit(Seq(participant1.adminParty), Seq(archiveIouCmd))
res42: com.daml.ledger.api.v1.transaction.TransactionTree = TransactionTree(
transactionId = "122067cf0dd5e2719426b7464fc3d4074709185297cb176bbe1fb692f8c1ef36476a",
commandId = "0d8c5817-8fb3-4262-822d-07bf35821bcf",
workflowId = "",
effectiveAt = Some(
value = Timestamp(
seconds = 1674027038L,
nanos = 482121000,
unknownFields = UnknownFieldSet(fields = Map())
)
),
offset = "00000000000000000c",
..
Then revoke the package vetting transaction:
@ val packageIds = participant1.topology.vetted_packages.list().map(_.item.packageIds).filter(_.contains(packageId)).head
packageIds : Seq[com.digitalasset.canton.package.LfPackageId] = Vector(
"b6a223f572fe64055932b2a83e05860bd8c631b91e7d4895c51fb9fa6a42b975",
"94f7c83923aa273fb90b907f57385ae951ca1195fb35806275cbd03e9e4faab6",
..
@ participant1.topology.vetted_packages.authorize(TopologyChangeOp.Remove, participant1.id, packageIds, force = true)
res44: com.google.protobuf.ByteString = <ByteString@59fb3175 size=2188 contents="\n\211\021\n\267\016\n\262\016\n\257\016\b\001\022 tLmb0PIjNE2BCFywXxvOHRak9QGqetC...">
The package removal operation should now succeed.
@ participant1.packages.remove(packageId)
Force-removing packages¶
Packages can also be forcibly removed, even if the conditions above are not satisfied. This is done by setting the
force
flag to true
.
To experiment with this, first re-upload the DAR so the package becomes available again:
@ participant1.dars.upload("dars/CantonExamples.dar")
res46: String = "12208d2c191a3e47f65e5b1af2575cb353dc9405dd1f41dc3484991f5e6e5aa43698"
Then force-remove the package:
@ participant1.packages.remove(packageId, force = true)
Please note, this is a dangerous operation. Forced removal of packages should be avoided whenever possible.