Skip to content

Commit d398309

Browse files
[static] working in logs but missing test + cleanups
Signed-off-by: Julien Tinguely <[email protected]>
1 parent b981110 commit d398309

File tree

9 files changed

+78
-33
lines changed

9 files changed

+78
-33
lines changed
Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
package org.lfdecentralizedtrust.splice.integration.tests
22

3-
import org.lfdecentralizedtrust.splice.integration.tests.SpliceTests.IntegrationTestWithSharedEnvironment
3+
import com.digitalasset.canton.HasExecutionContext
4+
import com.digitalasset.canton.topology.admin.grpc.TopologyStoreId
5+
import com.digitalasset.canton.topology.store.TimeQuery
46
import org.lfdecentralizedtrust.splice.integration.EnvironmentDefinition
5-
import org.lfdecentralizedtrust.splice.integration.tests.WalletTxLogTestUtil
7+
import org.lfdecentralizedtrust.splice.integration.tests.SpliceTests.IntegrationTestWithSharedEnvironment
68
import org.lfdecentralizedtrust.splice.util.WalletTestUtil
7-
import com.digitalasset.canton.HasExecutionContext
8-
99

1010
class ManualSignatureIntegrationTest
1111
extends IntegrationTestWithSharedEnvironment
1212
with HasExecutionContext
1313
with WalletTestUtil
1414
with WalletTxLogTestUtil {
1515

16+
override lazy val resetRequiredTopologyState = false
17+
1618
override def environmentDefinition: EnvironmentDefinition = {
1719
EnvironmentDefinition
1820
.simpleTopology1Sv(this.getClass.getSimpleName)
@@ -24,6 +26,20 @@ class ManualSignatureIntegrationTest
2426

2527
"rotate signatures" in { implicit env =>
2628
sv1Backend.startSync()
29+
eventually() {
30+
val synchronizerId = sv1Backend.participantClientWithAdminToken.synchronizers.id_of(
31+
sv1Backend.config.domains.global.alias
32+
)
33+
// FIXME: SV: add checks for mediator, sequencer and participant signatures + add checks
34+
val store = TopologyStoreId.Synchronizer(synchronizerId)
35+
sv1Backend.participantClientWithAdminToken.topology.owner_to_key_mappings
36+
.list(store = Some(store), timeQuery = TimeQuery.Range(None, None))
37+
.filter(
38+
_.item.member.toProtoPrimitive == sv1Backend.sequencerClient.name
39+
) should not be empty
40+
// FIXME: Validator: add checks for validator signatures + add checks
41+
}
2742
}
43+
2844
}
2945
}

