Skip to content

Commit

Permalink
6 - Ledger API changes for UM/UP extensions for Hub [DPP-1211] (digit…
Browse files Browse the repository at this point in the history
…al-asset#14937)

changelog_begin

[Ledger API Specification]:
1. Add 'is_deactivated' attribute to participant users.
2. Introduce participant server's local metadata for parties and participant users consisting of:
 - a resource version for optional concurrent change control,
 - modifiable key-value based annotations.
3. Add experimental update RPCs for parties and participant users:
  - participant user's modifiable fields are: 'primary_party', 'is_deactivated', 'metadata.annotations',
  - party's modifiable fields are 'local_metadata.annotations'.
4. Discourage use of 'party_details.display_name' in favor of using party's metadata annotations.

changelog_end


Other notes:

- no-op updates are allowed,
- update paths are resource relative,
- as annotation deletion is by providing an key with the empty string value,
- as a corollary, only non-empty strings are valid annotation values.
  • Loading branch information
pbatko-da authored Sep 26, 2022
1 parent 7635fbe commit ca81ade
Show file tree
Hide file tree
Showing 84 changed files with 4,143 additions and 1,427 deletions.
16 changes: 16 additions & 0 deletions compatibility/bazel_tools/testing.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,22 @@ excluded_test_tool_tests = [
},
],
},
{
# This exclusion is due incompatible Ledger API test-tool changes:
# The 'PartyDetails' message now contains a new 'local_metadata' field which is returned by
# 'PartyManagementService.GetParties' and 'PartyManagementService.ListKnownParties' RPCs
# and we changed the existing IT tests to verify that this new field is indeed returned.
"start": "2.4.0-snapshot.20220914.10592.1",
"platform_ranges": [
{
"end": "2.4.0-snapshot.20220914.10592.0.cf7c2b5c",
"exclusions": [
"PartyManagementServiceIT:PMGetPartiesDetails",
"PartyManagementServiceIT:PMListKnownParties",
],
},
],
},
]

