Skip to content

Commit

Permalink
Update Splice from CCI (#256)
Browse files Browse the repository at this point in the history
Signed-off-by: DA Automation <[email protected]>
Co-authored-by: DA Automation <[email protected]>
  • Loading branch information
canton-network-da and DA Automation authored Jan 16, 2025
1 parent be8e098 commit d5f9f82
Show file tree
Hide file tree
Showing 30 changed files with 264 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ object ConfigTransforms {
def bumpSvAppCantonDomainPortsBy(bump: Int): ConfigTransform = {
updateAllSvAppConfigs_(
_.focus(_.domains.global.url)
.modify(bumpUrl(bump, _))
.modify(_.map(bumpUrl(bump, _)))
.focus(_.localSynchronizerNode)
.modify(
_.map(d =>
Expand Down Expand Up @@ -444,7 +444,7 @@ object ConfigTransforms {
if (svApps.contains(name)) {
config
.focus(_.domains.global.url)
.modify(bumpUrl(bump, _))
.modify(_.map(bumpUrl(bump, _)))
.focus(_.localSynchronizerNode)
.modify(
_.map(d =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,9 @@ object SpliceConfig {
// sv1 must alway configure one to bootstrap the domain.
val sv1NodeHasSynchronizerConfig =
checkFoundDsoConfig((conf, _) => conf.localSynchronizerNode.isDefined)
// SV1 only ever connects to its own sequencer so the url is specified in the localSynchronizerNode config
val sv1NodeHasNoSequencerUrl =
checkFoundDsoConfig((conf, _) => conf.domains.global.url.isEmpty)
val initialPackageConfigExists =
checkFoundDsoConfig((_, foundDsoConf) =>
doesInitialPackageConfigExists(foundDsoConf.initialPackageConfig)
Expand All @@ -517,6 +520,11 @@ object SpliceConfig {
(),
ConfigValidationFailed("SV1 must always specify a domain config"),
)
_ <- Either.cond(
sv1NodeHasNoSequencerUrl,
(),
ConfigValidationFailed("SV1 must not specify domains.global.url"),
)
_ <- Either.cond(
initialPackageConfigExists,
(),
Expand Down

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions apps/app/src/test/resources/include/svs/sv1.conf
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,5 @@
sequencer = "sv1"
mediator = "sv1"
}
domains.global.url = null
}
1 change: 0 additions & 1 deletion apps/app/src/test/resources/local-sv-node/sv-app/app.conf
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ _sv {
domains {
global {
alias = "global"
url = "http://localhost:9108"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class DisasterRecoveryIntegrationTest
SvDecentralizedSynchronizerConfig(
alias = DomainAlias.tryCreate("global"),
// changing the domain config since for a domain migration SVs connect directly to their own sequencer instead of SV1's sequencer.
url = s"http://localhost:28${sv}08",
url = Some(s"http://localhost:28${sv}08"),
)
),
domainMigrationId = 1L,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,18 @@ import org.lfdecentralizedtrust.splice.util.StandaloneCanton

import java.nio.file.{Path, Paths}

class ParticipantIdentitiesExportIntegrationTest
class ParticipantKmsIdentitiesIntegrationTest
extends ParticipantIdentitiesImportTestBase
with StandaloneCanton {

override def dbsSuffix = "kms"

override def aliceParticipantDumpFilename =
ParticipantIdentitiesExportIntegrationTest.aliceKmsIdIdentityDumpFilePath
ParticipantKmsIdentitiesIntegrationTest.aliceKmsIdentitiesDumpFilePath

"We can export Canton participant identities dumps" in { implicit env =>
startAllSync(sv1Backend, sv1ScanBackend, sv1ValidatorBackend, aliceValidatorBackend)

val svParticipantDump = clue("Getting participant identities dump from SV1") {
sv1ValidatorBackend.dumpParticipantIdentities()
}

clue("Checking exported key names") {
val keyNames = svParticipantDump.keys.map(_.name.value)
val prefix = "sv1Participant"
keyNames should contain(s"$prefix-namespace")
keyNames should contain(s"$prefix-signing")
keyNames should contain(s"$prefix-encryption")
}

val validatorParticipantDump =
clue("Getting participant identities dump from Alice's validator") {
aliceValidatorBackend.dumpParticipantIdentities()
}

clue("Checking exported key names") {
val keyNames = validatorParticipantDump.keys.map(_.name.value)
val prefix = "aliceParticipant"
keyNames should contain(s"$prefix-namespace")
keyNames should contain(s"$prefix-signing")
keyNames should contain(s"$prefix-encryption")
}
}

"We can export and import Canton participant identities dumps with kms enabled" in {
"We can import and export Canton participant identities dumps with kms enabled" in {
implicit env =>
startAllSync(
sv1Backend,
sv1ScanBackend,
sv1ValidatorBackend,
)
startAllSync(sv1Backend, sv1ScanBackend, sv1ValidatorBackend)

withCanton(
Seq(
Expand All @@ -71,7 +38,7 @@ class ParticipantIdentitiesExportIntegrationTest
) {
val predefinedDump = NodeIdentitiesDump
.fromJsonFile(
ParticipantIdentitiesExportIntegrationTest.aliceKmsIdIdentityDumpFilePath,
ParticipantKmsIdentitiesIntegrationTest.aliceKmsIdentitiesDumpFilePath,
ParticipantId.tryFromProtoPrimitive,
)
.value
Expand Down Expand Up @@ -110,7 +77,7 @@ class ParticipantIdentitiesExportIntegrationTest
}
}

object ParticipantIdentitiesExportIntegrationTest {
object ParticipantKmsIdentitiesIntegrationTest {
val testDumpDir: Path = Paths.get("apps/app/src/test/resources/dumps")
val aliceKmsIdIdentityDumpFilePath = testDumpDir.resolve("alice-kms-id-identity-dump.json")
val aliceKmsIdentitiesDumpFilePath = testDumpDir.resolve("alice-kms-id-identity-dump.json")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.lfdecentralizedtrust.splice.integration.tests

import com.digitalasset.canton.topology.ParticipantId
import org.lfdecentralizedtrust.splice.identities.NodeIdentitiesDump
import org.lfdecentralizedtrust.splice.util.StandaloneCanton

import java.nio.file.{Path, Paths}

class ParticipantPlaintextIdentitiesIntegrationTest
extends ParticipantIdentitiesImportTestBase
with StandaloneCanton {

override def dbsSuffix = "plaintext"

override def aliceParticipantDumpFilename =
ParticipantPlaintextIdentitiesIntegrationTest.alicePlaintextIdentitiesDumpFilePath

"We can import and export Canton participant identities dumps with plaintext keys in them" in {
implicit env =>
startAllSync(sv1Backend, sv1ScanBackend, sv1ValidatorBackend)

val svParticipantDump = clue("Getting participant identities dump from SV1") {
sv1ValidatorBackend.dumpParticipantIdentities()
}

clue("Checking exported key names for SV1") {
val keyNames = svParticipantDump.keys.map(_.name.value)
val prefix = "sv1Participant"
keyNames should contain(s"$prefix-namespace")
keyNames should contain(s"$prefix-signing")
keyNames should contain(s"$prefix-encryption")
}

withCanton(
Seq(
testResourcesPath / "standalone-participant-extra.conf",
testResourcesPath / "standalone-participant-extra-no-auth.conf",
),
Seq(),
"alice-plaintext-participant",
"EXTRA_PARTICIPANT_ADMIN_USER" -> aliceValidatorLocalBackend.config.ledgerApiUser,
"EXTRA_PARTICIPANT_DB" -> "participant_extra_plaintext",
) {
val predefinedDump = NodeIdentitiesDump
.fromJsonFile(
ParticipantPlaintextIdentitiesIntegrationTest.alicePlaintextIdentitiesDumpFilePath,
ParticipantId.tryFromProtoPrimitive,
)
.value

clue("start validator with predefined dump") {
aliceValidatorLocalBackend.startSync()
}

val validatorParticipantDump =
clue("Getting participant identities dump from Alice's validator") {
aliceValidatorLocalBackend.dumpParticipantIdentities()
}

clue("Checking exported keys for Alice's validator") {
validatorParticipantDump.keys.toSet shouldBe predefinedDump.keys.toSet
}
}
}
}

object ParticipantPlaintextIdentitiesIntegrationTest {
val testDumpDir: Path = Paths.get("apps/app/src/test/resources/dumps")
val alicePlaintextIdentitiesDumpFilePath =
testDumpDir.resolve("alice-plaintext-id-identity-dump.json")
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,12 @@ class SvOnboardingViaNonFoundingSvIntegrationTest
case _ => throw new IllegalStateException("JoinWithKey configuration not found.")
}
val sv2BootstrapSequencerUrl =
bumpUrl(
sv1ToSv2Bump,
configuration
.svApps(InstanceName.tryCreate("sv2"))
.domains
.global
.url,
)
configuration
.svApps(InstanceName.tryCreate("sv2"))
.domains
.global
.url
.map(bumpUrl(sv1ToSv2Bump, _))
ConfigTransforms.updateAllSvAppConfigs { (name, config) =>
if (name == "sv3") {
config.copy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ class SubmitSvStatusReportTrigger(
statusReport <- store.getSvStatusReport(store.key.svParty)
openMiningRounds <- store.getOpenMiningRoundTriple()
cometBftHeight <- cometBft.traverse(_.getLatestBlockHeight())
// TODO(#17018) Switch to per-synchronizer SV status reports
mediatorAdminConnection = SvUtil.getMediatorAdminConnection(
dsoRules.domain,
mediatorAdminConnectionO,
extraSynchronizerNodes,
)
// TODO(#10297): make this code work properly with multiple mediators in the case of soft-domain migration
mediatorSynchronizerTimeLb <- getDomainTimeLowerBound(
mediatorAdminConnection,
dsoRules.domain,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,10 @@ final case class SynchronizerFeesConfig(

final case class SvDecentralizedSynchronizerConfig(
alias: DomainAlias,
url: String,
/** This must be set for SVs that onboard to initiallly connect to their sponsoring SV’s sequencer.
* Afterwards it can be unset.
*/
url: Option[String],

/** amount of extra traffic reserved for high priority transactions
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,19 @@ class JoiningNodeInitializer(
// We need to connect to the domain here because otherwise we create a circular dependency
// with the validator app: The validator app waits for its user to be provisioned (which happens in createValidatorUser)
// before establishing a domain connection, but allocating the SV party requires a domain connection.
val domainConfig = DomainConnectionConfig(
config.domains.global.alias,
SequencerConnections.single(
GrpcSequencerConnection.tryCreate(config.domains.global.url)
),
// Set manualConnect = true to avoid any issues with interrupted SV onboardings.
// This is changed to false after SV onboarding completes.
manualConnect = true,
timeTracker = DomainTimeTrackerConfig(
minObservationDuration = config.timeTrackerMinObservationDuration
),
val domainConfigO = config.domains.global.url.map(url =>
DomainConnectionConfig(
config.domains.global.alias,
SequencerConnections.single(
GrpcSequencerConnection.tryCreate(url)
),
// Set manualConnect = true to avoid any issues with interrupted SV onboardings.
// This is changed to false after SV onboarding completes.
manualConnect = true,
timeTracker = DomainTimeTrackerConfig(
minObservationDuration = config.timeTrackerMinObservationDuration
),
)
)
for {
(dsoPartyId, darUploads) <- (
Expand All @@ -156,9 +158,13 @@ class JoiningNodeInitializer(
for {
// Register domain with manualConnect=true. Confusingly, this still connects the first time.
// However, it won't connect if we crash and get here again which is what we're really after.
_ <- participantAdminConnection.ensureDomainRegisteredNoHandshake(
domainConfig,
RetryFor.WaitingOnInitDependency,
// If the url is unset, we skip this step. This is fine if the node has already initialized its
// own sequencer.
_ <- domainConfigO.traverse_(
participantAdminConnection.ensureDomainRegisteredNoHandshake(
_,
RetryFor.WaitingOnInitDependency,
)
)
// Have the uploads run in the background while we setup the sv party to save time
} yield participantAdminConnection.uploadDarFiles(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import org.lfdecentralizedtrust.splice.util.{
}
import org.lfdecentralizedtrust.splice.util.SpliceUtil.{defaultAmuletConfig, defaultAnsConfig}
import com.daml.nonempty.NonEmpty
import com.digitalasset.canton.SequencerAlias
import com.digitalasset.canton.config.DomainTimeTrackerConfig
import com.digitalasset.canton.config.RequireTypes.{NonNegativeInt, PositiveInt}
import com.digitalasset.canton.data.CantonTimestamp
Expand Down Expand Up @@ -151,11 +152,17 @@ class SV1Initializer(
)
(namespace, domainId) <- bootstrapDomain(localSynchronizerNode)
_ = logger.info("Domain is bootstrapped, connecting sv1 participant to domain")
internalSequencerApi = localSynchronizerNode.sequencerInternalConfig
_ <- participantAdminConnection.ensureDomainRegisteredAndConnected(
DomainConnectionConfig(
config.domains.global.alias,
sequencerConnections = SequencerConnections.single(
GrpcSequencerConnection.tryCreate(config.domains.global.url)
new GrpcSequencerConnection(
NonEmpty.mk(Seq, LocalSynchronizerNode.toEndpoint(internalSequencerApi)),
transportSecurity = internalSequencerApi.tls.isDefined,
customTrustCertificates = None,
SequencerAlias.Default,
)
),
manualConnect = false,
domainId = None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ import org.lfdecentralizedtrust.splice.environment.{DarResources, RetryProvider}
import org.lfdecentralizedtrust.splice.migration.DomainMigrationInfo
import org.lfdecentralizedtrust.splice.store.{Limit, MiningRoundsStore, PageLimit, StoreTest}
import org.lfdecentralizedtrust.splice.store.MultiDomainAcsStore.QueryResult
import org.lfdecentralizedtrust.splice.sv.config.{
SvDecentralizedSynchronizerConfig,
SvSynchronizerConfig,
}
import org.lfdecentralizedtrust.splice.store.events.DsoRulesCloseVoteRequest
import org.lfdecentralizedtrust.splice.sv.store.db.DbSvDsoStore
import org.lfdecentralizedtrust.splice.sv.store.SvDsoStore.{
Expand Down Expand Up @@ -1496,9 +1492,6 @@ abstract class SvDsoStoreTest extends StoreTest with HasExecutionContext {
lazy val acsOffset = nextOffset()
lazy val domain = dummyDomain.toProtoPrimitive
lazy val storeSvParty = providerParty(42)
lazy val svSynchronizerConfig = SvSynchronizerConfig(
SvDecentralizedSynchronizerConfig(DomainAlias.tryCreate(domain), "https://example.com")
)
}

class DbSvDsoStoreTest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ import org.lfdecentralizedtrust.splice.environment.{DarResources, RetryProvider}
import org.lfdecentralizedtrust.splice.migration.DomainMigrationInfo
import org.lfdecentralizedtrust.splice.store.MultiDomainAcsStore.QueryResult
import org.lfdecentralizedtrust.splice.store.StoreTest
import org.lfdecentralizedtrust.splice.sv.config.{
SvDecentralizedSynchronizerConfig,
SvSynchronizerConfig,
}
import org.lfdecentralizedtrust.splice.sv.store.db.DbSvSvStore
import org.lfdecentralizedtrust.splice.sv.store.{SvStore, SvSvStore}
import org.lfdecentralizedtrust.splice.util.{ResourceTemplateDecoder, TemplateJsonDecoder}
Expand Down Expand Up @@ -127,9 +123,6 @@ abstract class SvSvStoreTest extends StoreTest with HasExecutionContext {
lazy val acsOffset = nextOffset()
lazy val domain = dummyDomain.toProtoPrimitive
lazy val storeSvParty = providerParty(42)
lazy val svSynchronizerConfig = SvSynchronizerConfig(
SvDecentralizedSynchronizerConfig(DomainAlias.tryCreate(domain), "https://example.com")
)
}

class DbSvSvStoreTest
Expand Down
1 change: 0 additions & 1 deletion cluster/compose/sv/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ services:
}
}
}
- SPLICE_APP_SV_GLOBAL_DOMAIN_URL=http://sequencer-mediator:5008
- SPLICE_APP_SV_COMETBFT_ENABLED=false
- SPLICE_APP_UI_NETWORK_NAME=${SPLICE_APP_UI_NETWORK_NAME}
- SPLICE_APP_UI_NETWORK_FAVICON_URL=${SPLICE_APP_UI_NETWORK_FAVICON_URL}
Expand Down
Loading

0 comments on commit d5f9f82

Please sign in to comment.