Skip to content

Commit

Permalink
fix local contract upgrade (#20035)
Browse files Browse the repository at this point in the history
* test for local contract upgrade

* fix fetchAny for local contracts

* add ex and ex by key tests

* add local contract tests to ExceptionsTest

* add fetch by key test

* Add tests for dynamic exercise.
  • Loading branch information
paulbrauner-da committed Oct 21, 2024
1 parent 6c393cb commit 6c6a531
Show file tree
Hide file tree
Showing 3 changed files with 450 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2287,59 +2287,76 @@ private[lf] object SBuiltinFun {
machine: UpdateMachine,
dstTmplId: TypeConName,
coid: V.ContractId,
)(f: SValue => Control[Question.Update]): Control[Question.Update] =
machine.getIfLocalContract(coid) match {
case Some((srcTmplId, templateArg)) =>
ensureContractActive(machine, coid, srcTmplId) {
if (srcTmplId.qualifiedName != dstTmplId.qualifiedName)
Control.Error(
IE.WronglyTypedContract(coid, dstTmplId, srcTmplId)
)
else f(templateArg)
}
case None =>
machine.lookupContract(coid) { case V.ContractInstance(_, _, srcTmplId, coinstArg) =>
if (srcTmplId.qualifiedName != dstTmplId.qualifiedName)
Control.Error(
IE.WronglyTypedContract(coid, dstTmplId, srcTmplId)
)
else
machine.ensurePackageIsLoaded(
dstTmplId.packageId,
language.Reference.Template(dstTmplId),
) { () =>
importValue(machine, dstTmplId, coinstArg) { templateArg =>
getContractInfo(
machine,
coid,
dstTmplId,
templateArg,
allowCatchingContractInfoErrors = false,
) { contract =>
ensureContractActive(machine, coid, contract.templateId) {

machine.checkContractVisibility(coid, contract)
machine.enforceLimitAddInputContract()
machine.enforceLimitSignatoriesAndObservers(coid, contract)

// In Validation mode, we always call validateContractInfo
// In Submission mode, we only call validateContractInfo when src != dest
val needValidationCall: Boolean =
machine.validating || srcTmplId.packageId != dstTmplId.packageId
if (needValidationCall) {
validateContractInfo(machine, coid, srcTmplId, contract) { () =>
f(contract.value)
}
} else {
f(contract.value)
}
)(f: SValue => Control[Question.Update]): Control[Question.Update] = {
def importContract(coinst: V.ContractInstance) = {
val V.ContractInstance(_, _, srcTmplId, coinstArg) = coinst
if (srcTmplId.qualifiedName != dstTmplId.qualifiedName)
Control.Error(
IE.WronglyTypedContract(coid, dstTmplId, srcTmplId)
)
else
machine.ensurePackageIsLoaded(
dstTmplId.packageId,
language.Reference.Template(dstTmplId),
) { () =>
importValue(machine, dstTmplId, coinstArg) { templateArg =>
getContractInfo(
machine,
coid,
dstTmplId,
templateArg,
allowCatchingContractInfoErrors = false,
) { contract =>
ensureContractActive(machine, coid, contract.templateId) {

machine.checkContractVisibility(coid, contract)
machine.enforceLimitAddInputContract()
machine.enforceLimitSignatoriesAndObservers(coid, contract)

// In Validation mode, we always call validateContractInfo
// In Submission mode, we only call validateContractInfo when src != dest
val needValidationCall: Boolean =
machine.validating || srcTmplId.packageId != dstTmplId.packageId
if (needValidationCall) {
validateContractInfo(machine, coid, srcTmplId, contract) { () =>
f(contract.value)
}
} else {
f(contract.value)
}
}
}
}
}
}

machine.getIfLocalContract(coid) match {
case Some((srcTmplId, templateArg)) =>
ensureContractActive(machine, coid, srcTmplId) {
getContractInfo(
machine,
coid,
srcTmplId,
templateArg,
allowCatchingContractInfoErrors = false,
) { contract =>
if (srcTmplId == dstTmplId) f(templateArg)
else
importContract(
V.ContractInstance(
contract.packageName,
contract.packageVersion,
srcTmplId,
contract.arg,
)
)
}
}
case None =>
machine.lookupContract(coid)(importContract)
}
}

/** A version of [[fetchTemplate]] without a destination template type. The template type of the contract on ledger
* is used for importing its value, and is returned alongside the value.
*/
Expand Down
Loading

0 comments on commit 6c6a531

Please sign in to comment.