Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON API: etx-500 add type information into the package ids of template ids #19211

Merged
merged 5 commits into from
May 22, 2024

Conversation

raphael-speyer-da
Copy link
Collaborator

@raphael-speyer-da raphael-speyer-da commented May 16, 2024

A template/interface id (ContractTypeId) consists of three parts: package, module and entity.

So far the package portion has been modeled with a String, where that string could represent either a package name or a package id, depending on whether it started with a "#" prefix or not, respectively. However there are parts of the code, namely those that deal with the db cache, that are designed to work with contract type ids whose package portion is only a package id. The type system was not helping us to ensure this so far.

Fortunately the ContractTypeId class is parameterised with the type of the package, so this PR replaces all existing instantiations which used String packages, with either PackageId or PackageRef (which is a sum type which can contain either a PackageId or a PackageName).

The ContractTypeRef type contains all the package info we have about a contract type id. Its original field now returns a ContractTypeId[PackageRef], whereas its latestPkgId returns a ContractTypeId[PackageId]. This helps us to ensure that we are passing around the right kind of package specifiers to the parts of the code that need one or the other.

There are some type aliases used, that may be useful to help read and understand the changes, which tend to look like

   type RequiredPkg = CtId[Ref.PackageRef]
   type RequiredPkgId = CtId[Ref.PackageId]

i.e. if it ends with Pkg it uses a PackgeRef and if it ends with PkgId uses a PackageId.
Note also that the Resolved terminology is an orthogonal concern which refers to whether this id has been determined to belong to a template vs interface (i.e. it extends Definite), or whether that is not yet known.

@raphael-speyer-da raphael-speyer-da force-pushed the rls/etx-500-add-type-info-for-pkg-id branch 3 times, most recently from 33507f8 to 2b8802f Compare May 16, 2024 23:48
@raphael-speyer-da raphael-speyer-da force-pushed the rls/etx-500-add-type-info-for-pkg-id branch from 2b8802f to e17517c Compare May 17, 2024 02:05
@raphael-speyer-da raphael-speyer-da force-pushed the rls/etx-500-add-type-info-for-pkg-id branch from e17517c to 7cb03aa Compare May 17, 2024 02:58
sdk/fmt.sh Outdated
@@ -51,7 +51,7 @@ check_diff() {
# "${@:3}" command
changed_files=$(git diff --name-only --diff-filter=ACMRT "$1" | grep $2 | grep -E -v '^canton(-3x)?/' || [[ $? == 1 ]])
if [[ -n "$changed_files" ]]; then
run "${@:3}" ${changed_files[@]:-}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a developer, we now run ./fmt.sh --diff from within the sdk/ dir, but git still returns a list of changed files with a sdk prefix. This change removes the sdk/ prefix from those paths.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this change but in a small test I did the prefix removal only applied to the first file, so:

  • As this is an inf change it may be better to put it in a dedicated PR (@garyverhaegen-da may have an opinion on this)
  • As the canton pattern match in change files seems to assume no no sdk prefix so will not work
  • Consider changed_files=$(git diff --name-only --diff-filter=ACMRT "$1" | grep $2 | sed 's/^sdk\///' | grep -E -v '^canton(-3x)?/' || [[ $? == 1 ]])

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracted here #19237

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this change but in a small test I did the prefix removal only applied to the first file, so:

  • As this is an inf change it may be better to put it in a dedicated PR (@garyverhaegen-da may have an opinion on this)

I really don't - I don't use the pre-commit. My only opinion on the whole thing is it should be opt-in rather than opt-out.

log: LogHandler,
lc: LoggingContextOf[InstanceUUID],
): ConnectionIO[SurrogateTpId] = surrogateTemplateId(None, packageId, moduleName, entityName)

