Skip to content

Commit c7690ac

Browse files
committed
[ci] review fixes
Signed-off-by: Oriol Muñoz <oriol.munoz@digitalasset.com>
1 parent 5dbfc56 commit c7690ac

File tree

10 files changed

+133
-48
lines changed

10 files changed

+133
-48
lines changed

apps/app/src/main/scala/org/lfdecentralizedtrust/splice/config/SpliceConfig.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ import com.digitalasset.canton.synchronizer.sequencer.config.{
8282
}
8383
import com.digitalasset.canton.topology.PartyId
8484
import com.digitalasset.daml.lf.data.Ref.PackageVersion
85-
import org.lfdecentralizedtrust.splice.store.ContractFetcher
85+
import org.lfdecentralizedtrust.splice.store.ChoiceContextContractFetcher
8686

8787
case class SpliceConfig(
8888
override val name: Option[String] = None,
@@ -414,8 +414,8 @@ object SpliceConfig {
414414
implicit val circuitBreakersConfig: ConfigReader[CircuitBreakersConfig] =
415415
deriveReader[CircuitBreakersConfig]
416416
implicit val contractFetchLedgerFallbackConfigReader
417-
: ConfigReader[ContractFetcher.StoreContractFetcherWithLedgerFallbackConfig] =
418-
deriveReader[ContractFetcher.StoreContractFetcherWithLedgerFallbackConfig]
417+
: ConfigReader[ChoiceContextContractFetcher.StoreContractFetcherWithLedgerFallbackConfig] =
418+
deriveReader[ChoiceContextContractFetcher.StoreContractFetcherWithLedgerFallbackConfig]
419419
implicit val spliceParametersConfig: ConfigReader[SpliceParametersConfig] =
420420
deriveReader[SpliceParametersConfig]
421421
implicit val rateLimitersConfig: ConfigReader[RateLimitersConfig] =
@@ -843,8 +843,8 @@ object SpliceConfig {
843843
implicit val circuitBreakersConfig: ConfigWriter[CircuitBreakersConfig] =
844844
deriveWriter[CircuitBreakersConfig]
845845
implicit val contractFetchLedgerFallbackConfigWriter
846-
: ConfigWriter[ContractFetcher.StoreContractFetcherWithLedgerFallbackConfig] =
847-
deriveWriter[ContractFetcher.StoreContractFetcherWithLedgerFallbackConfig]
846+
: ConfigWriter[ChoiceContextContractFetcher.StoreContractFetcherWithLedgerFallbackConfig] =
847+
deriveWriter[ChoiceContextContractFetcher.StoreContractFetcherWithLedgerFallbackConfig]
848848
implicit val spliceParametersConfig: ConfigWriter[SpliceParametersConfig] =
849849
deriveWriter[SpliceParametersConfig]
850850

apps/app/src/test/scala/org/lfdecentralizedtrust/splice/integration/tests/TokenStandardFetchFallbackIntegrationTest.scala

Lines changed: 75 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,20 @@ package org.lfdecentralizedtrust.splice.integration.tests
22

33
import com.digitalasset.canton.data.CantonTimestamp
44
import com.digitalasset.canton.{HasActorSystem, HasExecutionContext}
5+
import org.lfdecentralizedtrust.splice.codegen.java.splice.api.token.allocationv1.*
6+
import org.lfdecentralizedtrust.splice.codegen.java.splice.api.token.holdingv1.InstrumentId
57
import org.lfdecentralizedtrust.splice.codegen.java.splice.api.token.transferinstructionv1.TransferInstruction
6-
import org.lfdecentralizedtrust.splice.config.ConfigTransforms.updateAllScanAppConfigs_
78
import org.lfdecentralizedtrust.splice.http.v0.definitions.TransferInstructionResultOutput.members
89
import org.lfdecentralizedtrust.splice.integration.EnvironmentDefinition
910
import org.lfdecentralizedtrust.splice.integration.tests.SpliceTests.IntegrationTestWithSharedEnvironment
10-
import org.lfdecentralizedtrust.splice.store.ContractFetcher
11-
import org.lfdecentralizedtrust.splice.util.{TriggerTestUtil, WalletTestUtil}
11+
import org.lfdecentralizedtrust.splice.util.{
12+
ChoiceContextWithDisclosures,
13+
TriggerTestUtil,
14+
WalletTestUtil,
15+
}
1216

13-
import java.util.UUID
17+
import java.time.Instant
18+
import java.util.{Optional, UUID}
1419

1520
class TokenStandardFetchFallbackIntegrationTest
1621
extends IntegrationTestWithSharedEnvironment
@@ -21,22 +26,10 @@ class TokenStandardFetchFallbackIntegrationTest
2126
with HasExecutionContext {
2227

2328
override def environmentDefinition: EnvironmentDefinition = {
24-
EnvironmentDefinition
25-
.simpleTopology1Sv(this.getClass.getSimpleName)
26-
.addConfigTransforms((_, config) =>
27-
updateAllScanAppConfigs_(scanConfig =>
28-
scanConfig.copy(parameters =
29-
scanConfig.parameters.copy(contractFetchLedgerFallbackConfig =
30-
ContractFetcher.StoreContractFetcherWithLedgerFallbackConfig(
31-
enabled = true
32-
)
33-
)
34-
)
35-
)(config)
36-
)
29+
EnvironmentDefinition.simpleTopology1Sv(this.getClass.getSimpleName)
3730
}
3831

39-
"Token Standard Transfers should" should {
32+
"Token Standard" should {
4033

4134
"TransferInstruction context can be fetched from Scan even if it's not yet ingested into the store" in {
4235
implicit env =>
@@ -77,6 +70,70 @@ class TokenStandardFetchFallbackIntegrationTest
7770
}
7871
}
7972

73+
"AmuletAllocations context can be fetched from Scan even if it's not yet ingested into the store" in {
74+
implicit env =>
75+
pauseScanIngestionWithin(sv1ScanBackend) {
76+
val aliceParty = onboardWalletUser(aliceWalletClient, aliceValidatorBackend)
77+
val bobParty = onboardWalletUser(bobWalletClient, bobValidatorBackend)
78+
// // Allocate venue on separate participant node, we still go through the validator API instead of parties.enable
79+
// // so we can use the standard wallet client APIs but give the party a more useful name than splitwell.
80+
// val venuePartyHint = s"venue-party-${Random.nextInt()}"
81+
// val venueParty = splitwellValidatorBackend.onboardUser(
82+
// splitwellWalletClient.config.ledgerApiUser,
83+
// Some(
84+
// PartyId.tryFromProtoPrimitive(
85+
// s"$venuePartyHint::${splitwellValidatorBackend.participantClient.id.namespace.toProtoPrimitive}"
86+
// )
87+
// ),
88+
// )
89+
90+
aliceWalletClient.tap(100)
91+
val referenceId = UUID.randomUUID().toString
92+
93+
val (_, allocation) = actAndCheck(
94+
"Alice creates an Allocation",
95+
aliceWalletClient.allocateAmulet(
96+
new AllocationSpecification(
97+
new SettlementInfo(
98+
dsoParty.toProtoPrimitive,
99+
new Reference(referenceId, Optional.empty),
100+
Instant.now,
101+
Instant.now.plusSeconds(3600L),
102+
Instant.now.plusSeconds(2 * 3600L),
103+
ChoiceContextWithDisclosures.emptyMetadata,
104+
),
105+
UUID.randomUUID().toString,
106+
new TransferLeg(
107+
aliceParty.toProtoPrimitive,
108+
bobParty.toProtoPrimitive,
109+
BigDecimal(10).bigDecimal,
110+
new InstrumentId(dsoParty.toProtoPrimitive, "Amulet"),
111+
ChoiceContextWithDisclosures.emptyMetadata,
112+
),
113+
)
114+
),
115+
)(
116+
"Alice sees the Allocation",
117+
_ => {
118+
val allocation =
119+
aliceWalletClient
120+
.listAmuletAllocations()
121+
.loneElement
122+
allocation.payload.allocation.settlement.settlementRef.id should be(referenceId)
123+
allocation
124+
},
125+
)
126+
127+
clue("SV-1's Scan sees it (still, even though ingestion is paused)") {
128+
eventuallySucceeds() {
129+
sv1ScanBackend.getAllocationTransferContext(
130+
allocation.contractId.toInterface(Allocation.INTERFACE)
131+
)
132+
}
133+
}
134+
}
135+
}
136+
80137
}
81138

82139
}

apps/app/src/test/scala/org/lfdecentralizedtrust/splice/integration/tests/TokenStandardTransferIntegrationTest.scala

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,20 @@ import org.lfdecentralizedtrust.splice.codegen.java.splice.api.token.metadatav1
88
import org.lfdecentralizedtrust.splice.codegen.java.splice.api.token.transferinstructionv1.TransferInstruction
99
import org.lfdecentralizedtrust.splice.config.ConfigTransforms.{
1010
ConfigurableApp,
11+
updateAllScanAppConfigs_,
1112
updateAllSvAppFoundDsoConfigs_,
1213
updateAutomationConfig,
1314
}
14-
import org.lfdecentralizedtrust.splice.http.v0.definitions.TransferInstructionResultOutput.members
1515
import org.lfdecentralizedtrust.splice.http.v0.definitions.TransactionHistoryResponseItem.TransactionType as HttpTransactionType
16+
import org.lfdecentralizedtrust.splice.http.v0.definitions.TransferInstructionResultOutput.members
1617
import org.lfdecentralizedtrust.splice.http.v0.definitions.{
1718
AbortTransferInstruction,
1819
ReceiverAmount,
1920
Transfer,
2021
}
2122
import org.lfdecentralizedtrust.splice.integration.EnvironmentDefinition
2223
import org.lfdecentralizedtrust.splice.integration.tests.SpliceTests.IntegrationTestWithSharedEnvironment
23-
import org.lfdecentralizedtrust.splice.integration.tests.WalletTxLogTestUtil
24+
import org.lfdecentralizedtrust.splice.store.ChoiceContextContractFetcher
2425
import org.lfdecentralizedtrust.splice.util.{DisclosedContracts, WalletTestUtil}
2526
import org.lfdecentralizedtrust.splice.wallet.automation.CollectRewardsAndMergeAmuletsTrigger
2627
import org.lfdecentralizedtrust.splice.wallet.store.{
@@ -56,6 +57,17 @@ class TokenStandardTransferIntegrationTest
5657
_.copy(zeroTransferFees = true)
5758
)(config)
5859
)
60+
.addConfigTransforms((_, config) =>
61+
updateAllScanAppConfigs_(scanConfig =>
62+
scanConfig.copy(parameters =
63+
scanConfig.parameters.copy(contractFetchLedgerFallbackConfig =
64+
ChoiceContextContractFetcher.StoreContractFetcherWithLedgerFallbackConfig(
65+
enabled = false // expiry test doesn't see the archival otherwise
66+
)
67+
)
68+
)
69+
)(config)
70+
)
5971
}
6072

6173
"Token Standard Transfers should" should {

apps/common/src/main/scala/org/lfdecentralizedtrust/splice/automation/UpdateIngestionService.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import org.lfdecentralizedtrust.splice.store.MultiDomainAcsStore
1616
import com.digitalasset.canton.logging.NamedLoggerFactory
1717
import com.digitalasset.canton.time.Clock
1818
import com.digitalasset.canton.tracing.TraceContext
19+
import com.google.common.annotations.VisibleForTesting
1920
import io.opentelemetry.api.trace.Tracer
2021
import org.lfdecentralizedtrust.splice.store.MultiDomainAcsStore.IngestionSink.IngestionStart
2122

@@ -135,8 +136,8 @@ class UpdateIngestionService(
135136
private var waitForResumePromise = Promise.successful(())
136137

137138
/** Note that any in-flight events being processed when `pause` is called will still be processed.
138-
* For test purposes.
139139
*/
140+
@VisibleForTesting
140141
def pause(): Future[Unit] = blocking {
141142
withNewTrace(this.getClass.getSimpleName) { implicit traceContext => _ =>
142143
logger.info("Pausing UpdateIngestionService.")
@@ -151,6 +152,7 @@ class UpdateIngestionService(
151152
}
152153
}
153154

155+
@VisibleForTesting
154156
def resume(): Unit = blocking {
155157
withNewTrace(this.getClass.getSimpleName) { implicit traceContext => _ =>
156158
logger.info("Resuming UpdateIngestionService.")

apps/common/src/main/scala/org/lfdecentralizedtrust/splice/config/SpliceParametersConfig.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ import com.digitalasset.canton.config.{
1010
NonNegativeFiniteDuration,
1111
WatchdogConfig,
1212
}
13-
import org.lfdecentralizedtrust.splice.store.ContractFetcher
13+
import org.lfdecentralizedtrust.splice.store.ChoiceContextContractFetcher
1414
import org.lfdecentralizedtrust.splice.util.SpliceRateLimitConfig
1515

1616
final case class SpliceParametersConfig(
1717
batching: BatchingConfig = BatchingConfig(),
1818
caching: CachingConfigs = CachingConfigs(),
19-
contractFetchLedgerFallbackConfig: ContractFetcher.StoreContractFetcherWithLedgerFallbackConfig =
20-
ContractFetcher.StoreContractFetcherWithLedgerFallbackConfig(),
19+
contractFetchLedgerFallbackConfig: ChoiceContextContractFetcher.StoreContractFetcherWithLedgerFallbackConfig =
20+
ChoiceContextContractFetcher.StoreContractFetcherWithLedgerFallbackConfig(),
2121
// Do not define any defaults on the class containing the `SpliceParametersConfig` as they'll be overwritten.
2222
// Do it instead on the app.conf file in `cluster/images/${the_app}/app.conf`
2323
customTimeouts: Map[String, NonNegativeFiniteDuration] = Map.empty,

apps/common/src/main/scala/org/lfdecentralizedtrust/splice/store/ContractFetcher.scala renamed to apps/common/src/main/scala/org/lfdecentralizedtrust/splice/store/ChoiceContextContractFetcher.scala

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,17 @@ import org.lfdecentralizedtrust.splice.util.Contract
1818

1919
import scala.concurrent.{ExecutionContext, Future}
2020

21-
trait ContractFetcher {
21+
/** The RecordOrderPublisher might cause that some contracts are visible by validators' stores,
22+
* but not yet by SVs'. Then, when a validator requires some data from Scan that is not yet there,
23+
* it slows the workflow down.
24+
* This is particularly relevant in the token standard, where the TransferInstruction and the amuletallocation
25+
* might appear in the validators before Scans, and when they try to accept them, Scan fails to provide the necessary
26+
* ChoiceContext.
27+
* The purpose of this class then is to fallback to a direct ledger call when the store says a contract does not exist.
28+
*
29+
* This is not general purpose (see limitations below), but covers the case for the Token Standard contracts.
30+
*/
31+
trait ChoiceContextContractFetcher {
2232

2333
def lookupContractById[C, TCid <: ContractId[?], T](
2434
companion: C
@@ -29,10 +39,10 @@ trait ContractFetcher {
2939

3040
}
3141

32-
object ContractFetcher {
42+
object ChoiceContextContractFetcher {
3343

34-
private class StoreContractFetcher(store: AppStore)(implicit ec: ExecutionContext)
35-
extends ContractFetcher {
44+
private class StoreChoiceContextContractFetcher(store: AppStore)(implicit ec: ExecutionContext)
45+
extends ChoiceContextContractFetcher {
3646
override def lookupContractById[C, TCid <: ContractId[?], T](
3747
companion: C
3848
)(id: ContractId[?])(implicit
@@ -42,14 +52,14 @@ object ContractFetcher {
4252
store.multiDomainAcsStore.lookupContractById(companion)(id).map(_.map(_.contract))
4353
}
4454

45-
private class StoreContractFetcherWithLedgerFallback(
55+
private class StoreChoiceContextContractFetcherWithLedgerFallback(
4656
store: AppStore,
4757
fallbackLedgerClient: BaseLedgerConnection,
4858
clock: Clock,
4959
loggerFactory: NamedLoggerFactory,
5060
getContractValidity: NonNegativeFiniteDuration,
5161
)(implicit ec: ExecutionContext)
52-
extends ContractFetcher {
62+
extends ChoiceContextContractFetcher {
5363
private val logger = loggerFactory.getLogger(this.getClass)
5464

5565
override def lookupContractById[C, TCid <: ContractId[?], T](
@@ -62,7 +72,7 @@ object ContractFetcher {
6272
.map(_.contract)
6373
.orElse(
6474
OptionT(fallbackLedgerClient.getContract(id, Seq(store.multiDomainAcsStore.storeParty)))
65-
// `getContract` may return a contract that was archived (and thus missing from the store).
75+
// `getContract` will return archived contracts (and thus missing from the store) until they have been pruned.
6676
// Thus, we verify that it was created not too long ago,
6777
// such that it means that what happened is the store didn't see it yet, but the ledger did.
6878
// (as opposed to the contract actually being archived)
@@ -84,7 +94,7 @@ object ContractFetcher {
8494
}
8595

8696
case class StoreContractFetcherWithLedgerFallbackConfig(
87-
enabled: Boolean = false,
97+
enabled: Boolean = true,
8898
// RecordOrderPublisher + (created_at VS record_time skew)
8999
getContractValidity: NonNegativeFiniteDuration = NonNegativeFiniteDuration.ofSeconds(120L),
90100
)
@@ -94,17 +104,17 @@ object ContractFetcher {
94104
fallbackLedgerClient: BaseLedgerConnection,
95105
clock: Clock,
96106
loggerFactory: NamedLoggerFactory,
97-
)(implicit ec: ExecutionContext): ContractFetcher = {
107+
)(implicit ec: ExecutionContext): ChoiceContextContractFetcher = {
98108
if (config.enabled) {
99-
new StoreContractFetcherWithLedgerFallback(
109+
new StoreChoiceContextContractFetcherWithLedgerFallback(
100110
store,
101111
fallbackLedgerClient,
102112
clock,
103113
loggerFactory,
104114
config.getContractValidity,
105115
)
106116
} else {
107-
new StoreContractFetcher(store)
117+
new StoreChoiceContextContractFetcher(store)
108118
}
109119
}
110120

apps/scan/src/main/scala/org/lfdecentralizedtrust/splice/scan/ScanApp.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ import org.lfdecentralizedtrust.splice.scan.store.db.{
4646
ScanAggregatesReaderContext,
4747
}
4848
import org.lfdecentralizedtrust.splice.scan.dso.DsoAnsResolver
49-
import org.lfdecentralizedtrust.splice.store.{ContractFetcher, PageLimit, UpdateHistory}
49+
import org.lfdecentralizedtrust.splice.store.{
50+
ChoiceContextContractFetcher,
51+
PageLimit,
52+
UpdateHistory,
53+
}
5054
import org.lfdecentralizedtrust.splice.util.HasHealth
5155
import com.digitalasset.canton.concurrent.FutureSupervisor
5256
import com.digitalasset.canton.config.CantonRequireTypes.InstanceName
@@ -307,7 +311,7 @@ class ScanApp(
307311
bftSequencersWithAdminConnections,
308312
initialRound,
309313
)
310-
contractFetcher = ContractFetcher.createStoreWithLedgerFallback(
314+
contractFetcher = ChoiceContextContractFetcher.createStoreWithLedgerFallback(
311315
config.parameters.contractFetchLedgerFallbackConfig,
312316
store,
313317
appInitConnection,

apps/scan/src/main/scala/org/lfdecentralizedtrust/splice/scan/admin/http/HttpTokenStandardAllocationHandler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import org.lfdecentralizedtrust.splice.codegen.java.splice.api.token.metadatav1
1313
import org.lfdecentralizedtrust.splice.environment.DarResources
1414
import org.lfdecentralizedtrust.splice.scan.store.ScanStore
1515
import org.lfdecentralizedtrust.splice.scan.util
16-
import org.lfdecentralizedtrust.splice.store.ContractFetcher
16+
import org.lfdecentralizedtrust.splice.store.ChoiceContextContractFetcher
1717
import org.lfdecentralizedtrust.splice.util.Contract
1818
import org.lfdecentralizedtrust.tokenstandard.allocation.v1
1919
import org.lfdecentralizedtrust.tokenstandard.allocation.v1.definitions.GetChoiceContextRequest
@@ -25,7 +25,7 @@ import scala.jdk.CollectionConverters.*
2525

2626
class HttpTokenStandardAllocationHandler(
2727
store: ScanStore,
28-
contractFetcher: ContractFetcher,
28+
contractFetcher: ChoiceContextContractFetcher,
2929
clock: Clock,
3030
protected val loggerFactory: NamedLoggerFactory,
3131
)(implicit

apps/scan/src/main/scala/org/lfdecentralizedtrust/splice/scan/admin/http/HttpTokenStandardTransferInstructionHandler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import org.lfdecentralizedtrust.splice.codegen.java.splice.api.token.{
1616
import org.lfdecentralizedtrust.splice.environment.DarResources
1717
import org.lfdecentralizedtrust.splice.scan.store.ScanStore
1818
import org.lfdecentralizedtrust.splice.scan.util
19-
import org.lfdecentralizedtrust.splice.store.ContractFetcher
19+
import org.lfdecentralizedtrust.splice.store.ChoiceContextContractFetcher
2020
import org.lfdecentralizedtrust.splice.util.{AmuletConfigSchedule, Contract}
2121
import org.lfdecentralizedtrust.tokenstandard.transferinstruction.v1
2222
import org.lfdecentralizedtrust.tokenstandard.transferinstruction.v1.{Resource, definitions}
@@ -28,7 +28,7 @@ import scala.util.{Failure, Success, Try}
2828

2929
class HttpTokenStandardTransferInstructionHandler(
3030
store: ScanStore,
31-
contractFetcher: ContractFetcher,
31+
contractFetcher: ChoiceContextContractFetcher,
3232
clock: Clock,
3333
protected val loggerFactory: NamedLoggerFactory,
3434
)(implicit

0 commit comments

Comments
 (0)