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 = "12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112"
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 = "122044931372586b05693d0f8982c5c4f4949efdce288c0c526ec27ec063d4d9422d",
name = "AdminWorkflowsWithVacuuming"
),
DarDescription(
hash = "12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112",
name = "CantonExamples"
)
)
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 = "12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112",
name = "CantonExamples"
)
)
@ val hash = dars.head.hash
hash : String = "12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112"
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 = "bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390",
packages = Vector(
"bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390",
"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 = "e163e4cf7283ea4ab6fcf4c06bcde90de1d653b05c359b11c41bbb4b00a4befe",
sourceDescription = "CantonExamples"
),
PackageDescription(
packageId = "86828b9843465f419db1ef8a8ee741d1eef645df02375ebf509cdc8c3ddd16cb",
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-03-16T07:26:07.387410Z,
validUntil = None,
operation = Add,
serialized = <ByteString@30f0ed0d size=2582 contents="\n\223\024\n\301\021\n\274\021\n\271\021\022 wtUyPSXwKPFED3EGtWcgefkXUQOCNrmRJ...">,
..
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 remove. 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",
"5921708ce82f4255deb1b26d2c05358b548720938a5a325718dc69f381ba47ff",
"cc348d369011362a5190fe96dd1f0dfbc697fdfd10e382b9e9666f0da05961b7",
"6839a6d3d430c569b2425e9391717b44ca324b88ba621d597778811b2d05031d",
"e22bce619ae24ca3b8e6519281cb5a33b64b3190cc763248b4c3f9ad5087a92c",
"d58cf9939847921b2aab78eaa7b427dc4c649d25e6bee3c749ace4c3f52f5c97",
"43a670141e6815e00acbcafb1ecc84677146344888f7670a9eaec874d5ae4e71",
"8a7806365bbd98d88b4c13832ebfa305f6abaeaf32cfa2b7dd25c4fa489b79fb",
"c1f1f00558799eec139fb4f4c76f95fb52fa1837a5dd29600baa1c8ed1bdccfd",
..
@ val darHash = participant1.dars.upload("dars/CantonExamples.dar")
darHash : String = "12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112"
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 = "12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112"
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(
"e163e4cf7283ea4ab6fcf4c06bcde90de1d653b05c359b11c41bbb4b00a4befe",
"86828b9843465f419db1ef8a8ee741d1eef645df02375ebf509cdc8c3ddd16cb",
"cc348d369011362a5190fe96dd1f0dfbc697fdfd10e382b9e9666f0da05961b7",
"e491352788e56ca4603acc411ffe1a49fefd76ed8b163af86cf5ee5f4c38645b",
"cb0552debf219cc909f51cbb5c3b41e9981d39f8f645b1f35e2ef5be2e0b858a",
"38e6274601b21d7202bb995bc5ec147decda5a01b68d57dda422425038772af7",
"99a2705ed38c1c26cbb8fe7acf36bbf626668e167a33335de932599219e0a235",
"f20de1e4e37b92280264c08bf15eca0be0bc5babd7a7b5e574997f154c00cb78",
"43a670141e6815e00acbcafb1ecc84677146344888f7670a9eaec874d5ae4e71",
..
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",
"5921708ce82f4255deb1b26d2c05358b548720938a5a325718dc69f381ba47ff",
"cc348d369011362a5190fe96dd1f0dfbc697fdfd10e382b9e9666f0da05961b7",
"6839a6d3d430c569b2425e9391717b44ca324b88ba621d597778811b2d05031d",
"e22bce619ae24ca3b8e6519281cb5a33b64b3190cc763248b4c3f9ad5087a92c",
"d58cf9939847921b2aab78eaa7b427dc4c649d25e6bee3c749ace4c3f52f5c97",
"43a670141e6815e00acbcafb1ecc84677146344888f7670a9eaec874d5ae4e71",
"8a7806365bbd98d88b4c13832ebfa305f6abaeaf32cfa2b7dd25c4fa489b79fb",
"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 = "12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112"
@ val packageId = participant1.packages.find("Iou").head.packageId
packageId : String = "bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390"
@ 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 = "12205b466fba1a1981c5f2a187c051f34a874303a52bff8669cab6f9e0b644e56f6d",
commandId = "58a019f1-e0d7-4634-acf9-f79760674fc7",
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,398fca97): The DAR DarDescriptor(SHA-256:0a4c7ef24e9a...,CantonExamples) cannot be removed because its main package bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390 is in-use by contract ContractId(003fe762b33643d35448559424ce842d3bc7f2e05e2a84594996c065e5d7212c03ca0112203483942345b23325c5082ff417a9256e546bd13b817c99f13fa79a6cd24a568e)
on domain mydomain::12203f410c78....
Request: RemoveDar(12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112)
CorrelationId: 398fca97dcbfe37b590b5fafb2fec4aa
Context: Map(participant -> participant1, test -> PackageDarManagementDocumentationIntegrationTest, pkg -> bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390)
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 = "#12205b466fba1a1981c5f2a187c051f34a874303a52bff8669cab6f9e0b644e56f6d:0",
contractId = "003fe762b33643d35448559424ce842d3bc7f2e05e2a84594996c065e5d7212c03ca0112203483942345b23325c5082ff417a9256e546bd13b817c99f13fa79a6cd24a568e",
templateId = Some(
value = Identifier(
packageId = "bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390",
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 = "1220751c82f0150ad68e77414095ac393fd5950dace8a5d97369cdbdad7b1e931d14",
commandId = "792362b8-1346-4297-9976-7a65e91d4416",
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 = "12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112"
@ 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(
"e163e4cf7283ea4ab6fcf4c06bcde90de1d653b05c359b11c41bbb4b00a4befe",
"86828b9843465f419db1ef8a8ee741d1eef645df02375ebf509cdc8c3ddd16cb",
..
@ participant1.topology.vetted_packages.authorize(TopologyChangeOp.Add, participant1.id, packageIds)
res29: com.google.protobuf.ByteString = <ByteString@41f435cd size=2384 contents="\n\315\022\n\373\017\n\366\017\n\363\017\022 nnMYLDtEzIgM1vIjgRHDNI6fICaFPAZ4J...">
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,928073e8): An error was encountered whilst trying to unvet the DAR DarDescriptor(SHA-256:0a4c7ef24e9a...,CantonExamples) with main package bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390 for DAR removal. Details: IdentityManagerParentError(Mapping(VettedPackages(
participant = participant1::12207d840d72...,
packages = Seq(
bb6b23d5c387...,
94f7c83923aa...,
cb0552debf21...,
3f4deaf145a1...,
86828b984346...,
f20de1e4e37b...,
76bf0fd12bd9...,
38e6274601b2...,
d58cf...
Request: RemoveDar(12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112)
CorrelationId: 928073e84ffa1582620de246e6e2a727
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@6f415363 size=2386 contents="\n\317\022\n\375\017\n\370\017\n\365\017\b\001\022 nnMYLDtEzIgM1vIjgRHDNI6fICaFPAZ...">
@ 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 = "12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112"
@ val packageId = participant1.packages.find("Iou").head.packageId
packageId : String = "bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390"
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,acaca71a): Package bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390 is currently vetted and available to use.
Request: RemovePackage(bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390,false)
CorrelationId: acaca71a391e26de138ac74c099d00f1
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(
"bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390",
"94f7c83923aa273fb90b907f57385ae951ca1195fb35806275cbd03e9e4faab6",
..
@ participant1.topology.vetted_packages.authorize(TopologyChangeOp.Remove, participant1.id, packageIds, force = true)
res35: com.google.protobuf.ByteString = <ByteString@2145217a size=2386 contents="\n\317\022\n\375\017\n\370\017\n\365\017\b\001\022 upUjqeLg1b0GG3pBA3wrCm3AY2uVoqb...">
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 = "12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112"
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 = "1220940ed57ee7654ec18cf2306d2978e8040d3773eca446db187c780f7698d6e47a",
commandId = "16f7e77f-06c9-4d80-a5ad-d1da9a3b956f",
workflowId = "",
effectiveAt = Some(
value = Timestamp(
seconds = 1678951579L,
nanos = 574154000,
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,c44b0ca7): Package bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390 is currently in-use by contract ContractId(00b4c83289fcac6ccf06b94e3ea8e82641ba0fd1f8851c7fcd435bfaad243268ddca01122001ecae1957e301bae3c710bde639d6fb0fcc750a627fccce329519c4c36d5136) on domain mydomain::12203f410c78.... It may also be in-use by other contracts.
Request: RemovePackage(bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390,false)
CorrelationId: c44b0ca73240f5fca48ec96075d82424
Context: HashMap(participant -> participant1, test -> PackageDarManagementDocumentationIntegrationTest, domain -> mydomain::12203f410c78..., pkg -> bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390, contract -> ContractId(00b4c83289fcac6ccf06b94e3ea8e82641ba0fd1f8851c7fcd435bfaad243268ddca01122001ecae1957e301bae3c710bde639d6fb0fcc750a627fccce329519c4c36d5136))
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 = "#1220940ed57ee7654ec18cf2306d2978e8040d3773eca446db187c780f7698d6e47a:0",
contractId = "00b4c83289fcac6ccf06b94e3ea8e82641ba0fd1f8851c7fcd435bfaad243268ddca01122001ecae1957e301bae3c710bde639d6fb0fcc750a627fccce329519c4c36d5136",
templateId = Some(
value = Identifier(
packageId = "bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390",
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 = "bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390",
moduleName = "Iou",
entityName = "Iou"
)
),
..
@ participant1.ledger_api.commands.submit(Seq(participant1.adminParty), Seq(archiveIouCmd))
res42: com.daml.ledger.api.v1.transaction.TransactionTree = TransactionTree(
transactionId = "1220d298982203111bde3c5651958fac0fcc68bba3c4f26b25547552b58a8f1bb6b9",
commandId = "eae0a68a-296a-456b-af78-c9be19753488",
workflowId = "",
effectiveAt = Some(
value = Timestamp(
seconds = 1678951580L,
nanos = 27698000,
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(
"bb6b23d5c3871f6236959144933e6259b693eab549ce9521a4862b525ccaa390",
"94f7c83923aa273fb90b907f57385ae951ca1195fb35806275cbd03e9e4faab6",
..
@ participant1.topology.vetted_packages.authorize(TopologyChangeOp.Remove, participant1.id, packageIds, force = true)
res44: com.google.protobuf.ByteString = <ByteString@112ceea0 size=2386 contents="\n\317\022\n\375\017\n\370\017\n\365\017\b\001\022 4XauGlnNNfAeTrKmDmE4eojU4R37igc...">
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 = "12200a4c7ef24e9ab5419c3300b5752b2869a9ab9df58720ea28b3e4ab1e3ae6e112"
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.