Participant Node Migration

To migrate an existing participant node connected to a domain with a non KMS-compatible provider and start using KMS external keys, you need to manually execute the following steps. The general idea is to replicate the old node into a new one that uses a KMS provider and connects to a KMS-compatible domain (e.g. running JCE with KMS supported encryption and signing keys).

First, delegate the namespace of the old participant to the new participant:

val namespaceOld = participantOld.uid.namespace.fingerprint
val namespaceNew = participantNew.uid.namespace.fingerprint

val rootNamespaceDelegationOld = participantOld.topology.namespace_delegations
  .list(filterNamespace = namespaceOld.toProtoPrimitive)

val namespaceKeyNew =
participantOld.keys.public.upload(namespaceKeyNew, Some("pNew-namespace-key"))

// Delegate namespace of old participant to new participant
val delegation = participantOld.topology.namespace_delegations.authorize(
  ops = TopologyChangeOp.Add,
  namespace = namespaceOld,
  authorizedKey = namespaceNew,


Secondly, you must recreate all parties of the old participant in the new participant:

val parties = participantOld.parties.list().map(

// Disconnect from new KMS-compatible domain to prepare migration of parties and contracts

parties.foreach { party =>
    .authorize(ops = TopologyChangeOp.Add, party = party, participant =

Finally, you need to transfer the active contracts of all the parties from the old participant to the new one and connect to the new domain:

val parties = participantOld.parties.list().map(

// Make sure domain and the old participant are quiet before exporting ACS

// There should be no conflicts between the protocol version of the old domain and the new domain
val protocolVersion = newKmsDomainManager.config.init.domainParameters.initialProtocolVersion

File.usingTemporaryFile("participantOld-acs", suffix = ".txt") { acsFile =>
  val acsFileName = acsFile.toString

  // Export from old participant
    parties = parties.toSet,
    outputFile = acsFileName,
    contractDomainRenames = Map(oldDomainId -> (newKmsDomainId, protocolVersion)),
    partiesOffboarding = false,

  // Import to new participant, parties.toSet)

// Kill/stop the old participant

// Connect the new participant to the new domain

The end result is a new participant node with its keys stored and managed by a KMS connected to a domain that is able to communicate using the appropriate key schemes.

You need to follow the same steps if you want to migrate a node back to using a non-KMS provider.