Skip to content

Commit cc6bd1a

Browse files
move to folders
Signed-off-by: rukmini-basu-da <[email protected]>
1 parent 601e22e commit cc6bd1a

File tree

4 files changed

+580
-0
lines changed

4 files changed

+580
-0
lines changed

canton/devnet/bootstrap.sc

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
import com.google.protobuf.ByteString
2+
3+
import java.io._
4+
import java.net.{HttpURLConnection, URI}
5+
import java.nio.file.{Files, Path, StandardCopyOption}
6+
import scala.concurrent.blocking
7+
import better.files.File
8+
import com.digitalasset.canton.console.{
9+
InstanceReference,
10+
LocalInstanceReference,
11+
LocalMediatorReference,
12+
LocalSequencerReference,
13+
MediatorReference,
14+
ParticipantReference,
15+
SequencerReference,
16+
}
17+
import com.digitalasset.canton.version.ProtocolVersion._
18+
import com.digitalasset.canton.topology.{SynchronizerId, UniqueIdentifier}
19+
import com.digitalasset.canton.console.commands.ConsoleCommandGroup
20+
import com.digitalasset.canton.util.BinaryFileUtil
21+
import com.digitalasset.canton.sequencing.{SequencerConnections, SubmissionRequestAmplification}
22+
23+
24+
val cantonDir = "canton"
25+
val synchronizerDir = s"$cantonDir/synchronizer-bootstrap"
26+
27+
logger.info(s"WALLET-KERNEL-BOOTSTRAP")
28+
29+
val keyName = "participant1NameSpaceKey"
30+
31+
participant1.keys.secret.upload_from(s"$cantonDir/participant1.key", Some(keyName))
32+
33+
val key = participant1.keys.secret.list(filterName = keyName).headOption.get
34+
35+
36+
val namespaceKey = key.publicKey match { case s: SigningPublicKey => s }
37+
38+
39+
val namespace = Namespace(namespaceKey.id)
40+
41+
participant1.topology.init_id_from_uid(UniqueIdentifier.tryCreate(participant1.name, namespace))
42+
43+
participant1.topology.namespace_delegations.propose_delegation(namespace, namespaceKey, CanSignAllMappings)
44+
45+
participant1.health.wait_for_ready_for_node_topology()
46+
47+
val sequencerAuthKey = participant1.keys.secret.generate_signing_key(s"participant1-${SigningKeyUsage.SequencerAuthentication.identifier}", SigningKeyUsage.SequencerAuthenticationOnly)
48+
49+
val signingKey = participant1.keys.secret.generate_signing_key(s"participant1-${SigningKeyUsage.Protocol.identifier}", SigningKeyUsage.ProtocolOnly)
50+
val encryptionKey = participant1.keys.secret.generate_encryption_key("participant1-encryption")
51+
52+
participant1.topology.owner_to_key_mappings.propose(
53+
OwnerToKeyMapping(
54+
participant1.id.member,
55+
com.daml.nonempty.NonEmpty(Seq, sequencerAuthKey, signingKey, encryptionKey),
56+
),
57+
signedBy = Seq(namespaceKey.fingerprint, sequencerAuthKey.fingerprint, signingKey.fingerprint),
58+
)
59+
participant1.health.wait_for_initialized()
60+
61+
//import data
62+
logger.info("Importing sequencer/mediator data ")
63+
64+
val synchronizerId = SynchronizerId.tryFromString(better.files.File(s"$synchronizerDir/synchronizer-id").contentAsString)
65+
logger.info(s"synchronizer id is $synchronizerId")
66+
67+
val testedProtocolVersion = ProtocolVersion.v33
68+
69+
70+
val newStaticSynchronizerParameters =
71+
StaticSynchronizerParameters.defaultsWithoutKMS(protocolVersion = testedProtocolVersion)
72+
73+
migrateNode(
74+
migratedNode = sequencer1,
75+
newStaticSynchronizerParameters = newStaticSynchronizerParameters,
76+
synchronizerId = synchronizerId,
77+
newSequencers = Seq(sequencer1),
78+
dars = Seq(),
79+
exportDirectory = better.files.File(synchronizerDir),
80+
)
81+
82+
migrateNode(
83+
migratedNode = mediator1,
84+
newStaticSynchronizerParameters = newStaticSynchronizerParameters,
85+
synchronizerId = synchronizerId,
86+
newSequencers = Seq(sequencer1),
87+
dars = Seq(),
88+
exportDirectory = better.files.File(synchronizerDir),
89+
)
90+
91+
92+
// start all local instances defined in the configuration file
93+
94+
nodes.local.start()
95+
96+
bootstrap.synchronizer(
97+
synchronizerName = "wallet",
98+
sequencers = Seq(sequencer1),
99+
mediators = Seq(mediator1),
100+
synchronizerOwners = Seq(sequencer1),
101+
synchronizerThreshold = PositiveInt.one,
102+
staticSynchronizerParameters = StaticSynchronizerParameters.defaultsWithoutKMS(ProtocolVersion.forSynchronizer),
103+
)
104+
105+
106+
107+
// Connect participant1 to wallet using the connect macro.
108+
// The connect macro will inspect the synchronizer configuration to find the correct URL and Port.
109+
// The macro is convenient for local testing, but obviously doesn't work in a distributed setup.
110+
participant1.synchronizers.connect_local(sequencer1, alias = "wallet")
111+
112+
utils.retry_until_true {
113+
participant1.synchronizers.active("wallet")
114+
}
115+
116+
117+
logger.info(s"WALLET-KERNEL-BOOTSTRAP: Creating operator user and party")
118+
val operatorParty = participant1.ledger_api.parties.allocate("operator").party
119+
120+
participant1.ledger_api.users.create(id = "operator", actAs = Set(operatorParty), readAs = Set(operatorParty), primaryParty = Some(operatorParty), participantAdmin = false, isDeactivated = false, annotations = Map("foo" -> "bar", "description" -> "This is a description"))
121+
122+
logger.info(s"WALLET-KERNEL-BOOTSTRAP: created operator user and party")
123+
124+
125+
126+
def initializeSequencer(
127+
migrated: SequencerReference,
128+
genesisState: ByteString,
129+
staticSynchronizerParameters: StaticSynchronizerParameters,
130+
): Unit = {
131+
migrated.health.wait_for_ready_for_initialization()
132+
migrated.setup.assign_from_genesis_state(
133+
genesisState,
134+
staticSynchronizerParameters,
135+
)
136+
137+
migrated.health.initialized()
138+
139+
}
140+
141+
def migrateNode(
142+
migratedNode: InstanceReference with ConsoleCommandGroup,
143+
newStaticSynchronizerParameters: StaticSynchronizerParameters,
144+
synchronizerId: SynchronizerId,
145+
newSequencers: Seq[SequencerReference],
146+
dars: Seq[String],
147+
sequencerTrustThreshold: PositiveInt = PositiveInt.one,
148+
exportDirectory: File,
149+
): Unit = {
150+
val files = UpgradeDataFiles.from(migratedNode.name, exportDirectory)
151+
152+
files.keys.foreach { case (keys, name) =>
153+
migratedNode.keys.secret.upload(keys, name)
154+
}
155+
migratedNode.topology.init_id_from_uid(files.uid)
156+
migratedNode.health.wait_for_ready_for_node_topology()
157+
migratedNode.topology.transactions
158+
.import_topology_snapshot(files.authorizedStore, TopologyStoreId.Authorized)
159+
160+
migratedNode match {
161+
case newSequencer: SequencerReference =>
162+
initializeSequencer(newSequencer, files.genesisState, newStaticSynchronizerParameters)
163+
164+
case newMediator: MediatorReference =>
165+
newMediator.setup.assign(
166+
synchronizerId,
167+
SequencerConnections.tryMany(
168+
newSequencers
169+
.map(s => s.sequencerConnection.withAlias(SequencerAlias.tryCreate(s.name))),
170+
sequencerTrustThreshold,
171+
SubmissionRequestAmplification.NoAmplification,
172+
),
173+
)
174+
175+
case newParticipant: ParticipantReference =>
176+
val node = newParticipant
177+
// user-manual-entry-begin: WaitForParticipantInitialization
178+
node.health.wait_for_initialized()
179+
// user-manual-entry-end: WaitForParticipantInitialization
180+
dars.foreach(dar => newParticipant.dars.upload(dar))
181+
182+
case _ =>
183+
throw new IllegalStateException(
184+
s"Unsupported migration from $files to $migratedNode"
185+
)
186+
}
187+
}
188+
189+
final case class UpgradeDataFiles(
190+
uidFile: File,
191+
keyFiles: Seq[File],
192+
authorizedStoreFile: File,
193+
acsSnapshotFile: File,
194+
genesisStateFile: File,
195+
) {
196+
def uid: UniqueIdentifier =
197+
UniqueIdentifier.tryFromProtoPrimitive(
198+
uidFile.contentAsString
199+
)
200+
201+
def keys: Seq[(ByteString, Option[String])] =
202+
keyFiles.map { file =>
203+
val key = BinaryFileUtil.tryReadByteStringFromFile(file.canonicalPath)
204+
val name = file.name.stripSuffix(".keys")
205+
key -> Option(name)
206+
}
207+
208+
def authorizedStore: ByteString =
209+
BinaryFileUtil.tryReadByteStringFromFile(authorizedStoreFile.canonicalPath)
210+
211+
def genesisState: ByteString =
212+
BinaryFileUtil.tryReadByteStringFromFile(genesisStateFile.canonicalPath)
213+
}
214+
215+
object UpgradeDataFiles {
216+
def from(nodeName: String, baseDirectory: File): UpgradeDataFiles = {
217+
val keys =
218+
baseDirectory.list
219+
.filter(file => file.name.startsWith(nodeName) && file.name.endsWith(".keys"))
220+
.toList
221+
UpgradeDataFiles(
222+
uidFile = baseDirectory / s"$nodeName-uid",
223+
keyFiles = keys,
224+
authorizedStoreFile = baseDirectory / s"$nodeName-authorized-store",
225+
acsSnapshotFile = baseDirectory / s"$nodeName-acs-snapshot",
226+
genesisStateFile = baseDirectory / s"$nodeName-genesis-state",
227+
)
228+
}
229+
}

canton/devnet/canton.conf

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
canton {
2+
3+
features.enable-testing-commands = yes
4+
features.enable-preview-commands = yes
5+
6+
sequencers {
7+
sequencer1 {
8+
init = {
9+
generate-topology-transactions-and-keys = false
10+
identity.type = manual
11+
}
12+
storage.type = memory
13+
public-api.port = 5001
14+
admin-api.port = 5002
15+
}
16+
}
17+
18+
mediators {
19+
mediator1 {
20+
init = {
21+
generate-topology-transactions-and-keys = false
22+
identity.type = manual
23+
}
24+
storage.type = memory
25+
admin-api.port = 5202
26+
}
27+
}
28+
29+
participants {
30+
// user-manual-entry-begin: port configuration
31+
32+
participant1 {
33+
init = {
34+
generate-topology-transactions-and-keys = false
35+
identity.type = manual
36+
}
37+
storage.type = memory
38+
admin-api.port = 5012
39+
ledger-api.port = 5011
40+
http-ledger-api.server.port = 5003
41+
ledger-api.auth-services = [{
42+
type = jwt-jwks
43+
url = "http://127.0.0.1:8889/jwks"
44+
}]
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)