def in_range(version, range):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ object Converter {

def toUser(v: SValue): Either[String, User] =
v match {
case SRecord(_, _, vals) if vals.size == 2 =>
case SRecord(_, _, vals) if vals.size >= 2 =>
for {
id <- toUserId(vals.get(0))
primaryParty <- toOptional(vals.get(1), toParty)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import scala.collection.mutable
// Note (MK) This is a simplified version of the in-memory store used in the participant in
// #11896. While it would be nice to not have to duplicate this for now this seems like the
// simpler option than trying to reuse participant code in the script service.
// TODO um-for-hub: Determine if this implementation needs to be updated
private[ledgerinteraction] class UserManagementStore {
import UserManagementStore._

Expand Down
152 changes: 151 additions & 1 deletion docs/resources/generated-error-pages/error-codes-inventory.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -492,13 +492,163 @@ PACKAGE_UPLOAD_REJECTED
2.2.1.1. ParticipantErrorGroup / LedgerApiErrors / AdminServices / UserManagementServiceErrors
2.2.1.1. ParticipantErrorGroup / LedgerApiErrors / AdminServices / PartyManagementServiceErrorGroup
===================================================================================================================
.. _error_code_CONCURRENT_PARTY_DETAILS_UPDATE_DETECTED:
CONCURRENT_PARTY_DETAILS_UPDATE_DETECTED
---------------------------------------------------------------------------------------------------------------------------------------
**Explanation**: Concurrent updates to a party can be controlled by supplying an update request with a resource version (this is optional). A party's resource version can be obtained by reading the party on the Ledger API. There was attempt to update a party using a stale resource version, indicating that a different process had updated the party earlier.
**Category**: ContentionOnSharedResources
**Conveyance**: This error is logged with log-level INFO on the server side. This error is exposed on the API with grpc-status ABORTED including a detailed error message
**Resolution**: Read this party again to obtain its most recent state and in particular its most recent resource version. Use the obtained information to build and send a new update request.
.. _error_code_INTERNAL_PARTY_RECORD_ALREADY_EXISTS:
INTERNAL_PARTY_RECORD_ALREADY_EXISTS
---------------------------------------------------------------------------------------------------------------------------------------
**Explanation**: Each on-ledger party known to this participant node can have a participant's local metadata assigned to it. The local information about a party referred to by this request was found when it should have been not found.
**Category**: SystemInternalAssumptionViolated
**Conveyance**: This error is logged with log-level ERROR on the server side. This error is exposed on the API with grpc-status INTERNAL without any details due to security reasons
**Resolution**: This error can indicate a problem with the server's storage or implementation.
.. _error_code_INTERNAL_PARTY_RECORD_NOT_FOUND:
INTERNAL_PARTY_RECORD_NOT_FOUND
---------------------------------------------------------------------------------------------------------------------------------------
**Explanation**: Each on-ledger party known to this participant node can have a participant's local metadata assigned to it. The local information about a party referred to by this request was not found when it should have been found.
**Category**: SystemInternalAssumptionViolated
**Conveyance**: This error is logged with log-level ERROR on the server side. This error is exposed on the API with grpc-status INTERNAL without any details due to security reasons
**Resolution**: This error can indicate a problem with the server's storage or implementation.
.. _error_code_INVALID_PARTY_DETAILS_UPDATE_REQUEST:
INVALID_PARTY_DETAILS_UPDATE_REQUEST
---------------------------------------------------------------------------------------------------------------------------------------
**Explanation**: There was an attempt to update a party using an invalid update request.
**Category**: InvalidIndependentOfSystemState
**Conveyance**: This error is logged with log-level INFO on the server side. This error is exposed on the API with grpc-status INVALID_ARGUMENT including a detailed error message
**Resolution**: Inspect the error details for specific information on what made the request invalid. Retry with an adjusted update request.
.. _error_code_MAX_PARTY_DETAILS_ANNOTATIONS_SIZE_EXCEEDED:
MAX_PARTY_DETAILS_ANNOTATIONS_SIZE_EXCEEDED
---------------------------------------------------------------------------------------------------------------------------------------
**Explanation**: A party can have at most 256kb worth of annotations in total measured in number of bytes in UTF-8 encoding. There was an attempt to allocate or update a party such that this limit would have been exceeded.
**Category**: InvalidGivenCurrentSystemStateOther
**Conveyance**: This error is logged with log-level INFO on the server side. This error is exposed on the API with grpc-status FAILED_PRECONDITION including a detailed error message
**Resolution**: Retry with fewer annotations or delete some of the party's existing annotations.
.. _error_code_PARTY_NOT_FOUND:
PARTY_NOT_FOUND
---------------------------------------------------------------------------------------------------------------------------------------
**Explanation**: The party referred to by the request was not found.
**Category**: InvalidGivenCurrentSystemStateResourceMissing
**Conveyance**: This error is logged with log-level INFO on the server side. This error is exposed on the API with grpc-status NOT_FOUND including a detailed error message
**Resolution**: Check that you are connecting to the right participant node and that the party is spelled correctly.
2.2.1.2. ParticipantErrorGroup / LedgerApiErrors / AdminServices / UserManagementServiceErrorGroup
===================================================================================================================
.. _error_code_CONCURRENT_USER_UPDATE_DETECTED:
CONCURRENT_USER_UPDATE_DETECTED
---------------------------------------------------------------------------------------------------------------------------------------
**Explanation**: Concurrent updates to a user can be controlled by supplying an update request with a resource version (this is optional). A user's resource version can be obtained by reading the user on the Ledger API. There was attempt to update a user using a stale resource version, indicating that a different process had updated the user earlier.
**Category**: ContentionOnSharedResources
**Conveyance**: This error is logged with log-level INFO on the server side. This error is exposed on the API with grpc-status ABORTED including a detailed error message
**Resolution**: Read this user again to obtain its most recent state and in particular its most recent resource version. Use the obtained information to build and send a new update request.
.. _error_code_INVALID_USER_UPDATE_REQUEST:
INVALID_USER_UPDATE_REQUEST
---------------------------------------------------------------------------------------------------------------------------------------
**Explanation**: There was an attempt to update a user using an invalid update request.
**Category**: InvalidIndependentOfSystemState
**Conveyance**: This error is logged with log-level INFO on the server side. This error is exposed on the API with grpc-status INVALID_ARGUMENT including a detailed error message
**Resolution**: Inspect the error details for specific information on what made the request invalid. Retry with an adjusted update request.
.. _error_code_MAX_USER_ANNOTATIONS_SIZE_EXCEEDED:
MAX_USER_ANNOTATIONS_SIZE_EXCEEDED
---------------------------------------------------------------------------------------------------------------------------------------
**Explanation**: A user can have at most 256kb worth of annotations in total measured in number of bytes in UTF-8 encoding. There was an attempt to create or update a user such that this limit would have been exceeded.
**Category**: InvalidGivenCurrentSystemStateOther
**Conveyance**: This error is logged with log-level INFO on the server side. This error is exposed on the API with grpc-status FAILED_PRECONDITION including a detailed error message
**Resolution**: Retry with fewer annotations or delete some of the user's existing annotations.
.. _error_code_TOO_MANY_USER_RIGHTS:
TOO_MANY_USER_RIGHTS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,5 @@ allocateParty request =
lowerRequest AllocatePartyRequest{..} = do
let allocatePartyRequestPartyIdHint = partyIdHint
let allocatePartyRequestDisplayName = displayName
let allocatePartyRequestLocalMetadata = Nothing
LL.AllocatePartyRequest {..}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ final class UserManagementServiceImpl extends UserManagementService with FakeAut

override def listUserRights(request: ListUserRightsRequest): Future[ListUserRightsResponse] =
record(request)(ListUserRightsResponse.defaultInstance)

override def updateUser(request: UpdateUserRequest): Future[UpdateUserResponse] =
record(request)(UpdateUserResponse.defaultInstance)
}

object UserManagementServiceImpl {
Expand Down
5 changes: 5 additions & 0 deletions ledger-api/grpc-definitions/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ proto_jars(
"@com_google_protobuf//:descriptor_proto",
"@com_google_protobuf//:duration_proto",
"@com_google_protobuf//:empty_proto",
"@com_google_protobuf//:field_mask_proto",
"@com_google_protobuf//:struct_proto",
"@com_google_protobuf//:timestamp_proto",
"@com_google_protobuf//:wrappers_proto",
Expand All @@ -46,6 +47,7 @@ genrule(
"Empty.hs",
"Wrappers.hs",
"Struct.hs",
"FieldMask.hs",
]],
cmd = """
for src in \
Expand All @@ -54,6 +56,7 @@ genrule(
external/com_google_protobuf/src/google/protobuf/empty.proto \
external/com_google_protobuf/src/google/protobuf/wrappers.proto \
external/com_google_protobuf/src/google/protobuf/struct.proto \
external/com_google_protobuf/src/google/protobuf/field_mask.proto \
; do
$(location @proto3-suite//:compile-proto-file) \
--includeDir """ + google_protobuf_src + """ \
Expand Down Expand Up @@ -179,6 +182,8 @@ ledger_api_haskellpb_sources_admin = [
"PackageManagementService.hs",
"PartyManagementService.hs",
"MeteringReportService.hs",
"ObjectMeta.hs",
"UserManagementService.hs",
]

genrule(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

syntax = "proto3";

package com.daml.ledger.api.v1.admin;

option java_outer_classname = "ObjectMetaOuterClass";
option java_package = "com.daml.ledger.api.v1.admin";
option csharp_namespace = "Com.Daml.Ledger.Api.V1.Admin";

// Represents metadata corresponding to a participant resource (e.g. a participant user or participant local information about a party).
//
// Based on ``ObjectMeta`` meta used in Kubernetes API.
// See https://github.com/kubernetes/apimachinery/blob/master/pkg/apis/meta/v1/generated.proto#L640
message ObjectMeta {

// An opaque value populated by a participant server which represents the internal version of the resource
// this ``ObjectMeta`` message is attached to. The participant server will change it to a unique value each time the corresponding resource is updated.
// You must not rely on the format of resource version. The participant server might change it without notice.
//
// You can obtain the newest resource version value by issuing a read request.
// You may use it for concurrent change detection by passing it back unmodified in an update request.
// The participant server will then compare the passed value with the value maintained by the system to determine
// if any other updates took place since you had read the resource version.
// Upon a successful update you are guaranteed that no other update took place during your read-modify-write sequence.
// However, if another update took place during your read-modify-write sequence then your update will fail with an appropriate error.
//
// Concurrent change control is optional. It will be applied only if you include a resource version in an update request.
//
// When creating a new instance of a resource you must leave the resource version empty.
// Its value will be populated by the participant server upon successful resource creation.
//
// Optional
string resource_version = 6;

// A set of modifiable key-value pairs that can be used to represent arbitrary, client-specific metadata.
//
// Constraints:
// 1. The total size over all keys and values cannot exceed 256kb in UTF-8 encoding.
// 2. Keys are composed of an optional prefix segment and a required name segment such that:
// - key prefix, when present, must be a valid DNS subdomain with at most 253 characters, followed by a '/' (forward slash) character,
// - name segment must have at most 63 characters that are either alphanumeric ([a-z0-9A-Z]), or a '.' (dot), '-' (dash) or '_' (underscore);
// and it must start and end with an alphanumeric character.
// 2. Values can be any non-empty strings.
//
// Keys with empty prefix are reserved for end-users.
// Properties set by external tools or internally by the participant server must use non-empty key prefixes.
//
// Duplicate keys are disallowed by the semantics of the protobuf3 maps.
// See: https://developers.google.com/protocol-buffers/docs/proto3#maps
//
// Annotations may be a part of a modifiable resource.
// Use the resource's update RPC to update its annotations.
// In order to add a new annotation or update an existing one using an update RPC, provide the desired annotation in the update request.
// In order to remove an annotation using an update RPC, provide the target annotation's key but set its value to the empty string in the update request.
//
// Optional
// Modifiable
map<string, string> annotations = 12;
}
Loading

0 comments on commit ca81ade

Please sign in to comment.