apps/common/src/main/scala/org/lfdecentralizedtrust/splice/setup/NodeInitializer.scala

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ package org.lfdecentralizedtrust.splice.setup
66
import cats.implicits.showInterpolator
77
import com.daml.nonempty.NonEmpty
88
import com.digitalasset.canton.admin.api.client.data.{NodeStatus, WaitingForId}
9-
import com.digitalasset.canton.crypto.{EncryptionPublicKey, SigningKeyUsage, SigningPublicKey}
9+
import com.digitalasset.canton.crypto.{SigningKeyUsage, SigningPublicKey}
1010
import com.digitalasset.canton.logging.{NamedLoggerFactory, NamedLogging}
11-
import com.digitalasset.canton.topology.store.TimeQuery
1211
import com.digitalasset.canton.topology.store.TopologyStoreId.AuthorizedStore
12+
import com.digitalasset.canton.topology.store.{TimeQuery, TopologyStoreId}
1313
import com.digitalasset.canton.topology.transaction.OwnerToKeyMapping
14-
import com.digitalasset.canton.topology.{Member, Namespace, NodeIdentity, UniqueIdentifier}
14+
import com.digitalasset.canton.topology.*
1515
import com.digitalasset.canton.tracing.TraceContext
1616
import com.digitalasset.canton.util.MonadUtil
1717
import com.google.protobuf.ByteString
@@ -104,6 +104,7 @@ class NodeInitializer(
104104
def initializeWithNewIdentityIfNeeded(
105105
idenfitierName: String,
106106
nodeIdentity: UniqueIdentifier => Member & NodeIdentity,
107+
synchronizerId: SynchronizerId,
107108
)(implicit tc: TraceContext, ec: ExecutionContext): Future[Unit] = {
108109
logger.info(s"Making sure canton node has an identity")
109110
for {
@@ -127,7 +128,7 @@ class NodeInitializer(
127128
)
128129
for {
129130
// rotate existing keys that are not signed by owner
130-
_ <- rotateOwnerToKeyMappingNotSignedByKeys(id, nodeIdentity)
131+
_ <- rotateOwnerToKeyMappingNotSignedByKeys(id, nodeIdentity, synchronizerId)
131132
// fixes previously initialized nodes with messed up keys
132133
_ <- rotateSigningKeyIfSameAsNamespaceKey(id, nodeIdentity)
133134
} yield ()
@@ -322,27 +323,39 @@ class NodeInitializer(
322323
private def rotateOwnerToKeyMappingNotSignedByKeys(
323324
id: UniqueIdentifier,
324325
nodeIdentity: UniqueIdentifier => Member & NodeIdentity,
326+
synchronizerId: SynchronizerId,
325327
)(implicit tc: TraceContext, ec: ExecutionContext): Future[Unit] =
326328
for {
327-
ownerToKeyMappingHistory <- connection.listOwnerToKeyMapping(
328-
nodeIdentity(id),
329-
TimeQuery.Range(None, None),
329+
// FIXME: clean this logic
330+
fullTxHistory <- connection.listAllTransactions(
331+
store = TopologyStoreId.SynchronizerStore(synchronizerId),
332+
timeQuery = TimeQuery.Range(None, None),
333+
includeMappings = Set(OwnerToKeyMapping.code),
330334
)
331-
latestKeys = ownerToKeyMappingHistory
332-
.sortBy(_.base.serial)
335+
ownerToKeyMappingTxHistory = fullTxHistory.filter(_.transaction.mapping match {
336+
case mapping: OwnerToKeyMapping if mapping.member == nodeIdentity(id) => true
337+
case _ => false
338+
})
339+
_ = logger.info(s"YOHOU: $ownerToKeyMappingTxHistory")
340+
allOtkSignatures = ownerToKeyMappingTxHistory
341+
.map(_.transaction)
342+
.flatMap(_.signatures)
343+
.map(_.signedBy)
344+
.distinct
345+
latestKeys = ownerToKeyMappingTxHistory
346+
.map(_.transaction)
347+
.sortBy(_.transaction.serial)
333348
.lastOption
334349
.getOrElse(throw new IllegalStateException("ownerToKeyMappingHistory is empty."))
335-
.mapping
336-
.keys
337-
.filter {
338-
case _: SigningPublicKey => true
339-
case _ => false
340-
}
341-
allSignedBy = ownerToKeyMappingHistory.flatMap(_.base.signedBy).distinct
342-
(_, toRotate) = latestKeys.map(_.id).partition(allSignedBy.contains)
343-
_ = logger.info(
344-
s"Keys that are not signed by the owner: ${toRotate.mkString(", ")}"
345-
)
350+
.mapping match {
351+
case mapping: OwnerToKeyMapping =>
352+
mapping.keys.filter {
353+
case _: SigningPublicKey => true
354+
case _ => false
355+
}
356+
case _ => throw new IllegalStateException("Latest transaction is not an OwnerToKeyMapping.")
357+
}
358+
(_, toRotate) = latestKeys.map(_.id).partition(allOtkSignatures.contains)
346359
_ = if (toRotate.nonEmpty) {
347360
logger.info(s"keyToRotate: ${toRotate}")
348361
val rotatedKeys = latestKeys.map {
@@ -351,10 +364,6 @@ class NodeInitializer(
351364
key.keySpec.name,
352365
key.usage,
353366
)
354-
case key: EncryptionPublicKey if toRotate.contains(key.id) =>
355-
connection.generateEncryptionKeyPair(
356-
key.keySpec.name
357-
)
358367
case key => Future.successful(key)
359368
}
360369
for {

apps/common/src/main/scala/org/lfdecentralizedtrust/splice/setup/ParticipantInitializer.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
package org.lfdecentralizedtrust.splice.setup
55

6+
import com.digitalasset.canton.SynchronizerAlias
67
import org.lfdecentralizedtrust.splice.config.ParticipantBootstrapDumpConfig
78
import org.lfdecentralizedtrust.splice.environment.{ParticipantAdminConnection, RetryProvider}
89
import org.lfdecentralizedtrust.splice.identities.NodeIdentitiesDump
@@ -23,6 +24,7 @@ object ParticipantInitializer {
2324
dumpConfig: Option[ParticipantBootstrapDumpConfig],
2425
loggerFactory: NamedLoggerFactory,
2526
retryProvider: RetryProvider,
27+
synchronizerAlias: SynchronizerAlias,
2628
)(implicit
2729
ec: ExecutionContextExecutor,
2830
tc: TraceContext,
@@ -33,6 +35,7 @@ object ParticipantInitializer {
3335
loggerFactory,
3436
retryProvider,
3537
participantAdminConnection,
38+
synchronizerAlias,
3639
)
3740
participantInitializer
3841
.ensureInitializedWithExpectedId()
@@ -62,6 +65,7 @@ class ParticipantInitializer(
6265
override protected val loggerFactory: NamedLoggerFactory,
6366
retryProvider: RetryProvider,
6467
participantAdminConnection: ParticipantAdminConnection,
68+
synchronizerAlias: SynchronizerAlias,
6569
)(implicit
6670
ec: ExecutionContextExecutor,
6771
tc: TraceContext,
@@ -84,9 +88,11 @@ class ParticipantInitializer(
8488
case None =>
8589
logger.info(s"Initializing participant $identifierName")
8690
for {
91+
synchronizerId <- participantAdminConnection.getSynchronizerId(synchronizerAlias)
8792
_ <- nodeInitializer.initializeWithNewIdentityIfNeeded(
8893
identifierName,
8994
ParticipantId.apply,
95+
synchronizerId,
9096
)
9197
_ <- nodeInitializer.waitForNodeInitialized()
9298
} yield {

apps/sv/src/main/scala/org/lfdecentralizedtrust/splice/sv/SvApp.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ class SvApp(
176176
config.participantBootstrappingDump,
177177
loggerFactory,
178178
retryProvider,
179+
config.domains.global.alias,
179180
)
180181
}
181182
}

apps/sv/src/main/scala/org/lfdecentralizedtrust/splice/sv/onboarding/SynchronizerNodeInitializer.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import org.lfdecentralizedtrust.splice.sv.LocalSynchronizerNode
99
import org.lfdecentralizedtrust.splice.sv.config.SvCantonIdentifierConfig
1010
import com.digitalasset.canton.logging.NamedLoggerFactory
1111
import com.digitalasset.canton.time.Clock
12-
import com.digitalasset.canton.topology.{MediatorId, SequencerId}
12+
import com.digitalasset.canton.topology.{MediatorId, SequencerId, SynchronizerId}
1313
import com.digitalasset.canton.tracing.TraceContext
1414

1515
import scala.concurrent.{ExecutionContext, Future}
@@ -40,6 +40,7 @@ object SynchronizerNodeInitializer {
4040
clock: Clock,
4141
logger: NamedLoggerFactory,
4242
retryProvider: RetryProvider,
43+
synchronizerId: SynchronizerId,
4344
)(implicit tc: TraceContext, ec: ExecutionContext): Future[Unit] = {
4445
val synchronizerNodeInitializer = SynchronizerNodeInitializer(
4546
synchronizerNode,
@@ -52,10 +53,12 @@ object SynchronizerNodeInitializer {
5253
_ <- synchronizerNodeInitializer.sequencerInitializer.initializeWithNewIdentityIfNeeded(
5354
identifierConfig.sequencer,
5455
SequencerId.apply,
56+
synchronizerId,
5557
)
5658
_ <- synchronizerNodeInitializer.mediatorInitializer.initializeWithNewIdentityIfNeeded(
5759
identifierConfig.mediator,
5860
MediatorId.apply,
61+
synchronizerId,
5962
)
6063
} yield ()
6164
}

apps/sv/src/main/scala/org/lfdecentralizedtrust/splice/sv/onboarding/joining/JoiningNodeInitializer.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ class JoiningNodeInitializer(
312312
clock,
313313
loggerFactory,
314314
retryProvider,
315+
decentralizedSynchronizerId,
315316
)
316317
)
317318
} else {

apps/sv/src/main/scala/org/lfdecentralizedtrust/splice/sv/onboarding/sv1/SV1Initializer.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class SV1Initializer(
143143
cantonIdentifierConfig = config.cantonIdentifierConfig.getOrElse(
144144
SvCantonIdentifierConfig.default(config)
145145
)
146+
synchronizerId <- participantAdminConnection.getSynchronizerId(config.domains.global.alias)
146147
_ <-
147148
if (!config.skipSynchronizerInitialization) {
148149
SynchronizerNodeInitializer.initializeLocalCantonNodesWithNewIdentities(
@@ -151,6 +152,7 @@ class SV1Initializer(
151152
clock,
152153
loggerFactory,
153154
retryProvider,
155+
synchronizerId,
154156
)
155157
} else {
156158
logger.info(

apps/validator/src/main/scala/org/lfdecentralizedtrust/splice/validator/ValidatorApp.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ class ValidatorApp(
175175
config.participantBootstrappingDump,
176176
loggerFactory,
177177
retryProvider,
178+
config.domains.global.alias,
178179
)
179180
}
180181
}

bootstrap-canton.sc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ import com.digitalasset.canton.topology.transaction.SignedTopologyTransaction.Ge
1717
import com.digitalasset.canton.topology.transaction.TopologyChangeOp
1818
import com.digitalasset.canton.version.ProtocolVersion
1919
import com.digitalasset.canton.console.commands.TopologyAdministrationGroup
20-
import com.digitalasset.canton.topology.store.{StoredTopologyTransaction, StoredTopologyTransactions}
20+
import com.digitalasset.canton.topology.store.{
21+
StoredTopologyTransaction,
22+
StoredTopologyTransactions,
23+
}
2124
import com.digitalasset.canton.topology.processing.{EffectiveTime, SequencedTime}
2225
import com.digitalasset.canton.sequencing.SequencerConnectionValidation
2326
import com.digitalasset.canton.discard.Implicits.DiscardOps
@@ -31,7 +34,8 @@ val domainParametersConfig = SynchronizerParametersConfig(
3134
def dropSignatures(tx: GenericSignedTopologyTransaction): GenericSignedTopologyTransaction = {
3235
tx.transaction.mapping match {
3336
case OwnerToKeyMapping(member, _) =>
34-
val signaturesToRemove = tx.signatures.forgetNE.filter(_.signedBy != member.namespace.fingerprint).map(_.signedBy)
37+
val signaturesToRemove =
38+
tx.signatures.forgetNE.filter(_.signedBy != member.namespace.fingerprint).map(_.signedBy)
3539
tx.removeSignatures(signaturesToRemove).get
3640
case _ => tx
3741
}
@@ -43,11 +47,12 @@ def staticParameters(sequencer: LocalInstanceReference) =
4347
.map(StaticSynchronizerParameters(_))
4448
.getOrElse(sys.error("whatever"))
4549

50+
// FIXME: replace this by original code and put that into a separate file or under new flag
4651
def bootstrapOtherDomain(
4752
name: String,
4853
sequencer: LocalSequencerReference,
4954
mediator: LocalMediatorReference,
50-
extraParticipant : LocalInstanceReference,
55+
extraParticipant: LocalInstanceReference,
5156
) = {
5257
// first synchronizer method
5358
val synchronizerName = name
@@ -114,7 +119,8 @@ def bootstrapOtherDomain(
114119
.mapFilter(_.selectOp[TopologyChangeOp.Replace])
115120
.distinct
116121

117-
val merged = SignedTopologyTransactions.compact(initialTopologyState).map(_.updateIsProposal(false))
122+
val merged =
123+
SignedTopologyTransactions.compact(initialTopologyState).map(_.updateIsProposal(false))
118124

119125
val storedTopologySnapshot = StoredTopologyTransactions[TopologyChangeOp, TopologyMapping](
120126
merged.map(stored =>

0 commit comments

Comments
 (0)