diff --git a/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Alpha.hs b/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Alpha.hs index 8bc70f81e1f9..03ec1d7e9a96 100644 --- a/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Alpha.hs +++ b/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Alpha.hs @@ -519,6 +519,9 @@ alphaUpdate env = \case && alphaExpr' env e1a e2a && alphaExpr' (bindExprVar x1 x2 env) e1b e2b _ -> structuralMismatch + UPrefetchContracts e1 -> \case + UPrefetchContracts e2 -> alphaExpr' env e1 e2 + _ -> structuralMismatch alphaScenario :: AlphaEnv reason -> Scenario -> Scenario -> Mismatches reason alphaScenario env = \case diff --git a/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Base.hs b/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Base.hs index 9b9a4202cde0..01d0427d8bc9 100644 --- a/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Base.hs +++ b/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Base.hs @@ -762,6 +762,9 @@ data Update , tryCatchVar :: !ExprVarName , tryCatchHandler :: !Expr } + | UPrefetchContracts + { contracts :: !Expr + } deriving (Eq, Data, Generic, NFData, Ord, Show) -- | Expression in the scenario monad diff --git a/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/FreeVars.hs b/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/FreeVars.hs index b03e77f41ce4..deabeec30ff2 100644 --- a/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/FreeVars.hs +++ b/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/FreeVars.hs @@ -158,6 +158,7 @@ freeVarsStep = \case UFetchByKeyF _ -> mempty ULookupByKeyF _ -> mempty UTryCatchF t e1 x e2 -> freeVarsInType t <> e1 <> bindExprVar x e2 + UPrefetchContractsF e -> e goScenario :: ScenarioF FreeVars -> FreeVars goScenario = \case diff --git a/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Pretty.hs b/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Pretty.hs index 313b0e14ad52..e9a8415a8241 100644 --- a/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Pretty.hs +++ b/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Pretty.hs @@ -422,6 +422,7 @@ instance Pretty Update where pPrintAppKeyword lvl prec "ulookup_by_key" [tplArg tmplId] UTryCatch t e1 x e2 -> keyword_ "try" <-> pPrintTyArg lvl t <-> pPrintTmArg lvl e1 <-> keyword_ "catch" <-> pPrintPrec lvl precParam x <-> keyword_ "." <-> pPrintTmArg lvl e2 + UPrefetchContracts e -> pPrintAppKeyword lvl prec "prefetch_contracts" [TmArg e] instance Pretty Scenario where pPrintPrec lvl prec = \case diff --git a/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Recursive.hs b/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Recursive.hs index 5a8fdc1266e5..f0a29ccdedad 100644 --- a/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Recursive.hs +++ b/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Recursive.hs @@ -86,6 +86,7 @@ data UpdateF expr | UFetchByKeyF !(Qualified TypeConName) | ULookupByKeyF !(Qualified TypeConName) | UTryCatchF !Type !expr !ExprVarName !expr + | UPrefetchContractsF !expr deriving (Foldable, Functor, Traversable) data ScenarioF expr @@ -130,6 +131,7 @@ projectUpdate = \case ULookupByKey a -> ULookupByKeyF a UFetchByKey a -> UFetchByKeyF a UTryCatch a b c d -> UTryCatchF a b c d + UPrefetchContracts a -> UPrefetchContractsF a embedUpdate :: UpdateF Expr -> Update embedUpdate = \case @@ -148,6 +150,7 @@ embedUpdate = \case UFetchByKeyF a -> UFetchByKey a ULookupByKeyF a -> ULookupByKey a UTryCatchF a b c d -> UTryCatch a b c d + UPrefetchContractsF a -> UPrefetchContracts a projectScenario :: Scenario -> ScenarioF Expr projectScenario = \case diff --git a/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Subst.hs b/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Subst.hs index 9af34bfe4435..89428b85a33a 100644 --- a/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Subst.hs +++ b/sdk/compiler/daml-lf-ast/src/DA/Daml/LF/Ast/Subst.hs @@ -315,6 +315,8 @@ applySubstInUpdate subst = \case (applySubstInExpr subst e1) x' (applySubstInExpr subst' e2) + UPrefetchContracts e -> UPrefetchContracts + (applySubstInExpr subst e) applySubstInScenario :: Subst -> Scenario -> Scenario applySubstInScenario subst = \case diff --git a/sdk/compiler/daml-lf-proto-decode/src/DA/Daml/LF/Proto3/DecodeV2.hs b/sdk/compiler/daml-lf-proto-decode/src/DA/Daml/LF/Proto3/DecodeV2.hs index 9f3a5da4ce52..93da280ad70b 100644 --- a/sdk/compiler/daml-lf-proto-decode/src/DA/Daml/LF/Proto3/DecodeV2.hs +++ b/sdk/compiler/daml-lf-proto-decode/src/DA/Daml/LF/Proto3/DecodeV2.hs @@ -645,6 +645,8 @@ decodeUpdate LF2.Update{..} = mayDecode "updateSum" updateSum $ \case <*> mayDecode "update_TryCatchTryExpr" update_TryCatchTryExpr decodeExpr <*> decodeNameId ExprVarName update_TryCatchVarInternedStr <*> mayDecode "update_TryCatchCatchExpr" update_TryCatchCatchExpr decodeExpr + LF2.UpdateSumPrefetchContracts LF2.Update_PrefetchContracts{..} -> + fmap EUpdate $ UPrefetchContracts <$> mayDecode "update_PrefetchContractsExpr" update_PrefetchContractsExpr decodeExpr decodeRetrieveByKey :: LF2.Update_RetrieveByKey -> Decode (Qualified TypeConName) decodeRetrieveByKey LF2.Update_RetrieveByKey{..} = diff --git a/sdk/compiler/daml-lf-proto-encode/src/DA/Daml/LF/Proto3/EncodeV2.hs b/sdk/compiler/daml-lf-proto-encode/src/DA/Daml/LF/Proto3/EncodeV2.hs index 17d014eae311..7a5b011fcb6d 100644 --- a/sdk/compiler/daml-lf-proto-encode/src/DA/Daml/LF/Proto3/EncodeV2.hs +++ b/sdk/compiler/daml-lf-proto-encode/src/DA/Daml/LF/Proto3/EncodeV2.hs @@ -724,6 +724,9 @@ encodeUpdate = fmap (P.Update . Just) . \case update_TryCatchVarInternedStr <- encodeNameId unExprVarName tryCatchVar update_TryCatchCatchExpr <- encodeExpr tryCatchHandler pure $ P.UpdateSumTryCatch P.Update_TryCatch{..} + UPrefetchContracts{..} -> do + update_PrefetchContractsExpr <- encodeExpr contracts + pure $ P.UpdateSumPrefetchContracts P.Update_PrefetchContracts{..} encodeRetrieveByKey :: Qualified TypeConName -> Encode P.Update_RetrieveByKey encodeRetrieveByKey tmplId = do diff --git a/sdk/compiler/daml-lf-tools/src/DA/Daml/LF/TypeChecker/Check.hs b/sdk/compiler/daml-lf-tools/src/DA/Daml/LF/TypeChecker/Check.hs index a53b8e26ddc3..e3c3b4d9408b 100644 --- a/sdk/compiler/daml-lf-tools/src/DA/Daml/LF/TypeChecker/Check.hs +++ b/sdk/compiler/daml-lf-tools/src/DA/Daml/LF/TypeChecker/Check.hs @@ -657,6 +657,9 @@ typeOfUpdate = \case introExprVar var TAnyException $ do checkExpr handler (TOptional (TUpdate typ)) pure (TUpdate typ) + UPrefetchContracts expr -> do + checkExpr expr (TList (TContractId TUnit)) + pure (TUpdate TUnit) typeOfScenario :: MonadGamma m => Scenario -> m Type typeOfScenario = \case diff --git a/sdk/daml-lf/archive/src/main/protobuf/com/digitalasset/daml/lf/archive/daml_lf1.proto b/sdk/daml-lf/archive/src/main/protobuf/com/digitalasset/daml/lf/archive/daml_lf1.proto index 3792b1fe8849..7e7822bceaad 100644 --- a/sdk/daml-lf/archive/src/main/protobuf/com/digitalasset/daml/lf/archive/daml_lf1.proto +++ b/sdk/daml-lf/archive/src/main/protobuf/com/digitalasset/daml/lf/archive/daml_lf1.proto @@ -1462,6 +1462,10 @@ message Update { Expr catch_expr = 4; } + message PrefetchContracts { + Expr expr = 1; + } + oneof Sum { Pure pure = 1; Block block = 2; @@ -1481,6 +1485,7 @@ message Update { DynamicExercise dynamic_exercise = 15; // *Available in versions >= 1.dev* SoftFetch soft_fetch = 16; // *Available in versions >= 1.dev* SoftExercise soft_exercise = 17; // *Available in versions >= 1.dev* + PrefetchContracts prefetch_contracts = 18; // *Available in versions >= 1.17* } } diff --git a/sdk/daml-lf/archive/src/main/protobuf/com/digitalasset/daml/lf/archive/daml_lf2.proto b/sdk/daml-lf/archive/src/main/protobuf/com/digitalasset/daml/lf/archive/daml_lf2.proto index 4b4504b9fcaf..78dea2741b67 100644 --- a/sdk/daml-lf/archive/src/main/protobuf/com/digitalasset/daml/lf/archive/daml_lf2.proto +++ b/sdk/daml-lf/archive/src/main/protobuf/com/digitalasset/daml/lf/archive/daml_lf2.proto @@ -1100,6 +1100,10 @@ message Update { Expr catch_expr = 4; } + message PrefetchContracts { + Expr expr = 1; + } + oneof Sum { Pure pure = 1; Block block = 2; @@ -1115,6 +1119,7 @@ message Update { CreateInterface create_interface = 12; ExerciseInterface exercise_interface = 13; FetchInterface fetch_interface = 14; + PrefetchContracts prefetch_contracts = 15; // *Available in versions >= 2.dev* DynamicExercise dynamic_exercise = 1001; // *Available in versions >= 2.dev* SoftFetch soft_fetch = 1002; // *Available in versions >= 2.dev* diff --git a/sdk/daml-lf/archive/src/main/scala/com/digitalasset/daml/lf/archive/DecodeV2.scala b/sdk/daml-lf/archive/src/main/scala/com/digitalasset/daml/lf/archive/DecodeV2.scala index 7babcaa037eb..759868782759 100644 --- a/sdk/daml-lf/archive/src/main/scala/com/digitalasset/daml/lf/archive/DecodeV2.scala +++ b/sdk/daml-lf/archive/src/main/scala/com/digitalasset/daml/lf/archive/DecodeV2.scala @@ -1400,6 +1400,13 @@ private[archive] class DecodeV2(minor: LV.Minor) { } } + case PLF.Update.SumCase.PREFETCH_CONTRACTS => + assertSince(LV.Features.prefetch, "Update.prefetch_contracts") + val prefetch = lfUpdate.getPrefetchContracts + decodeExpr(prefetch.getExpr, definition) { contracts => + Ret(UpdatePrefetchContracts(contracts)) + } + case PLF.Update.SumCase.SUM_NOT_SET => throw Error.Parsing("Update.SUM_NOT_SET") } diff --git a/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/PhaseOne.scala b/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/PhaseOne.scala index ecf69881b97c..ea2fc2a25c24 100644 --- a/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/PhaseOne.scala +++ b/sdk/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/PhaseOne.scala @@ -759,6 +759,9 @@ private[lf] final class PhaseOne( } } } + case UpdatePrefetchContracts(_) => + // TODO: Implement prefetching + ??? } @tailrec diff --git a/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Ast.scala b/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Ast.scala index e52491aca7d5..107c3a364897 100644 --- a/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Ast.scala +++ b/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Ast.scala @@ -608,6 +608,7 @@ object Ast { binder: ExprVarName, handler: Expr, ) extends Update + final case class UpdatePrefetchContracts(contracts: Expr) extends Update // // Scenario expressions diff --git a/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/LanguageVersion.scala b/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/LanguageVersion.scala index f706f9a7779f..9fc571f9cf2d 100644 --- a/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/LanguageVersion.scala +++ b/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/LanguageVersion.scala @@ -106,6 +106,8 @@ object LanguageVersion { val scenarios = v2_dev val contractKeys = v2_dev + val prefetch = v2_dev + /** Unstable, experimental features. This should stay in x.dev forever. * Features implemented with this flag should be moved to a separate * feature flag once the decision to add them permanently has been made. diff --git a/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/util/iterable/ExprIterable.scala b/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/util/iterable/ExprIterable.scala index 7183284c35ad..fa84c8076403 100644 --- a/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/util/iterable/ExprIterable.scala +++ b/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/util/iterable/ExprIterable.scala @@ -127,6 +127,8 @@ private[lf] object ExprIterable { Iterator(body) case UpdateTryCatch(typ @ _, body, binder @ _, handler) => Iterator(body, handler) + case UpdatePrefetchContracts(contracts) => + Iterator(contracts) } } diff --git a/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/util/iterable/TypeIterable.scala b/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/util/iterable/TypeIterable.scala index 1c2e29d94daa..a218c08955fd 100644 --- a/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/util/iterable/TypeIterable.scala +++ b/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/util/iterable/TypeIterable.scala @@ -162,7 +162,9 @@ private[lf] object TypeIterable { case UpdateEmbedExpr(typ, body) => Iterator(typ) ++ iterator(body) - case UpdateGetTime | UpdateFetchByKey(_) | UpdateLookupByKey(_) => + case UpdateGetTime | UpdateFetchByKey(_) | UpdateLookupByKey(_) | UpdatePrefetchContracts( + _ + ) => ExprIterable.iterator(update).flatMap(iterator(_)) case UpdateTryCatch(typ, body, binder @ _, handler) => Iterator(typ) ++ diff --git a/sdk/daml-lf/spec/daml-lf-2.rst b/sdk/daml-lf/spec/daml-lf-2.rst index 8f9c0dc0a867..53f62fa901d7 100644 --- a/sdk/daml-lf/spec/daml-lf-2.rst +++ b/sdk/daml-lf/spec/daml-lf-2.rst @@ -734,6 +734,7 @@ Then we can define our kinds, types, and expressions:: | 'lookup_by_key' @τ e -- UpdateLookUpByKey | 'embed_expr' @τ e -- UpdateEmbedExpr | 'try' @τ e₁ 'catch' x. e₂ -- UpdateTryCatch [Daml-LF ≥ 1.14] + | 'prefetch_contracts' e -- UpdatePrefetchContracts Scenario s ::= 'spure' @τ e -- ScenarioPure @@ -2062,6 +2063,7 @@ need to be evaluated further. :: | 'lookup_by_key' @Mod:T v -- ValUpdateLookupByKey | 'embed_expr' @τ e -- ValUpdateEmbedExpr | 'try' @τ e₁ 'catch' x. e₂ -- ValUpdateTryCatch + | 'prefetch_contracts' v -- ValPrefetchContracts ┌────┐ Scenario Values │ sv │ @@ -2378,6 +2380,7 @@ grammar below. :: | 'exercise_interface' @Mod:I Ch v₁ v₂ E₃ | 'fetch_by_key' @τ E | 'lookup_by_key' @τ E + | 'prefetch_contracts' E Scenario Evaluation Context SE ::= 'spure' @τ E @@ -3625,6 +3628,9 @@ as described by the ledger model:: ⇓ᵤ (Err err, ('rollback' tr₁)) + —————————————————————————————————————————————————————————————————————— EvUpdPrefetchContracts + 'prefetch_contracts' v ‖ (st, keys) ⇓ᵤ (Ok (), ε) ‖ (st, keys) + Transaction normalization ~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/sdk/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Typing.scala b/sdk/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Typing.scala index 9831fff4f857..3c7aa57be9da 100644 --- a/sdk/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Typing.scala +++ b/sdk/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Typing.scala @@ -1389,6 +1389,10 @@ private[validation] object Typing { Ret(updTyp) } } + case UpdatePrefetchContracts(contracts) => + checkExpr(contracts, TList(TContractId(TUnit))) { + Ret(TUpdate(TUnit)) + } } private def typeOfCommit(typ: Type, party: Expr, update: Expr): Work[Type] = {