final def surrogateTemplateId(
packageName: Option[String],
packageId: String,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Within the db cache, we always use a package id as the basis for the surrogate template ids, i.e. an integeter which corresponds to a specific template.

parties: domain.PartySet,
contractTypeIds: List[ContractTypeId.Resolved],
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used to build a template filter for grpc requests to the ledger. In these filters the package may be specified with a name or an id, and this function is agnostic to the package type.

@@ -89,22 +89,22 @@ package domain {
)

object ActiveContract {
type ResolvedCtTyId[+LfV] = ActiveContract[ContractTypeId.Resolved, LfV]
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ActiveContract is always something that is returned from the ledger, and as such it the template ids are specified with a specific package id.


def apply(id: ContractTypeId.Resolved): ExtractAs[ContractTypeId.Resolved] = id match {
def apply(id: ContractTypeId.Definite[_]): ExtractAs[ContractTypeId.Definite] = id match {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can build an ExtractAs without considering the form of package of the id we queried, which is why the type parameter for it is _.


private[this] def qualifiedName(a: CtId[_]): Ref.QualifiedName =
Ref.QualifiedName(
Ref.DottedName.assertFromString(a.moduleName),
Ref.DottedName.assertFromString(a.entityName),
)

final def toLedgerApiValue(a: RequiredPkg): Ref.Identifier = {
final def toLedgerApiValue(a: RequiredPkgId): Ref.Identifier = {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice we only use this for calculating a contract key hash. If the type is from a package new enough to have a package name, then the package id portion is ignored and replaced with the name for the purposes of calculating the hash. If it's older, then the package id would be the appropriate package specifier anyway.

sealed abstract class ContractTypeRef[+CtTyId](
orig: CtTyId,
ids: NonEmpty[Seq[CtTyId]],
sealed abstract class ContractTypeRef[+CtTyId[T] <: ContractTypeId[T]](
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the original field will always use a package reference, but latestPkgId and allPkgIds will always use package ids. This was the case before, but not encoded by the types as they all used used strings.

To support this, ContractTypeRef, also moves from being parameterised with a type, to being parameterised with a type constructor. This is so that we can have different package specifiers for different fields, which both share the same contract type, e.g. original returns Template[PackageRef] but latestPkgId returns Template[PackageId].

@@ -71,7 +71,7 @@ private class ContractsFetch(
jwt: Jwt,
ledgerId: LedgerApiDomain.LedgerId,
parties: domain.PartySet,
templateIds: List[domain.ContractTypeId.Resolved],
templateIds: List[domain.ContractTypeId.ResolvedPkgId],
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything within this module relates to the db cache and thus needs to work with package ids.

@@ -478,44 +474,48 @@ object PackageService {

def buildTemplateIdMap[CtId[T] <: ContractTypeId.Definite[T] with ContractTypeId.Ops[CtId, T]](
idName: PackageNameMap,
ids: Set[RequiredPkg[CtId]],
ids: Set[CtId[Ref.PackageId]],
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These contract ids come out of hte package definition itself, and thus will have the package id embedded within them.

genDuplicateModuleEntityApiIdentifiers.map(xs =>
xs.map(domain.ContractTypeId.Template.fromLedgerApi)
)

final case class PackageIdGen[A](gen: Gen[A])

implicit val RequiredPackageIdGen: PackageIdGen[String] = PackageIdGen(Gen.identifier)
private val genPkgIdentifier = Gen.identifier.map(s => s.substring(0, 64 min s.length))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Package ids may not be longer than 64 chars, so just truncate the randomised values to that length.

@raphael-speyer-da raphael-speyer-da force-pushed the rls/etx-500-add-type-info-for-pkg-id branch from e8d8c63 to 7020195 Compare May 20, 2024 01:02
= added 2 commits May 20, 2024 11:05
…nd in the case that we queried an interface we can still just get the template id out of the ArchivedEvent, rather than having to use the one we queried with
…ore consistent type alias names. We may want to coverhaul these names though as they are still not very clear

run-all-tests: true
@raphael-speyer-da raphael-speyer-da force-pushed the rls/etx-500-add-type-info-for-pkg-id branch from 7020195 to 51f45f0 Compare May 20, 2024 01:05
Copy link
Contributor

@simonmaxen-da simonmaxen-da left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good apart from the fmt.sh change that would be better moved into a different PR.

sdk/fmt.sh Outdated
@@ -51,7 +51,7 @@ check_diff() {
# "${@:3}" command
changed_files=$(git diff --name-only --diff-filter=ACMRT "$1" | grep $2 | grep -E -v '^canton(-3x)?/' || [[ $? == 1 ]])
if [[ -n "$changed_files" ]]; then
run "${@:3}" ${changed_files[@]:-}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this change but in a small test I did the prefix removal only applied to the first file, so:

  • As this is an inf change it may be better to put it in a dedicated PR (@garyverhaegen-da may have an opinion on this)
  • As the canton pattern match in change files seems to assume no no sdk prefix so will not work
  • Consider changed_files=$(git diff --name-only --diff-filter=ACMRT "$1" | grep $2 | sed 's/^sdk\///' | grep -E -v '^canton(-3x)?/' || [[ $? == 1 ]])


final def fromLedgerApi(in: lav1.value.Identifier): RequiredPkg =
apply(in.packageId, in.moduleName, in.entityName)
final def fromLedgerApi(in: lav1.value.Identifier): RequiredPkgId =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean when reading from the DB or reading from the ledger-API ?

Copy link
Collaborator

@erwin-ramirez-da erwin-ramirez-da left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@raphael-speyer-da raphael-speyer-da merged commit 8cf8027 into main-2.x May 22, 2024
17 checks passed
@raphael-speyer-da raphael-speyer-da deleted the rls/etx-500-add-type-info-for-pkg-id branch May 22, 2024 03:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants